From 313819d4c25cdd46b42e85d70870b713bb9189ab Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 12 Jun 2012 12:04:29 +0200 Subject: [PATCH 0001/5375] ARM: remove linkup-l1110.h No file includes this header. Nothing seems interested in the things this header provides. It appears that it has never been included since at least v2.6.12-rc2. It can safely be removed. Signed-off-by: Paul Bolle Acked-by: Dmitry Artamonow Signed-off-by: Russell King --- arch/arm/include/asm/hardware/linkup-l1110.h | 48 -------------------- 1 file changed, 48 deletions(-) delete mode 100644 arch/arm/include/asm/hardware/linkup-l1110.h diff --git a/arch/arm/include/asm/hardware/linkup-l1110.h b/arch/arm/include/asm/hardware/linkup-l1110.h deleted file mode 100644 index 7ec91168a576..000000000000 --- a/arch/arm/include/asm/hardware/linkup-l1110.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -* -* Definitions for H3600 Handheld Computer -* -* Copyright 2001 Compaq Computer Corporation. -* -* Use consistent with the GNU GPL is permitted, -* provided that this copyright notice is -* preserved in its entirety in all copies and derived works. -* -* COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, -* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS -* FITNESS FOR ANY PARTICULAR PURPOSE. -* -* Author: Jamey Hicks. -* -*/ - -/* LinkUp Systems PCCard/CompactFlash Interface for SA-1100 */ - -/* PC Card Status Register */ -#define LINKUP_PRS_S1 (1 << 0) /* voltage control bits S1-S4 */ -#define LINKUP_PRS_S2 (1 << 1) -#define LINKUP_PRS_S3 (1 << 2) -#define LINKUP_PRS_S4 (1 << 3) -#define LINKUP_PRS_BVD1 (1 << 4) -#define LINKUP_PRS_BVD2 (1 << 5) -#define LINKUP_PRS_VS1 (1 << 6) -#define LINKUP_PRS_VS2 (1 << 7) -#define LINKUP_PRS_RDY (1 << 8) -#define LINKUP_PRS_CD1 (1 << 9) -#define LINKUP_PRS_CD2 (1 << 10) - -/* PC Card Command Register */ -#define LINKUP_PRC_S1 (1 << 0) -#define LINKUP_PRC_S2 (1 << 1) -#define LINKUP_PRC_S3 (1 << 2) -#define LINKUP_PRC_S4 (1 << 3) -#define LINKUP_PRC_RESET (1 << 4) -#define LINKUP_PRC_APOE (1 << 5) /* Auto Power Off Enable: clears S1-S4 when either nCD goes high */ -#define LINKUP_PRC_CFE (1 << 6) /* CompactFlash mode Enable: addresses A[10:0] only, A[25:11] high */ -#define LINKUP_PRC_SOE (1 << 7) /* signal output driver enable */ -#define LINKUP_PRC_SSP (1 << 8) /* sock select polarity: 0 for socket 0, 1 for socket 1 */ -#define LINKUP_PRC_MBZ (1 << 15) /* must be zero */ - -struct linkup_l1110 { - volatile short prc; -}; From 7f61d1e2b77a3c2c222a7ba5c751b63bfd5dbb37 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 12 Jun 2012 12:37:39 +0200 Subject: [PATCH 0002/5375] ARM: remove old SA-1111.h All (in tree) users of old mach/SA-1111.h were already updated to include asm/hardware/sa1111.h in v2.6.12-rc2. The old header can safely be removed now. Signed-off-by: Paul Bolle Signed-off-by: Russell King --- arch/arm/mach-sa1100/include/mach/SA-1111.h | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 arch/arm/mach-sa1100/include/mach/SA-1111.h diff --git a/arch/arm/mach-sa1100/include/mach/SA-1111.h b/arch/arm/mach-sa1100/include/mach/SA-1111.h deleted file mode 100644 index c38f60915cb6..000000000000 --- a/arch/arm/mach-sa1100/include/mach/SA-1111.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * Moved to new location - */ -#warning using old SA-1111.h - update to -#include From c7530aac165ce3f43d3c32042692da52c9845e33 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 12 Jun 2012 14:49:46 +0200 Subject: [PATCH 0003/5375] ARM: pxa: remove eseries.h Commit e478fe4cd50b86e95fadc415438b63fa94060b7d ("[ARM] pxa: merge all eseries board code into eseries.c") removed all six files that included eseries.h. Everything that this header provides is now either local to eseries.c or entirely unused. It was apparently just an oversight to keep this header. This header can safely be removed. Signed-off-by: Paul Bolle Signed-off-by: Russell King --- arch/arm/mach-pxa/eseries.h | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 arch/arm/mach-pxa/eseries.h diff --git a/arch/arm/mach-pxa/eseries.h b/arch/arm/mach-pxa/eseries.h deleted file mode 100644 index b96949dd5adb..000000000000 --- a/arch/arm/mach-pxa/eseries.h +++ /dev/null @@ -1,14 +0,0 @@ -void __init eseries_fixup(struct tag *tags, char **cmdline, struct meminfo *mi); - -extern struct pxa2xx_udc_mach_info e7xx_udc_mach_info; -extern struct pxaficp_platform_data e7xx_ficp_platform_data; -extern int e7xx_irda_init(void); - -extern int eseries_tmio_enable(struct platform_device *dev); -extern int eseries_tmio_disable(struct platform_device *dev); -extern int eseries_tmio_suspend(struct platform_device *dev); -extern int eseries_tmio_resume(struct platform_device *dev); -extern void eseries_get_tmio_gpios(void); -extern struct resource eseries_tmio_resources[]; -extern struct platform_device e300_tc6387xb_device; - From c5dfdbe0c70c8c032a2962ccd51f163388def148 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 19 Jun 2012 12:46:27 +0200 Subject: [PATCH 0004/5375] ARM: sa1100: remove lart.h No file includes this header. It has never been included since at least v2.6.12-rc2. It can safely be removed. Signed-off-by: Paul Bolle Signed-off-by: Russell King --- arch/arm/mach-sa1100/include/mach/lart.h | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 arch/arm/mach-sa1100/include/mach/lart.h diff --git a/arch/arm/mach-sa1100/include/mach/lart.h b/arch/arm/mach-sa1100/include/mach/lart.h deleted file mode 100644 index 8a5482d908db..000000000000 --- a/arch/arm/mach-sa1100/include/mach/lart.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _INCLUDE_LART_H -#define _INCLUDE_LART_H - -#define LART_GPIO_ETH0 GPIO_GPIO0 -#define LART_IRQ_ETH0 IRQ_GPIO0 - -#define LART_GPIO_IDE GPIO_GPIO1 -#define LART_IRQ_IDE IRQ_GPIO1 - -#define LART_GPIO_UCB1200 GPIO_GPIO18 -#define LART_IRQ_UCB1200 IRQ_GPIO18 - -#endif From 6d70a74ffd616073a68ae0974d98819bfa8e6da6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Jun 2012 11:31:14 -0700 Subject: [PATCH 0005/5375] isci: fix isci_pci_probe() generates warning on efi failure path The oem parameter image embedded in the efi variable is at an offset from the start of the variable. However, in the failure path we try to free the 'orom' pointer which is only valid when the paramaters are being read from the legacy option-rom space. Since failure to load the oem parameters is unlikely and we keep the memory around in the success case just defer all de-allocation to devm. Cc: Reported-by: Don Morris Signed-off-by: Dan Williams --- drivers/scsi/isci/init.c | 1 - drivers/scsi/isci/probe_roms.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 47e28b555029..8870bd3b6383 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -641,7 +641,6 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic orom->hdr.version)) { dev_warn(&pdev->dev, "[%d]: invalid oem parameters detected, falling back to firmware\n", i); - devm_kfree(&pdev->dev, orom); orom = NULL; break; } diff --git a/drivers/scsi/isci/probe_roms.c b/drivers/scsi/isci/probe_roms.c index 4d95654c3fd4..8ac646e5eddc 100644 --- a/drivers/scsi/isci/probe_roms.c +++ b/drivers/scsi/isci/probe_roms.c @@ -104,7 +104,6 @@ struct isci_orom *isci_request_oprom(struct pci_dev *pdev) if (i >= len) { dev_err(&pdev->dev, "oprom parse error\n"); - devm_kfree(&pdev->dev, rom); rom = NULL; } pci_unmap_biosrom(oprom); From a90037560588e51b3e98b49537799137cbfda17d Mon Sep 17 00:00:00 2001 From: Dave Maurer Date: Fri, 22 Jun 2012 06:45:33 +0000 Subject: [PATCH 0006/5375] isci: fix COMSAS negation timout workaround for WD SAS drives The following patch is a fix for the WD workaround COMSAS negation timeout change. This patch disables the OOB SM when the OOB is placed in reset, which allows the updated COMSAS negation timeout value to take effect. Cc: Dan Thompson Reported-by: Dan Thompson Signed-off-by: Dave Maurer Signed-off-by: Dan Williams --- drivers/scsi/isci/phy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 18f43d4c30ba..ebb8f530f708 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -1205,6 +1205,7 @@ static void scu_link_layer_start_oob(struct isci_phy *iphy) /** Reset OOB sequence - start */ val = readl(&ll->phy_configuration); val &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | + SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE) | SCU_SAS_PCFG_GEN_BIT(HARD_RESET)); writel(val, &ll->phy_configuration); readl(&ll->phy_configuration); /* flush */ @@ -1236,6 +1237,7 @@ static void scu_link_layer_tx_hard_reset( * to the starting state. */ phy_configuration_value = readl(&iphy->link_layer_registers->phy_configuration); + phy_configuration_value &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE)); phy_configuration_value |= (SCU_SAS_PCFG_GEN_BIT(HARD_RESET) | SCU_SAS_PCFG_GEN_BIT(OOB_RESET)); From 67787c330762eb884bf8c169fe942263d55ec162 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 27 Jun 2012 12:10:06 +0300 Subject: [PATCH 0007/5375] isci: make function declaration match implementation Sparse complains that we redeclare this with a different type, because in the .c file we use an enum and in the .h file we declare the parameter as a u32. Probably it's best to use an enum in both places. Signed-off-by: Dan Carpenter Signed-off-by: Dan Williams --- drivers/scsi/isci/remote_node_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h index a703b9ce0c2c..c7ee81d01125 100644 --- a/drivers/scsi/isci/remote_node_context.h +++ b/drivers/scsi/isci/remote_node_context.h @@ -212,7 +212,7 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context scics_sds_remote_node_context_callback callback, void *callback_parameter); enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc, - u32 suspend_type, + enum sci_remote_node_suspension_reasons reason, u32 suspension_code); enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc, scics_sds_remote_node_context_callback cb_fn, From 6734092e66011def7875bd67beef889d0fee1cc9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 27 Jun 2012 12:05:21 +0300 Subject: [PATCH 0008/5375] isci: add a couple __iomem annotations These are __iomem. Sparse complains if we don't have that. drivers/scsi/isci/phy.c +149 70: warning: incorrect type in initializer (different address spaces) Signed-off-by: Dan Carpenter Signed-off-by: Dan Williams --- drivers/scsi/isci/host.c | 2 +- drivers/scsi/isci/phy.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 45385f531649..b425ed523ccc 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -1973,7 +1973,7 @@ static void sci_controller_afe_initialization(struct isci_host *ihost) } for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) { - struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_id]; + struct scu_afe_transceiver __iomem *xcvr = &afe->scu_afe_xcvr[phy_id]; const struct sci_phy_oem_params *oem_phy = &oem->phys[phy_id]; int cable_length_long = is_long_cable(phy_id, cable_selection_mask); diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index ebb8f530f708..cb87b2ef7c92 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -169,7 +169,7 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, phy_cap.gen1_no_ssc = 1; if (ihost->oem_parameters.controller.do_enable_ssc) { struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe; - struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_idx]; + struct scu_afe_transceiver __iomem *xcvr = &afe->scu_afe_xcvr[phy_idx]; struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); bool en_sas = false; bool en_sata = false; From d2d48480d16ab349ae5d4732b4d79ff48b4b4171 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 22 Jun 2012 16:35:38 -0700 Subject: [PATCH 0009/5375] mtd: move mtd_read_oob() definition out of mtd.h mtd_read_oob() will be expanded a little, so don't leave it in the header as a static inline function. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtdcore.c | 9 +++++++++ include/linux/mtd/mtd.h | 9 +-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 575730744fdb..fcfce24f87d1 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -858,6 +858,15 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, } EXPORT_SYMBOL_GPL(mtd_panic_write); +int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) +{ + ops->retlen = ops->oobretlen = 0; + if (!mtd->_read_oob) + return -EOPNOTSUPP; + return mtd->_read_oob(mtd, from, ops); +} +EXPORT_SYMBOL_GPL(mtd_read_oob); + /* * Method to access the protection register area, present in some flash * devices. The user data is one time programmable but the factory data is read diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 63dadc0dfb62..81d61e704599 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -265,14 +265,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); -static inline int mtd_read_oob(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - ops->retlen = ops->oobretlen = 0; - if (!mtd->_read_oob) - return -EOPNOTSUPP; - return mtd->_read_oob(mtd, from, ops); -} +int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops); static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) From 9cb93fbb5e84a2749e4ad6fec5091d149323a3d4 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 11 May 2012 13:30:33 -0700 Subject: [PATCH 0010/5375] mtd: mtdoops: refactor loop We can clean up the loop logic a bit, here. This refactoring was enabled in part by: Commit bb4a09866 [mtdoops: clean-up new MTD API usage] Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtdoops.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index ae36d7e1e913..6ba9507b7c84 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -169,14 +169,7 @@ static void mtdoops_workfunc_erase(struct work_struct *work) cxt->nextpage = 0; } - while (1) { - ret = mtd_block_isbad(mtd, cxt->nextpage * record_size); - if (!ret) - break; - if (ret < 0) { - printk(KERN_ERR "mtdoops: block_isbad failed, aborting\n"); - return; - } + while ((ret = mtd_block_isbad(mtd, cxt->nextpage * record_size)) > 0) { badblock: printk(KERN_WARNING "mtdoops: bad block at %08lx\n", cxt->nextpage * record_size); @@ -190,6 +183,11 @@ badblock: } } + if (ret < 0) { + printk(KERN_ERR "mtdoops: mtd_block_isbad failed, aborting\n"); + return; + } + for (j = 0, ret = -1; (j < 3) && (ret < 0); j++) ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size); From b9bc815c2c01e8cbc6fe894e3b4ff6bb4313ebcb Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 11 May 2012 13:30:34 -0700 Subject: [PATCH 0011/5375] mtd: cafe_nand: spelling mistake Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/cafe_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index f3f6cfedd69e..ac0d967ee3fd 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -377,7 +377,7 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, * @buf: buffer to store read data * @oob_required: caller expects OOB data read to chip->oob_poi * - * The hw generator calculates the error syndrome automatically. Therefor + * The hw generator calculates the error syndrome automatically. Therefore * we need a special oob layout and handling. */ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, From 271b874ba1512a1b3bd24edbd4e4116c3b5c15ae Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 11 May 2012 13:30:35 -0700 Subject: [PATCH 0012/5375] mtd: nand: gpmi: need to use {read,write}_oob_raw This patch is simply an added warning in the comments. Ideally, this patch need not be merged, but rather, a developer will write a proper solution that can use the ecc.read_oob_raw and ecc.write_oob_raw interfaces. Signed-off-by: Brian Norris Cc: Huang Shijie Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index a6cad5caba78..6574c6f51b8b 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1064,6 +1064,9 @@ exit_auxiliary: * ECC-based or raw view of the page is implicit in which function it calls * (there is a similar pair of ECC-based/raw functions for writing). * + * FIXME: The following paragraph is incorrect, now that there exist + * ecc.read_oob_raw and ecc.write_oob_raw functions. + * * Since MTD assumes the OOB is not covered by ECC, there is no pair of * ECC-based/raw functions for reading or or writing the OOB. The fact that the * caller wants an ECC-based or raw view of the page is not propagated down to From cb54751d7a706b4a068b798b97e8a815b99fa835 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Mon, 14 May 2012 14:14:40 +0200 Subject: [PATCH 0013/5375] mtd: sh_flctl: Add missing iounmap() Add the unmapping for the error case and for the driver removal. Signed-off-by: Bastian Hecht Acked-by: Laurent Pinchart Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/sh_flctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index aa9b8a5e0b8f..a5a60cac7e70 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -918,6 +918,7 @@ static int __devinit flctl_probe(struct platform_device *pdev) err_chip: pm_runtime_disable(&pdev->dev); + iounmap(flctl->reg); err_iomap: kfree(flctl); return ret; @@ -929,6 +930,7 @@ static int __devexit flctl_remove(struct platform_device *pdev) nand_release(&flctl->mtd); pm_runtime_disable(&pdev->dev); + iounmap(flctl->reg); kfree(flctl); return 0; From 3c7ea4eccfd2e209ba666d217a2993b8a084a429 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Mon, 14 May 2012 14:14:41 +0200 Subject: [PATCH 0014/5375] mtd: sh_flctl: Add support for error IRQ When the data transfer between the controller and the NAND chip fails, we now get notified. Signed-off-by: Bastian Hecht Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/sh_flctl.c | 34 +++++++++++++++++++++++++++++++--- include/linux/mtd/sh_flctl.h | 9 +++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index a5a60cac7e70..c835b136e7cb 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -68,8 +69,8 @@ static struct nand_bbt_descr flctl_4secc_largepage = { static void empty_fifo(struct sh_flctl *flctl) { - writel(0x000c0000, FLINTDMACR(flctl)); /* FIFO Clear */ - writel(0x00000000, FLINTDMACR(flctl)); /* Clear Error flags */ + writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl)); + writel(flctl->flintdmacr_base, FLINTDMACR(flctl)); } static void start_translation(struct sh_flctl *flctl) @@ -839,6 +840,16 @@ static int flctl_chip_init_tail(struct mtd_info *mtd) return 0; } +static irqreturn_t flctl_handle_flste(int irq, void *dev_id) +{ + struct sh_flctl *flctl = dev_id; + + dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl))); + writel(flctl->flintdmacr_base, FLINTDMACR(flctl)); + + return IRQ_HANDLED; +} + static int __devinit flctl_probe(struct platform_device *pdev) { struct resource *res; @@ -847,6 +858,7 @@ static int __devinit flctl_probe(struct platform_device *pdev) struct nand_chip *nand; struct sh_flctl_platform_data *pdata; int ret = -ENXIO; + int irq; pdata = pdev->dev.platform_data; if (pdata == NULL) { @@ -872,14 +884,27 @@ static int __devinit flctl_probe(struct platform_device *pdev) goto err_iomap; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get flste irq data\n"); + goto err_flste; + } + + ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl); + if (ret) { + dev_err(&pdev->dev, "request interrupt failed.\n"); + goto err_flste; + } + platform_set_drvdata(pdev, flctl); flctl_mtd = &flctl->mtd; nand = &flctl->chip; flctl_mtd->priv = nand; flctl->pdev = pdev; - flctl->flcmncr_base = pdata->flcmncr_val; flctl->hwecc = pdata->has_hwecc; flctl->holden = pdata->use_holden; + flctl->flcmncr_base = pdata->flcmncr_val; + flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE; /* Set address of hardware control function */ /* 20 us command delay time */ @@ -918,6 +943,8 @@ static int __devinit flctl_probe(struct platform_device *pdev) err_chip: pm_runtime_disable(&pdev->dev); + free_irq(irq, flctl); +err_flste: iounmap(flctl->reg); err_iomap: kfree(flctl); @@ -930,6 +957,7 @@ static int __devexit flctl_remove(struct platform_device *pdev) nand_release(&flctl->mtd); pm_runtime_disable(&pdev->dev); + free_irq(platform_get_irq(pdev, 0), flctl); iounmap(flctl->reg); kfree(flctl); diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index a38e1fa8af01..2daa43e17039 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -107,6 +107,14 @@ #define DOCMD2_E (0x1 << 17) /* 2nd cmd stage execute */ #define DOCMD1_E (0x1 << 16) /* 1st cmd stage execute */ +/* FLINTDMACR control bits */ +#define ESTERINTE (0x1 << 24) /* ECC error interrupt enable */ +#define AC1CLR (0x1 << 19) /* ECC FIFO clear */ +#define AC0CLR (0x1 << 18) /* Data FIFO clear */ +#define ECERB (0x1 << 9) /* ECC error */ +#define STERB (0x1 << 8) /* Status error */ +#define STERINTE (0x1 << 4) /* Status error enable */ + /* FLTRCR control bits */ #define TRSTRT (0x1 << 0) /* translation start */ #define TREND (0x1 << 1) /* translation end */ @@ -145,6 +153,7 @@ struct sh_flctl { uint32_t erase_ADRCNT; /* bits of FLCMDCR in ERASE1 cmd */ uint32_t rw_ADRCNT; /* bits of FLCMDCR in READ WRITE cmd */ uint32_t flcmncr_base; /* base value of FLCMNCR */ + uint32_t flintdmacr_base; /* irq enable bits */ int hwecc_cant_correct[4]; From aa32d1f0601ac2f5f69520175b8d2cea42caa025 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Mon, 14 May 2012 14:14:42 +0200 Subject: [PATCH 0015/5375] mtd: sh_flctl: Use different OOB layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flctl hardware has changed and a new OOB layout must be adapted for 2KiB page size NAND chips when using hardware ECC. The related bit fields ECCPOS[0-2] are gone — the bits are marked as reserved now in the datasheet. As there are no official users of the hardware ECC so far, they are completely removed. Signed-off-by: Bastian Hecht Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/sh_flctl.c | 18 ++++++++++++------ include/linux/mtd/sh_flctl.h | 4 ---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index c835b136e7cb..b3666be0ccfc 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -44,11 +44,17 @@ static struct nand_ecclayout flctl_4secc_oob_16 = { }; static struct nand_ecclayout flctl_4secc_oob_64 = { - .eccbytes = 10, - .eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57}, + .eccbytes = 4 * 10, + .eccpos = { + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }, .oobfree = { - {.offset = 60, - . length = 4} }, + {.offset = 2, .length = 4}, + {.offset = 16, .length = 6}, + {.offset = 32, .length = 6}, + {.offset = 48, .length = 6} }, }; static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; @@ -62,7 +68,7 @@ static struct nand_bbt_descr flctl_4secc_smallpage = { static struct nand_bbt_descr flctl_4secc_largepage = { .options = NAND_BBT_SCAN2NDPAGE, - .offs = 58, + .offs = 0, .len = 2, .pattern = scan_ff_pattern, }; @@ -832,7 +838,7 @@ static int flctl_chip_init_tail(struct mtd_info *mtd) chip->ecc.mode = NAND_ECC_HW; /* 4 symbols ECC enabled */ - flctl->flcmncr_base |= _4ECCEN | ECCPOS2 | ECCPOS_02; + flctl->flcmncr_base |= _4ECCEN; } else { chip->ecc.mode = NAND_ECC_SOFT; } diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index 2daa43e17039..3feaae062feb 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -49,7 +49,6 @@ #define FLERRADR(f) (f->reg + 0x98) /* FLCMNCR control bits */ -#define ECCPOS2 (0x1 << 25) #define _4ECCCNTEN (0x1 << 24) #define _4ECCEN (0x1 << 23) #define _4ECCCORRECT (0x1 << 22) @@ -59,9 +58,6 @@ #define QTSEL_E (0x1 << 17) #define ENDIAN (0x1 << 16) /* 1 = little endian */ #define FCKSEL_E (0x1 << 15) -#define ECCPOS_00 (0x00 << 12) -#define ECCPOS_01 (0x01 << 12) -#define ECCPOS_02 (0x02 << 12) #define ACM_SACCES_MODE (0x01 << 10) #define NANWF_E (0x1 << 9) #define SE_D (0x1 << 8) /* Spare area disable */ From ef4ce0bcb3c91375d2bdefd7a0e2fead95c97620 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Mon, 14 May 2012 14:14:43 +0200 Subject: [PATCH 0016/5375] mtd: sh_flctl: Fix hardware ECC behaviour The flctl uses 10 bytes ECC data for every 512 bytes sector. This patch makes the controller write all 40 bytes instead of 10 bytes only. Signed-off-by: Bastian Hecht Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/sh_flctl.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index b3666be0ccfc..8633b5b98a13 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -427,30 +427,20 @@ static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) static void execmd_read_oob(struct mtd_info *mtd, int page_addr) { struct sh_flctl *flctl = mtd_to_flctl(mtd); + int page_sectors = flctl->page_size ? 4 : 1; + int i; set_cmd_regs(mtd, NAND_CMD_READ0, (NAND_CMD_READSTART << 8) | NAND_CMD_READ0); empty_fifo(flctl); - if (flctl->page_size) { - int i; - /* In case that the page size is 2k */ - for (i = 0; i < 16 * 3; i++) - flctl->done_buff[i] = 0xFF; - set_addr(mtd, 3 * 528 + 512, page_addr); + for (i = 0; i < page_sectors; i++) { + set_addr(mtd, (512 + 16) * i + 512 , page_addr); writel(16, FLDTCNTR(flctl)); start_translation(flctl); - read_fiforeg(flctl, 16, 16 * 3); - wait_completion(flctl); - } else { - /* In case that the page size is 512b */ - set_addr(mtd, 512, page_addr); - writel(16, FLDTCNTR(flctl)); - - start_translation(flctl); - read_fiforeg(flctl, 16, 0); + read_fiforeg(flctl, 16, 16 * i); wait_completion(flctl); } } @@ -495,18 +485,12 @@ static void execmd_write_oob(struct mtd_info *mtd) int page_addr = flctl->seqin_page_addr; int sector, page_sectors; - if (flctl->page_size) { - sector = 3; - page_sectors = 4; - } else { - sector = 0; - page_sectors = 1; - } + page_sectors = flctl->page_size ? 4 : 1; set_cmd_regs(mtd, NAND_CMD_PAGEPROG, (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN); - for (; sector < page_sectors; sector++) { + for (sector = 0; sector < page_sectors; sector++) { empty_fifo(flctl); set_addr(mtd, sector * 528 + 512, page_addr); writel(16, FLDTCNTR(flctl)); /* set read size */ From 50ed399cc3fbe5e16de78f7b62a39b8280f9001b Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Mon, 14 May 2012 14:14:44 +0200 Subject: [PATCH 0017/5375] mtd: sh_flctl: Simplify the hardware ecc page read/write As the equation mtd->writesize == eccsteps * eccsize holds, we can simplify the code. The second loop of the 1st hunk is never entered, so we delete it. Signed-off-by: Bastian Hecht Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/sh_flctl.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 8633b5b98a13..1cc19eb1c302 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -353,35 +353,14 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - struct sh_flctl *flctl = mtd_to_flctl(mtd); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->read_buf(mtd, p, eccsize); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - if (flctl->hwecc_cant_correct[i]) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += 0; /* FIXME */ - } - + chip->read_buf(mtd, buf, mtd->writesize); return 0; } static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - const uint8_t *p = buf; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->write_buf(mtd, p, eccsize); + chip->write_buf(mtd, buf, mtd->writesize); } static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) From 623c55caa37203ece6b4450daa0d2d058255da30 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Mon, 14 May 2012 14:14:45 +0200 Subject: [PATCH 0018/5375] mtd: sh_flctl: Group sector accesses into a single transfer When we use hardware ecc, the flctl is run in so-called "sector access mode". We can bundle 4 sector accesses when using 2KiB page sizes to read a whole page at once and speed up things. Signed-off-by: Bastian Hecht Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/sh_flctl.c | 46 ++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 1cc19eb1c302..96e242adda6a 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -368,25 +368,21 @@ static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) struct sh_flctl *flctl = mtd_to_flctl(mtd); int sector, page_sectors; - if (flctl->page_size) - page_sectors = 4; - else - page_sectors = 1; - - writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT, - FLCMNCR(flctl)); + page_sectors = flctl->page_size ? 4 : 1; set_cmd_regs(mtd, NAND_CMD_READ0, (NAND_CMD_READSTART << 8) | NAND_CMD_READ0); + writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT, + FLCMNCR(flctl)); + writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl)); + writel(page_addr << 2, FLADR(flctl)); + + empty_fifo(flctl); + start_translation(flctl); + for (sector = 0; sector < page_sectors; sector++) { int ret; - - empty_fifo(flctl); - writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl)); - writel(page_addr << 2 | sector, FLADR(flctl)); - - start_translation(flctl); read_fiforeg(flctl, 512, 512 * sector); ret = read_ecfiforeg(flctl, @@ -397,8 +393,10 @@ static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) flctl->hwecc_cant_correct[sector] = 1; writel(0x0, FL4ECCCR(flctl)); - wait_completion(flctl); } + + wait_completion(flctl); + writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT), FLCMNCR(flctl)); } @@ -430,31 +428,27 @@ static void execmd_write_page_sector(struct mtd_info *mtd) int i, page_addr = flctl->seqin_page_addr; int sector, page_sectors; - if (flctl->page_size) - page_sectors = 4; - else - page_sectors = 1; - - writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl)); + page_sectors = flctl->page_size ? 4 : 1; set_cmd_regs(mtd, NAND_CMD_PAGEPROG, (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN); - for (sector = 0; sector < page_sectors; sector++) { - empty_fifo(flctl); - writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl)); - writel(page_addr << 2 | sector, FLADR(flctl)); + empty_fifo(flctl); + writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl)); + writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl)); + writel(page_addr << 2, FLADR(flctl)); + start_translation(flctl); - start_translation(flctl); + for (sector = 0; sector < page_sectors; sector++) { write_fiforeg(flctl, 512, 512 * sector); for (i = 0; i < 4; i++) { wait_wecfifo_ready(flctl); /* wait for write ready */ writel(0xFFFFFFFF, FLECFIFO(flctl)); } - wait_completion(flctl); } + wait_completion(flctl); writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl)); } From 6667a6d58e25d351d8fce7a628a8c9c139a8bdc9 Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Mon, 14 May 2012 14:14:46 +0200 Subject: [PATCH 0019/5375] mtd: sh_flctl: Restructure the hardware ECC handling There are multiple reasons for a rewrite: - a race exists: when _4ECCEND is set, _4ECCFA may become true too meanwhile, which is lost and a non-correctable error is treated as correctable. - the ECC statistics don't get properly propagated to the base code. - empty pages would get marked as corrupted The rewrite resolves the issues and I hope it gives a more explicit code flow structure. Signed-off-by: Bastian Hecht Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/sh_flctl.c | 119 +++++++++++++++++++++++------------ include/linux/mtd/sh_flctl.h | 10 ++- 2 files changed, 87 insertions(+), 42 deletions(-) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 96e242adda6a..bc50e83336bb 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -165,27 +165,56 @@ static void wait_wfifo_ready(struct sh_flctl *flctl) timeout_error(flctl, __func__); } -static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number) +static enum flctl_ecc_res_t wait_recfifo_ready + (struct sh_flctl *flctl, int sector_number) { uint32_t timeout = LOOP_TIMEOUT_MAX; - int checked[4]; void __iomem *ecc_reg[4]; int i; + int state = FL_SUCCESS; uint32_t data, size; - memset(checked, 0, sizeof(checked)); - + /* + * First this loops checks in FLDTCNTR if we are ready to read out the + * oob data. This is the case if either all went fine without errors or + * if the bottom part of the loop corrected the errors or marked them as + * uncorrectable and the controller is given time to push the data into + * the FIFO. + */ while (timeout--) { + /* check if all is ok and we can read out the OOB */ size = readl(FLDTCNTR(flctl)) >> 24; - if (size & 0xFF) - return 0; /* success */ + if ((size & 0xFF) == 4) + return state; - if (readl(FL4ECCCR(flctl)) & _4ECCFA) - return 1; /* can't correct */ - - udelay(1); - if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) + /* check if a correction code has been calculated */ + if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) { + /* + * either we wait for the fifo to be filled or a + * correction pattern is being generated + */ + udelay(1); continue; + } + + /* check for an uncorrectable error */ + if (readl(FL4ECCCR(flctl)) & _4ECCFA) { + /* check if we face a non-empty page */ + for (i = 0; i < 512; i++) { + if (flctl->done_buff[i] != 0xff) { + state = FL_ERROR; /* can't correct */ + break; + } + } + + if (state == FL_SUCCESS) + dev_dbg(&flctl->pdev->dev, + "reading empty sector %d, ecc error ignored\n", + sector_number); + + writel(0, FL4ECCCR(flctl)); + continue; + } /* start error correction */ ecc_reg[0] = FL4ECCRESULT0(flctl); @@ -194,28 +223,26 @@ static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number) ecc_reg[3] = FL4ECCRESULT3(flctl); for (i = 0; i < 3; i++) { + uint8_t org; + int index; + data = readl(ecc_reg[i]); - if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) { - uint8_t org; - int index; - if (flctl->page_size) - index = (512 * sector_number) + - (data >> 16); - else - index = data >> 16; + if (flctl->page_size) + index = (512 * sector_number) + + (data >> 16); + else + index = data >> 16; - org = flctl->done_buff[index]; - flctl->done_buff[index] = org ^ (data & 0xFF); - checked[i] = 1; - } + org = flctl->done_buff[index]; + flctl->done_buff[index] = org ^ (data & 0xFF); } - + state = FL_REPAIRABLE; writel(0, FL4ECCCR(flctl)); } timeout_error(flctl, __func__); - return 1; /* timeout */ + return FL_TIMEOUT; /* timeout */ } static void wait_wecfifo_ready(struct sh_flctl *flctl) @@ -259,20 +286,23 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset) } } -static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff, int sector) +static enum flctl_ecc_res_t read_ecfiforeg + (struct sh_flctl *flctl, uint8_t *buff, int sector) { int i; + enum flctl_ecc_res_t res; unsigned long *ecc_buf = (unsigned long *)buff; - void *fifo_addr = (void *)FLECFIFO(flctl); - for (i = 0; i < 4; i++) { - if (wait_recfifo_ready(flctl , sector)) - return 1; - ecc_buf[i] = readl(fifo_addr); - ecc_buf[i] = be32_to_cpu(ecc_buf[i]); + res = wait_recfifo_ready(flctl , sector); + + if (res != FL_ERROR) { + for (i = 0; i < 4; i++) { + ecc_buf[i] = readl(FLECFIFO(flctl)); + ecc_buf[i] = be32_to_cpu(ecc_buf[i]); + } } - return 0; + return res; } static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) @@ -367,6 +397,7 @@ static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) { struct sh_flctl *flctl = mtd_to_flctl(mtd); int sector, page_sectors; + enum flctl_ecc_res_t ecc_result; page_sectors = flctl->page_size ? 4 : 1; @@ -382,17 +413,27 @@ static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) start_translation(flctl); for (sector = 0; sector < page_sectors; sector++) { - int ret; read_fiforeg(flctl, 512, 512 * sector); - ret = read_ecfiforeg(flctl, + ecc_result = read_ecfiforeg(flctl, &flctl->done_buff[mtd->writesize + 16 * sector], sector); - if (ret) - flctl->hwecc_cant_correct[sector] = 1; - - writel(0x0, FL4ECCCR(flctl)); + switch (ecc_result) { + case FL_REPAIRABLE: + dev_info(&flctl->pdev->dev, + "applied ecc on page 0x%x", page_addr); + flctl->mtd.ecc_stats.corrected++; + break; + case FL_ERROR: + dev_warn(&flctl->pdev->dev, + "page 0x%x contains corrupted data\n", + page_addr); + flctl->mtd.ecc_stats.failed++; + break; + default: + ; + } } wait_completion(flctl); diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index 3feaae062feb..01e4b15b280e 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -129,9 +129,15 @@ #define _4ECCEND (0x1 << 1) /* 4 symbols end */ #define _4ECCEXST (0x1 << 0) /* 4 symbols exist */ -#define INIT_FL4ECCRESULT_VAL 0x03FF03FF #define LOOP_TIMEOUT_MAX 0x00010000 +enum flctl_ecc_res_t { + FL_SUCCESS, + FL_REPAIRABLE, + FL_ERROR, + FL_TIMEOUT +}; + struct sh_flctl { struct mtd_info mtd; struct nand_chip chip; @@ -151,8 +157,6 @@ struct sh_flctl { uint32_t flcmncr_base; /* base value of FLCMNCR */ uint32_t flintdmacr_base; /* irq enable bits */ - int hwecc_cant_correct[4]; - unsigned page_size:1; /* NAND page size (0 = 512, 1 = 2048) */ unsigned hwecc:1; /* Hardware ECC (0 = disabled, 1 = enabled) */ unsigned holden:1; /* Hardware has FLHOLDCR and HOLDEN is set */ From 3166df0d0424ef5c742faba87775cfca99e8f2bf Mon Sep 17 00:00:00 2001 From: Bastian Hecht Date: Mon, 14 May 2012 14:14:47 +0200 Subject: [PATCH 0020/5375] mtd: sh_flctl: Use user oob data in hardware ECC mode In hardware ecc mode, the flctl now writes and reads the oob data provided by the user. Additionally the ECC is now returned in normal page reads, not only when using the explicit NAND_CMD_READOOB command. Signed-off-by: Bastian Hecht Acked-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/sh_flctl.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index bc50e83336bb..2eb15418c227 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -275,13 +275,12 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset) { int i, len_4align; unsigned long *buf = (unsigned long *)&flctl->done_buff[offset]; - void *fifo_addr = (void *)FLDTFIFO(flctl); len_4align = (rlen + 3) / 4; for (i = 0; i < len_4align; i++) { wait_rfifo_ready(flctl); - buf[i] = readl(fifo_addr); + buf[i] = readl(FLDTFIFO(flctl)); buf[i] = be32_to_cpu(buf[i]); } } @@ -318,6 +317,18 @@ static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset) } } +static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, int offset) +{ + int i, len_4align; + unsigned long *data = (unsigned long *)&flctl->done_buff[offset]; + + len_4align = (rlen + 3) / 4; + for (i = 0; i < len_4align; i++) { + wait_wecfifo_ready(flctl); + writel(cpu_to_be32(data[i]), FLECFIFO(flctl)); + } +} + static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val) { struct sh_flctl *flctl = mtd_to_flctl(mtd); @@ -384,6 +395,7 @@ static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { chip->read_buf(mtd, buf, mtd->writesize); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); return 0; } @@ -391,6 +403,7 @@ static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { chip->write_buf(mtd, buf, mtd->writesize); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); } static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) @@ -466,7 +479,7 @@ static void execmd_read_oob(struct mtd_info *mtd, int page_addr) static void execmd_write_page_sector(struct mtd_info *mtd) { struct sh_flctl *flctl = mtd_to_flctl(mtd); - int i, page_addr = flctl->seqin_page_addr; + int page_addr = flctl->seqin_page_addr; int sector, page_sectors; page_sectors = flctl->page_size ? 4 : 1; @@ -482,11 +495,7 @@ static void execmd_write_page_sector(struct mtd_info *mtd) for (sector = 0; sector < page_sectors; sector++) { write_fiforeg(flctl, 512, 512 * sector); - - for (i = 0; i < 4; i++) { - wait_wecfifo_ready(flctl); /* wait for write ready */ - writel(0xFFFFFFFF, FLECFIFO(flctl)); - } + write_ec_fiforeg(flctl, 16, mtd->writesize + 16 * sector); } wait_completion(flctl); From bfea1d4ee53c4628a7bbdcfe3b026f8ce4032a1c Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 18 May 2012 18:44:53 +0300 Subject: [PATCH 0021/5375] mtd: tests: use random32 instead of home-brewed generator This is a clean-up patch which removes the own pseudo-random numbers generator from the speed- and stress-tests and makes them use the 'random32()' generator instead. [dwmw2: Merge later fix for negative offsets] Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/tests/mtd_speedtest.c | 16 ++---------- drivers/mtd/tests/mtd_stresstest.c | 39 +++++++----------------------- 2 files changed, 11 insertions(+), 44 deletions(-) diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c index 2aec4f3b72be..42b0f7456fc4 100644 --- a/drivers/mtd/tests/mtd_speedtest.c +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -26,6 +26,7 @@ #include #include #include +#include #define PRINT_PREF KERN_INFO "mtd_speedtest: " @@ -47,25 +48,13 @@ static int ebcnt; static int pgcnt; static int goodebcnt; static struct timeval start, finish; -static unsigned long next = 1; - -static inline unsigned int simple_rand(void) -{ - next = next * 1103515245 + 12345; - return (unsigned int)((next / 65536) % 32768); -} - -static inline void simple_srand(unsigned long seed) -{ - next = seed; -} static void set_random_data(unsigned char *buf, size_t len) { size_t i; for (i = 0; i < len; ++i) - buf[i] = simple_rand(); + buf[i] = random32(); } static int erase_eraseblock(int ebnum) @@ -407,7 +396,6 @@ static int __init mtd_speedtest_init(void) goto out; } - simple_srand(1); set_random_data(iobuf, mtd->erasesize); err = scan_for_bad_eraseblocks(); diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c index 7b33f22d0b58..cb268cebf01a 100644 --- a/drivers/mtd/tests/mtd_stresstest.c +++ b/drivers/mtd/tests/mtd_stresstest.c @@ -27,6 +27,7 @@ #include #include #include +#include #define PRINT_PREF KERN_INFO "mtd_stresstest: " @@ -48,28 +49,13 @@ static int pgsize; static int bufsize; static int ebcnt; static int pgcnt; -static unsigned long next = 1; - -static inline unsigned int simple_rand(void) -{ - next = next * 1103515245 + 12345; - return (unsigned int)((next / 65536) % 32768); -} - -static inline void simple_srand(unsigned long seed) -{ - next = seed; -} static int rand_eb(void) { - int eb; + unsigned int eb; again: - if (ebcnt < 32768) - eb = simple_rand(); - else - eb = (simple_rand() << 15) | simple_rand(); + eb = random32(); /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */ eb %= (ebcnt - 1); if (bbt[eb]) @@ -79,24 +65,18 @@ again: static int rand_offs(void) { - int offs; + unsigned int offs; - if (bufsize < 32768) - offs = simple_rand(); - else - offs = (simple_rand() << 15) | simple_rand(); + offs = random32(); offs %= bufsize; return offs; } static int rand_len(int offs) { - int len; + unsigned int len; - if (bufsize < 32768) - len = simple_rand(); - else - len = (simple_rand() << 15) | simple_rand(); + len = random32(); len %= (bufsize - offs); return len; } @@ -211,7 +191,7 @@ static int do_write(void) static int do_operation(void) { - if (simple_rand() & 1) + if (random32() & 1) return do_read(); else return do_write(); @@ -302,9 +282,8 @@ static int __init mtd_stresstest_init(void) } for (i = 0; i < ebcnt; i++) offsets[i] = mtd->erasesize; - simple_srand(current->pid); for (i = 0; i < bufsize; i++) - writebuf[i] = simple_rand(); + writebuf[i] = random32(); err = scan_for_bad_eraseblocks(); if (err) From b1ccfab31a0bbcb103989cba3b08df0776ff90fe Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 22 May 2012 07:30:47 -0700 Subject: [PATCH 0022/5375] mtd: nand: add Eon Silicon Solutions manufacturer ID Eon's new NAND flash: EN27LN1G08. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_ids.c | 1 + include/linux/mtd/nand.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 621b70b7a159..509a9f6706f3 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -176,6 +176,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_MICRON, "Micron"}, {NAND_MFR_AMD, "AMD"}, {NAND_MFR_MACRONIX, "Macronix"}, + {NAND_MFR_EON, "Eon"}, {0x0, "Unknown"} }; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 57977c640529..53dcf4973c1b 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -559,6 +559,7 @@ struct nand_chip { #define NAND_MFR_MICRON 0x2c #define NAND_MFR_AMD 0x01 #define NAND_MFR_MACRONIX 0xc2 +#define NAND_MFR_EON 0x92 /** * struct nand_flash_dev - NAND Flash Device ID Structure From 63d99c0e89039e1509209d36ee17fc374fd112c9 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 22 May 2012 07:30:48 -0700 Subject: [PATCH 0023/5375] mtd: nand: remove NAND_BBT_SEARCH option This option was never used and isn't currently used. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- Documentation/DocBook/mtdnand.tmpl | 2 -- include/linux/mtd/bbm.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/Documentation/DocBook/mtdnand.tmpl b/Documentation/DocBook/mtdnand.tmpl index e0aedb7a7827..fe122d6e686f 100644 --- a/Documentation/DocBook/mtdnand.tmpl +++ b/Documentation/DocBook/mtdnand.tmpl @@ -1216,8 +1216,6 @@ in this page #define NAND_BBT_LASTBLOCK 0x00000010 /* The bbt is at the given page, else we must scan for the bbt */ #define NAND_BBT_ABSPAGE 0x00000020 -/* The bbt is at the given page, else we must scan for the bbt */ -#define NAND_BBT_SEARCH 0x00000040 /* bbt is stored per chip on multichip devices */ #define NAND_BBT_PERCHIP 0x00000080 /* bbt has a version counter at offset veroffs */ diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 650ef352f045..5d9fcb7645ae 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -78,8 +78,6 @@ struct nand_bbt_descr { #define NAND_BBT_LASTBLOCK 0x00000010 /* The bbt is at the given page, else we must scan for the bbt */ #define NAND_BBT_ABSPAGE 0x00000020 -/* The bbt is at the given page, else we must scan for the bbt */ -#define NAND_BBT_SEARCH 0x00000040 /* bbt is stored per chip on multichip devices */ #define NAND_BBT_PERCHIP 0x00000080 /* bbt has a version counter at offset veroffs */ From 1696e6bc2ae83734e64e206ac99766ea19e9a14e Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 22 May 2012 23:50:00 -0700 Subject: [PATCH 0024/5375] mtd: nand: kill NAND_NO_READRDY According to its documentation, the NAND_NO_READRDY option is always used when autoincrement is not supported. Autoincrement support was recently dropped, so we can drop this options as well (defaulting to "no read ready check"). Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsl_elbc_nand.c | 1 - drivers/mtd/nand/fsl_ifc_nand.c | 1 - drivers/mtd/nand/nand_base.c | 17 ----------------- drivers/mtd/nand/nand_ids.c | 4 ++-- drivers/mtd/nand/pxa3xx_nand.c | 1 - include/linux/mtd/nand.h | 6 ------ 6 files changed, 2 insertions(+), 28 deletions(-) diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 784293806110..1d8d111fa3ae 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -805,7 +805,6 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->bbt_md = &bbt_mirror_descr; /* set up nand options */ - chip->options = NAND_NO_READRDY; chip->bbt_options = NAND_BBT_USE_FLASH; chip->controller = &elbc_fcm_ctrl->controller; diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 9602c1b7e27e..c5d7f382759d 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -805,7 +805,6 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) out_be32(&ifc->ifc_nand.ncfgr, 0x0); /* set up nand options */ - chip->options = NAND_NO_READRDY; chip->bbt_options = NAND_BBT_USE_FLASH; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a11253a0fcab..0a8724e657d7 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1565,14 +1565,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, oobreadlen -= toread; } } - - if (!(chip->options & NAND_NO_READRDY)) { - /* Apply delay or wait for ready/busy pin */ - if (!chip->dev_ready) - udelay(chip->chip_delay); - else - nand_wait_ready(mtd); - } } else { memcpy(buf, chip->buffers->databuf + col, bytes); buf += bytes; @@ -1837,14 +1829,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, len = min(len, readlen); buf = nand_transfer_oob(chip, buf, ops, len); - if (!(chip->options & NAND_NO_READRDY)) { - /* Apply delay or wait for ready/busy pin */ - if (!chip->dev_ready) - udelay(chip->chip_delay); - else - nand_wait_ready(mtd); - } - readlen -= len; if (!readlen) break; @@ -2915,7 +2899,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, *busw = NAND_BUSWIDTH_16; chip->options &= ~NAND_CHIPOPTIONS_MSK; - chip->options |= NAND_NO_READRDY & NAND_CHIPOPTIONS_MSK; pr_info("ONFI flash detected\n"); return 1; diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 509a9f6706f3..e04c675bf609 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -70,7 +70,7 @@ struct nand_flash_dev nand_flash_ids[] = { * These are the new chips with large page size. The pagesize and the * erasesize is determined from the extended id bytes */ -#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY) +#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) /* 512 Megabit */ @@ -157,7 +157,7 @@ struct nand_flash_dev nand_flash_ids[] = { * writes possible, but not implemented now */ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, - NAND_IS_AND | NAND_NO_READRDY | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, + NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, {NULL,} }; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 252aaefcacfa..afc4681f44d7 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1005,7 +1005,6 @@ KEEP_CONFIG: chip->ecc.size = host->page_size; chip->ecc.strength = 1; - chip->options |= NAND_NO_READRDY; if (host->reg_ndcr & NDCR_DWIDTH_M) chip->options |= NAND_BUSWIDTH_16; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 53dcf4973c1b..a81ac89a6950 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -185,12 +185,6 @@ typedef enum { * This happens with the Renesas AG-AND chips, possibly others. */ #define BBT_AUTO_REFRESH 0x00000080 -/* - * Chip does not require ready check on read. True - * for all large page devices, as they do not support - * autoincrement. - */ -#define NAND_NO_READRDY 0x00000100 /* Chip does not allow subpage writes */ #define NAND_NO_SUBPAGE_WRITE 0x00000200 From 3d059693f6e0489066a98f455601137fa003df77 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 25 May 2012 20:14:50 -0300 Subject: [PATCH 0025/5375] nand: mxc_nand: Use clk_prepare_enable/clk_disable_unprepare Prepare the clock before enabling it. Signed-off-by: Fabio Estevam Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/mxc_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 6acc790c2fbb..fc3b38c7ffb4 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -784,7 +784,7 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip) if (chip == -1) { /* Disable the NFC clock */ if (host->clk_act) { - clk_disable(host->clk); + clk_disable_unprepare(host->clk); host->clk_act = 0; } return; @@ -792,7 +792,7 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip) if (!host->clk_act) { /* Enable the NFC clock */ - clk_enable(host->clk); + clk_prepare_enable(host->clk); host->clk_act = 1; } From 9d6367f4f7835131b2b3987d134fd4c44636fa8d Mon Sep 17 00:00:00 2001 From: "ing. Federico Fuga" Date: Tue, 5 Jun 2012 17:37:01 +0200 Subject: [PATCH 0026/5375] mtd: add JEDEC ID for w25q32dw to chip table Adds JEDEC ID for the 1.8V version of WinBond w25q32. Signed-off-by: Federico Fuga Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 5d0d68c3fe27..4b8b45435e0f 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -730,6 +730,7 @@ static const struct spi_device_id m25p_ids[] = { { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, + { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, From 874d72c4fe07713c4889c944d3c7ebbce352c762 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Wed, 6 Jun 2012 18:36:39 -0500 Subject: [PATCH 0027/5375] mtd: elbc nand: use drvdata to only remove the relevant chip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the remove method was looping and removing all chips, which is obviously not the right thing to do — left over from when the driver was organized differently and that was the remove method for the entire controller. This would result in bad things happening if you have more than one NAND chip, and remove the module. This also fixes priv->dev to properly point to the chip's device rather than the controller's. Until now priv->dev was only used for error/debug prints (and it's an improvement there), so this shouldn't break anything. Signed-off-by: Scott Wood Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/fsl_elbc_nand.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 1d8d111fa3ae..22bb5e6ddaca 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -915,7 +915,8 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) elbc_fcm_ctrl->chips[bank] = priv; priv->bank = bank; priv->ctrl = fsl_lbc_ctrl_dev; - priv->dev = dev; + priv->dev = &pdev->dev; + dev_set_drvdata(priv->dev, priv); priv->vbase = ioremap(res.start, resource_size(&res)); if (!priv->vbase) { @@ -962,11 +963,10 @@ err: static int fsl_elbc_nand_remove(struct platform_device *pdev) { - int i; struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand; - for (i = 0; i < MAX_BANKS; i++) - if (elbc_fcm_ctrl->chips[i]) - fsl_elbc_chip_remove(elbc_fcm_ctrl->chips[i]); + struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev); + + fsl_elbc_chip_remove(priv); mutex_lock(&fsl_elbc_nand_mutex); elbc_fcm_ctrl->counter--; From e4a09cbf2dc7ba6c7fd7e07a3ab3d3f499a575e2 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 6 Jun 2012 12:33:13 +0200 Subject: [PATCH 0028/5375] mtd: mxc_nand: Use managed resources To make the error path simpler and to make subsequent patches easier. Signed-off-by: Sascha Hauer Acked-by: Shawn Guo Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/mxc_nand.c | 70 ++++++++++++------------------------- 1 file changed, 23 insertions(+), 47 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index fc3b38c7ffb4..db428c24e2c8 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1344,8 +1344,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) int err = 0; /* Allocate memory for MTD device structure and private data */ - host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE + - NAND_MAX_OOBSIZE, GFP_KERNEL); + host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host) + + NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL); if (!host) return -ENOMEM; @@ -1372,26 +1372,17 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->read_buf = mxc_nand_read_buf; this->verify_buf = mxc_nand_verify_buf; - host->clk = clk_get(&pdev->dev, "nfc"); - if (IS_ERR(host->clk)) { - err = PTR_ERR(host->clk); - goto eclk; - } - - clk_prepare_enable(host->clk); - host->clk_act = 1; + host->clk = devm_clk_get(&pdev->dev, "nfc"); + if (IS_ERR(host->clk)) + return PTR_ERR(host->clk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - err = -ENODEV; - goto eres; - } + if (!res) + return -ENODEV; - host->base = ioremap(res->start, resource_size(res)); - if (!host->base) { - err = -ENOMEM; - goto eres; - } + host->base = devm_request_and_ioremap(&pdev->dev, res); + if (!host->base) + return -ENOMEM; host->main_area0 = host->base; @@ -1399,7 +1390,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) if (err > 0) err = mxcnd_probe_pdata(host); if (err < 0) - goto eirq; + return err; if (host->devtype_data->regs_offset) host->regs = host->base + host->devtype_data->regs_offset; @@ -1416,15 +1407,11 @@ static int __init mxcnd_probe(struct platform_device *pdev) if (host->devtype_data->needs_ip) { res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) { - err = -ENODEV; - goto eirq; - } - host->regs_ip = ioremap(res->start, resource_size(res)); - if (!host->regs_ip) { - err = -ENOMEM; - goto eirq; - } + if (!res) + return -ENODEV; + host->regs_ip = devm_request_and_ioremap(&pdev->dev, res); + if (!host->regs_ip) + return -ENOMEM; } if (host->pdata.hw_ecc) { @@ -1458,9 +1445,13 @@ static int __init mxcnd_probe(struct platform_device *pdev) */ host->devtype_data->irq_control(host, 0); - err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); + err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq, + IRQF_DISABLED, DRIVER_NAME, host); if (err) - goto eirq; + return err; + + clk_prepare_enable(host->clk); + host->clk_act = 1; /* * Now that we "own" the interrupt make sure the interrupt mask bit is @@ -1512,15 +1503,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) return 0; escan: - free_irq(host->irq, host); -eirq: - if (host->regs_ip) - iounmap(host->regs_ip); - iounmap(host->base); -eres: - clk_put(host->clk); -eclk: - kfree(host); + clk_disable_unprepare(host->clk); return err; } @@ -1529,16 +1512,9 @@ static int __devexit mxcnd_remove(struct platform_device *pdev) { struct mxc_nand_host *host = platform_get_drvdata(pdev); - clk_put(host->clk); - platform_set_drvdata(pdev, NULL); nand_release(&host->mtd); - free_irq(host->irq, host); - if (host->regs_ip) - iounmap(host->regs_ip); - iounmap(host->base); - kfree(host); return 0; } From 71885b650ab0fd9d2d35cd922bf949c07c171b04 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 6 Jun 2012 12:33:14 +0200 Subject: [PATCH 0029/5375] mtd: mxc_nand: swap iomem resource order The i.MX v3 nand controller (i.MX5) needs two memory resources. Traditionally we have the AXI resource first. For sorting in this driver into the devicetree it feels much more natural to have the IP resource first. This patch swaps the ordering of these two resources. Signed-off-by: Sascha Hauer Acked-by: Shawn Guo Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- arch/arm/plat-mxc/devices/platform-mxc_nand.c | 11 +++--- drivers/mtd/nand/mxc_nand.c | 35 ++++++++++--------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/arch/arm/plat-mxc/devices/platform-mxc_nand.c b/arch/arm/plat-mxc/devices/platform-mxc_nand.c index 1568f39fba8b..95b75cc70515 100644 --- a/arch/arm/plat-mxc/devices/platform-mxc_nand.c +++ b/arch/arm/plat-mxc/devices/platform-mxc_nand.c @@ -63,10 +63,6 @@ struct platform_device *__init imx_add_mxc_nand( /* AXI has to come first, that's how the mxc_nand driver expect it */ struct resource res[] = { { - .start = data->axibase, - .end = data->axibase + SZ_16K - 1, - .flags = IORESOURCE_MEM, - }, { .start = data->iobase, .end = data->iobase + data->iosize - 1, .flags = IORESOURCE_MEM, @@ -74,10 +70,13 @@ struct platform_device *__init imx_add_mxc_nand( .start = data->irq, .end = data->irq, .flags = IORESOURCE_IRQ, + }, { + .start = data->axibase, + .end = data->axibase + SZ_16K - 1, + .flags = IORESOURCE_MEM, }, }; return imx_add_platform_device("mxc_nand", data->id, - res + !data->axibase, - ARRAY_SIZE(res) - !data->axibase, + res, ARRAY_SIZE(res) - !data->axibase, pdata, sizeof(*pdata)); } diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index db428c24e2c8..48c57275001f 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1376,7 +1376,25 @@ static int __init mxcnd_probe(struct platform_device *pdev) if (IS_ERR(host->clk)) return PTR_ERR(host->clk); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + err = mxcnd_probe_dt(host); + if (err > 0) + err = mxcnd_probe_pdata(host); + if (err < 0) + return err; + + if (host->devtype_data->needs_ip) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + host->regs_ip = devm_request_and_ioremap(&pdev->dev, res); + if (!host->regs_ip) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + } else { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + } + if (!res) return -ENODEV; @@ -1386,12 +1404,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) host->main_area0 = host->base; - err = mxcnd_probe_dt(host); - if (err > 0) - err = mxcnd_probe_pdata(host); - if (err < 0) - return err; - if (host->devtype_data->regs_offset) host->regs = host->base + host->devtype_data->regs_offset; host->spare0 = host->base + host->devtype_data->spare0_offset; @@ -1405,15 +1417,6 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->ecc.size = 512; this->ecc.layout = host->devtype_data->ecclayout_512; - if (host->devtype_data->needs_ip) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) - return -ENODEV; - host->regs_ip = devm_request_and_ioremap(&pdev->dev, res); - if (!host->regs_ip) - return -ENOMEM; - } - if (host->pdata.hw_ecc) { this->ecc.calculate = mxc_nand_calculate_ecc; this->ecc.hwctl = mxc_nand_enable_hwecc; From 71718a8edf688eb02a9475b7f567e3ec383c9734 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 6 Jun 2012 12:33:15 +0200 Subject: [PATCH 0030/5375] mtd: mxc_nand: add i.MX53 support The only relevant change between i.MX51 and i.MX53 is that a bitfield is shifted one bit to the left. Signed-off-by: Sascha Hauer Acked-by: Shawn Guo Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/mxc_nand.c | 48 ++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 48c57275001f..3f94e1f13231 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -43,8 +43,8 @@ #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) -#define nfc_is_v3_2() (cpu_is_mx51() || cpu_is_mx53()) -#define nfc_is_v3() nfc_is_v3_2() +#define nfc_is_v3_2a() cpu_is_mx51() +#define nfc_is_v3_2b() cpu_is_mx53() /* Addresses for NFC registers */ #define NFC_V1_V2_BUF_SIZE (host->regs + 0x00) @@ -122,7 +122,7 @@ #define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4) #define NFC_V3_CONFIG2_NUM_ADDR_PHASE0 (1 << 5) #define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6) -#define NFC_V3_CONFIG2_PPB(x) (((x) & 0x3) << 7) +#define NFC_V3_CONFIG2_PPB(x, shift) (((x) & 0x3) << shift) #define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x) (((x) & 0x3) << 12) #define NFC_V3_CONFIG2_INT_MSK (1 << 15) #define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24) @@ -174,6 +174,7 @@ struct mxc_nand_devtype_data { int spare_len; int eccbytes; int eccsize; + int ppb_shift; }; struct mxc_nand_host { @@ -1021,7 +1022,9 @@ static void preset_v3(struct mtd_info *mtd) } if (mtd->writesize) { - config2 |= NFC_V3_CONFIG2_PPB(ffs(mtd->erasesize / mtd->writesize) - 6); + config2 |= NFC_V3_CONFIG2_PPB( + ffs(mtd->erasesize / mtd->writesize) - 6, + host->devtype_data->ppb_shift); host->eccsize = get_eccsize(mtd); if (host->eccsize == 8) config2 |= NFC_V3_CONFIG2_ECC_MODE_8; @@ -1234,7 +1237,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { .eccsize = 0, }; -/* v3: i.MX51, i.MX53 */ +/* v3.2a: i.MX51 */ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { .preset = preset_v3, .send_cmd = send_cmd_v3, @@ -1258,6 +1261,34 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { .spare_len = 64, .eccbytes = 0, .eccsize = 0, + .ppb_shift = 7, +}; + +/* v3.2b: i.MX53 */ +static const struct mxc_nand_devtype_data imx53_nand_devtype_data = { + .preset = preset_v3, + .send_cmd = send_cmd_v3, + .send_addr = send_addr_v3, + .send_page = send_page_v3, + .send_read_id = send_read_id_v3, + .get_dev_status = get_dev_status_v3, + .check_int = check_int_v3, + .irq_control = irq_control_v3, + .get_ecc_status = get_ecc_status_v3, + .ecclayout_512 = &nandv2_hw_eccoob_smallpage, + .ecclayout_2k = &nandv2_hw_eccoob_largepage, + .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */ + .select_chip = mxc_nand_select_chip_v1_v3, + .correct_data = mxc_nand_correct_data_v2_v3, + .irqpending_quirk = 0, + .needs_ip = 1, + .regs_offset = 0, + .spare0_offset = 0x1000, + .axi_offset = 0x1e00, + .spare_len = 64, + .eccbytes = 0, + .eccsize = 0, + .ppb_shift = 8, }; #ifdef CONFIG_OF_MTD @@ -1274,6 +1305,9 @@ static const struct of_device_id mxcnd_dt_ids[] = { }, { .compatible = "fsl,imx51-nand", .data = &imx51_nand_devtype_data, + }, { + .compatible = "fsl,imx53-nand", + .data = &imx53_nand_devtype_data, }, { /* sentinel */ } }; @@ -1327,8 +1361,10 @@ static int __init mxcnd_probe_pdata(struct mxc_nand_host *host) host->devtype_data = &imx27_nand_devtype_data; } else if (nfc_is_v21()) { host->devtype_data = &imx25_nand_devtype_data; - } else if (nfc_is_v3_2()) { + } else if (nfc_is_v3_2a()) { host->devtype_data = &imx51_nand_devtype_data; + } else if (nfc_is_v3_2b()) { + host->devtype_data = &imx53_nand_devtype_data; } else BUG(); From 75453a08e3658ca467cda3c5fe5632e563742421 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 6 Jun 2012 12:33:16 +0200 Subject: [PATCH 0031/5375] ARM: i.MX5: Add nand oftree support This adds snippets to the i.MX51/53 devicetrees for the nand flash controller. Signed-off-by: Sascha Hauer Acked-by: Shawn Guo Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- arch/arm/boot/dts/imx51.dtsi | 7 +++++++ arch/arm/boot/dts/imx53.dtsi | 7 +++++++ arch/arm/mach-imx/clk-imx51-imx53.c | 2 ++ 3 files changed, 16 insertions(+) diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index bfa65abe8ef2..39eb88e9971c 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -259,6 +259,13 @@ status = "disabled"; }; + nand@83fdb000 { + compatible = "fsl,imx51-nand"; + reg = <0x83fdb000 0x1000 0xcfff0000 0x10000>; + interrupts = <8>; + status = "disabled"; + }; + ssi3: ssi@83fe8000 { compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; reg = <0x83fe8000 0x4000>; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index e3e869470cd3..2b5caf9fe660 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -314,6 +314,13 @@ status = "disabled"; }; + nand@63fdb000 { + compatible = "fsl,imx53-nand"; + reg = <0x63fdb000 0x1000 0xf7ff0000 0x10000>; + interrupts = <8>; + status = "disabled"; + }; + ssi3: ssi@63fe8000 { compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; reg = <0x63fe8000 0x4000>; diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index fcd94f3b0f0e..7b525c1230d9 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -357,6 +357,7 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "83fcc000.ssi"); clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "70014000.ssi"); clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "83fe8000.ssi"); + clk_register_clkdev(clk[nfc_gate], NULL, "83fdb000.nand"); /* set the usboh3 parent to pll2_sw */ clk_set_parent(clk[usboh3_sel], clk[pll2_sw]); @@ -446,6 +447,7 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "63fcc000.ssi"); clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "50014000.ssi"); clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "63fd0000.ssi"); + clk_register_clkdev(clk[nfc_gate], NULL, "63fdb000.nand"); /* set SDHC root clock to 200MHZ*/ clk_set_rate(clk[esdhc_a_podf], 200000000); From 7bb9c75436212813b38700c34df4bbb6eb82debe Mon Sep 17 00:00:00 2001 From: Shmulik Ladkani Date: Sun, 10 Jun 2012 13:58:12 +0300 Subject: [PATCH 0032/5375] mtd: nand: Use the mirror BBT descriptor when reading its version The code responsible for reading the version of the mirror bbt was incorrectly using the descriptor of the main bbt. Pass the mirror bbt descriptor to 'scan_read_raw' when reading the version of the mirror bbt. Signed-off-by: Shmulik Ladkani Acked-by: Sebastian Andrzej Siewior Cc: stable@vger.kernel.org [v2.6.37+] Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_bbt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 30d1319ff065..c126469b0645 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -390,7 +390,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, - mtd->writesize, td); + mtd->writesize, md); md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; pr_info("Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); From 943b35a6da6c66b12a581b914195199bd0815390 Mon Sep 17 00:00:00 2001 From: Alexandre Pereira da Silva Date: Tue, 12 Jun 2012 16:42:40 -0300 Subject: [PATCH 0033/5375] mtd: m25p80: Add support for m25pe20 Signed-off-by: Alexandre Pereira da Silva Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 4b8b45435e0f..e924b4b37839 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -714,6 +714,7 @@ static const struct spi_device_id m25p_ids[] = { { "m45pe80", INFO(0x204014, 0, 64 * 1024, 16, 0) }, { "m45pe16", INFO(0x204015, 0, 64 * 1024, 32, 0) }, + { "m25pe20", INFO(0x208012, 0, 64 * 1024, 4, 0) }, { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, From 95c1b0ce2ad8bfc0092782a75e86b219eb2c5204 Mon Sep 17 00:00:00 2001 From: Alexandre Pereira da Silva Date: Tue, 12 Jun 2012 16:55:15 -0300 Subject: [PATCH 0034/5375] mtd: m25p80: Add support for n25q064 Signed-off-by: Alexandre Pereira da Silva Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index e924b4b37839..afa77c02aaf7 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -646,6 +646,7 @@ static const struct spi_device_id m25p_ids[] = { { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, /* Macronix */ { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, From 3dfe41a4c705223c66373968327407e11c2fb1a1 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 25 Jun 2012 18:07:43 +0800 Subject: [PATCH 0035/5375] mtd: at91: extract hw ecc initialization to one function This patch moves hw ecc initialization code to one function. Signed-off-by: Hong Xu Signed-off-by: Josh Wu Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/atmel_nand.c | 127 ++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 61 deletions(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 97ac6712bb19..7a41a04beb87 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -527,6 +527,66 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host, } #endif +static int __init atmel_hw_nand_init_params(struct platform_device *pdev, + struct atmel_nand_host *host) +{ + struct mtd_info *mtd = &host->mtd; + struct nand_chip *nand_chip = &host->nand_chip; + struct resource *regs; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!regs) { + dev_err(host->dev, + "Can't get I/O resource regs, use software ECC\n"); + nand_chip->ecc.mode = NAND_ECC_SOFT; + return 0; + } + + host->ecc = ioremap(regs->start, resource_size(regs)); + if (host->ecc == NULL) { + dev_err(host->dev, "ioremap failed\n"); + return -EIO; + } + + /* ECC is calculated for the whole page (1 step) */ + nand_chip->ecc.size = mtd->writesize; + + /* set ECC page size and oob layout */ + switch (mtd->writesize) { + case 512: + nand_chip->ecc.layout = &atmel_oobinfo_small; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); + break; + case 1024: + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); + break; + case 2048: + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); + break; + case 4096: + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); + break; + default: + /* page size not handled by HW ECC */ + /* switching back to soft ECC */ + nand_chip->ecc.mode = NAND_ECC_SOFT; + return 0; + } + + /* set up for HW ECC */ + nand_chip->ecc.calculate = atmel_nand_calculate; + nand_chip->ecc.correct = atmel_nand_correct; + nand_chip->ecc.hwctl = atmel_nand_hwctl; + nand_chip->ecc.read_page = atmel_nand_read_page; + nand_chip->ecc.bytes = 4; + nand_chip->ecc.strength = 1; + + return 0; +} + /* * Probe for the NAND device. */ @@ -535,7 +595,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev) struct atmel_nand_host *host; struct mtd_info *mtd; struct nand_chip *nand_chip; - struct resource *regs; struct resource *mem; struct mtd_part_parser_data ppdata = {}; int res; @@ -587,29 +646,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev) nand_chip->dev_ready = atmel_nand_device_ready; nand_chip->ecc.mode = host->board.ecc_mode; - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) { - printk(KERN_ERR "atmel_nand: can't get I/O resource " - "regs\nFalling back on software ECC\n"); - nand_chip->ecc.mode = NAND_ECC_SOFT; - } - - if (nand_chip->ecc.mode == NAND_ECC_HW) { - host->ecc = ioremap(regs->start, resource_size(regs)); - if (host->ecc == NULL) { - printk(KERN_ERR "atmel_nand: ioremap failed\n"); - res = -EIO; - goto err_ecc_ioremap; - } - nand_chip->ecc.calculate = atmel_nand_calculate; - nand_chip->ecc.correct = atmel_nand_correct; - nand_chip->ecc.hwctl = atmel_nand_hwctl; - nand_chip->ecc.read_page = atmel_nand_read_page; - nand_chip->ecc.bytes = 4; - nand_chip->ecc.strength = 1; - } - nand_chip->chip_delay = 20; /* 20us command delay time */ if (host->board.bus_width_16) /* 16-bit bus width */ @@ -661,40 +697,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev) } if (nand_chip->ecc.mode == NAND_ECC_HW) { - /* ECC is calculated for the whole page (1 step) */ - nand_chip->ecc.size = mtd->writesize; - - /* set ECC page size and oob layout */ - switch (mtd->writesize) { - case 512: - nand_chip->ecc.layout = &atmel_oobinfo_small; - ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); - break; - case 1024: - nand_chip->ecc.layout = &atmel_oobinfo_large; - ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); - break; - case 2048: - nand_chip->ecc.layout = &atmel_oobinfo_large; - ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); - break; - case 4096: - nand_chip->ecc.layout = &atmel_oobinfo_large; - ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); - break; - default: - /* page size not handled by HW ECC */ - /* switching back to soft ECC */ - nand_chip->ecc.mode = NAND_ECC_SOFT; - nand_chip->ecc.calculate = NULL; - nand_chip->ecc.correct = NULL; - nand_chip->ecc.hwctl = NULL; - nand_chip->ecc.read_page = NULL; - nand_chip->ecc.postpad = 0; - nand_chip->ecc.prepad = 0; - nand_chip->ecc.bytes = 0; - break; - } + res = atmel_hw_nand_init_params(pdev, host); + if (res != 0) + goto err_hw_ecc; } /* second phase scan */ @@ -711,15 +716,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev) return res; err_scan_tail: + if (host->ecc) + iounmap(host->ecc); +err_hw_ecc: 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: iounmap(host->io_base); err_nand_ioremap: kfree(host); From fdbad98dff8007f2b8bee6698b5d25ebba0471c9 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 25 Jun 2012 18:07:45 +0800 Subject: [PATCH 0036/5375] mtd: nand: teach write_page and write_page_raw return an error code There is an implemention of hardware ECC write page function which may return an error indication. For instance, using Atmel HW PMECC to write one page into a nand flash, the hardware engine will compute the BCH ecc code for this page. so we need read a the status register to theck whether the ecc code is generated. But we cannot assume the status register always can be ready, for example, incorrect hardware configuration or hardware issue, in such case we need write_page() to return a error code. Since the definition of 'write_page' function in struct nand_ecc_ctrl is 'void'. So this patch will: 1. add return 'int' value for 'write_page' function. 2. to be consitent, add return 'int' value for 'write_page_raw' fuctions too. 3. add code to test the return value, and if negative, indicate an error happend when write page with ECC. 4. fix the compile warning in all impacted nand flash driver. Note: I couldn't compile-test all of these easily, as some had ARCH dependencies. Signed-off-by: Josh Wu Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/bcm_umi_bch.c | 6 ++++-- drivers/mtd/nand/bf5xx_nand.c | 6 ++++-- drivers/mtd/nand/cafe_nand.c | 11 ++++++++--- drivers/mtd/nand/denali.c | 12 +++++++----- drivers/mtd/nand/docg4.c | 8 +++++--- drivers/mtd/nand/fsl_elbc_nand.c | 4 +++- drivers/mtd/nand/fsl_ifc_nand.c | 4 +++- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 6 ++++-- drivers/mtd/nand/nand_base.c | 27 ++++++++++++++++++-------- drivers/mtd/nand/pxa3xx_nand.c | 4 +++- drivers/mtd/nand/sh_flctl.c | 3 ++- include/linux/mtd/nand.h | 4 ++-- 12 files changed, 64 insertions(+), 31 deletions(-) diff --git a/drivers/mtd/nand/bcm_umi_bch.c b/drivers/mtd/nand/bcm_umi_bch.c index 5914bb32e001..c8799a001833 100644 --- a/drivers/mtd/nand/bcm_umi_bch.c +++ b/drivers/mtd/nand/bcm_umi_bch.c @@ -23,7 +23,7 @@ /* ---- Private Function Prototypes -------------------------------------- */ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page); -static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd, +static int bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required); /* ---- Private Variables ------------------------------------------------ */ @@ -194,7 +194,7 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, * @oob_required: must write chip->oob_poi to OOB * ***************************************************************************/ -static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd, +static int bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { int sectorIdx = 0; @@ -214,4 +214,6 @@ static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd, } bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; } diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 3f1c18599cbd..ab0caa74eb43 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -566,11 +566,13 @@ static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip return 0; } -static void bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) +static int bf5xx_nand_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, int oob_required) { bf5xx_nand_write_buf(mtd, buf, mtd->writesize); bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; } /* diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index ac0d967ee3fd..08248a0a167e 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -520,7 +520,7 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = { }; -static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd, +static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { @@ -531,6 +531,8 @@ static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd, /* Set up ECC autogeneration */ cafe->ctl2 |= (1<<30); + + return 0; } static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, @@ -542,9 +544,12 @@ static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); if (unlikely(raw)) - chip->ecc.write_page_raw(mtd, chip, buf, oob_required); + status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required); else - chip->ecc.write_page(mtd, chip, buf, oob_required); + status = chip->ecc.write_page(mtd, chip, buf, oob_required); + + if (status < 0) + return status; /* * Cached progamming disabled for now, Not sure if its worth the diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 0650aafa0dd2..e706a237170f 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1028,7 +1028,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) /* writes a page. user specifies type, and this function handles the * configuration details. */ -static void write_page(struct mtd_info *mtd, struct nand_chip *chip, +static int write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, bool raw_xfer) { struct denali_nand_info *denali = mtd_to_denali(mtd); @@ -1078,6 +1078,8 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip, denali_enable_dma(denali, false); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE); + + return 0; } /* NAND core entry points */ @@ -1086,24 +1088,24 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip, * writing a page with ECC or without is similar, all the work is done * by write_page above. * */ -static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, +static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { /* for regular page writes, we let HW handle all the ECC * data written to the device. */ - write_page(mtd, chip, buf, false); + return write_page(mtd, chip, buf, false); } /* This is the callback that the NAND core calls to write a page without ECC. * 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, +static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { /* for raw page writes, we want to disable ECC and simply write whatever data is in the buffer. */ - write_page(mtd, chip, buf, true); + return write_page(mtd, chip, buf, true); } static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index a225e49a5623..0f2ffd7b6c82 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -898,7 +898,7 @@ static void docg4_erase_block(struct mtd_info *mtd, int page) write_nop(docptr); } -static void write_page(struct mtd_info *mtd, struct nand_chip *nand, +static int write_page(struct mtd_info *mtd, struct nand_chip *nand, const uint8_t *buf, bool use_ecc) { struct docg4_priv *doc = nand->priv; @@ -950,15 +950,17 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *nand, write_nop(docptr); writew(0, docptr + DOC_DATAEND); write_nop(docptr); + + return 0; } -static void docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, +static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, const uint8_t *buf, int oob_required) { return write_page(mtd, nand, buf, false); } -static void docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, +static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, const uint8_t *buf, int oob_required) { return write_page(mtd, nand, buf, true); diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 22bb5e6ddaca..8143873d17a5 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -766,11 +766,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, /* ECC will be calculated automatically, and errors will be detected in * waitfunc. */ -static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, +static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; } static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index c5d7f382759d..1f71b545062a 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -721,11 +721,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, /* ECC will be calculated automatically, and errors will be detected in * waitfunc. */ -static void fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip, +static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { fsl_ifc_write_buf(mtd, buf, mtd->writesize); fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; } static int fsl_ifc_chip_init_tail(struct mtd_info *mtd) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 6574c6f51b8b..d6fa8f4779ce 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -930,7 +930,7 @@ exit_nfc: return ret; } -static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, +static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { struct gpmi_nand_data *this = chip->priv; @@ -972,7 +972,7 @@ static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, &payload_virt, &payload_phys); if (ret) { pr_err("Inadequate payload DMA buffer\n"); - return; + return 0; } ret = send_page_prepare(this, @@ -1002,6 +1002,8 @@ exit_auxiliary: nfc_geo->payload_size, payload_virt, payload_phys); } + + return 0; } /* diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 0a8724e657d7..98ba46ecd5d8 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1911,12 +1911,14 @@ out: * * Not for syndrome calculating ECC controllers, which use a special oob layout. */ -static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, +static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { chip->write_buf(mtd, buf, mtd->writesize); if (oob_required) chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; } /** @@ -1928,7 +1930,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * * We need a special oob layout and handling even when ECC isn't checked. */ -static void nand_write_page_raw_syndrome(struct mtd_info *mtd, +static int nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { @@ -1958,6 +1960,8 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, size = mtd->oobsize - (oob - chip->oob_poi); if (size) chip->write_buf(mtd, oob, size); + + return 0; } /** * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function @@ -1966,7 +1970,7 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB */ -static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, +static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { int i, eccsize = chip->ecc.size; @@ -1983,7 +1987,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; - chip->ecc.write_page_raw(mtd, chip, buf, 1); + return chip->ecc.write_page_raw(mtd, chip, buf, 1); } /** @@ -1993,7 +1997,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, * @buf: data buffer * @oob_required: must write chip->oob_poi to OOB */ -static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, +static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { int i, eccsize = chip->ecc.size; @@ -2013,6 +2017,8 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, chip->oob_poi[eccpos[i]] = ecc_calc[i]; chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; } /** @@ -2025,7 +2031,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * The hw generator calculates the error syndrome automatically. Therefore we * need a special oob layout and handling. */ -static void nand_write_page_syndrome(struct mtd_info *mtd, +static int nand_write_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { @@ -2059,6 +2065,8 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, i = mtd->oobsize - (oob - chip->oob_poi); if (i) chip->write_buf(mtd, oob, i); + + return 0; } /** @@ -2080,9 +2088,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); if (unlikely(raw)) - chip->ecc.write_page_raw(mtd, chip, buf, oob_required); + status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required); else - chip->ecc.write_page(mtd, chip, buf, oob_required); + status = chip->ecc.write_page(mtd, chip, buf, oob_required); + + if (status < 0) + return status; /* * Cached progamming disabled for now. Not sure if it's worth the diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index afc4681f44d7..e8a1ae97a952 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -681,11 +681,13 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, info->state = STATE_IDLE; } -static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, +static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { chip->write_buf(mtd, buf, mtd->writesize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; } static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 2eb15418c227..ed03ed2355de 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -399,11 +399,12 @@ static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, +static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { chip->write_buf(mtd, buf, mtd->writesize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + return 0; } static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index a81ac89a6950..6dce5a7154bb 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -355,13 +355,13 @@ struct nand_ecc_ctrl { uint8_t *calc_ecc); int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page); - void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, + int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required); int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page); int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offs, uint32_t len, uint8_t *buf); - void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, + int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required); int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, int page); From 2944a44da09e46b6db2fd2c3334f242b09e05c43 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Thu, 7 Jun 2012 12:22:15 +0200 Subject: [PATCH 0037/5375] mtd: add LPC32xx SLC NAND driver This patch adds support for the SLC NAND controller inside the LPC32xx SoC. [dwmw2: 21st century pedantry] Signed-off-by: Roland Stigge Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- .../devicetree/bindings/mtd/lpc32xx-slc.txt | 52 + drivers/mtd/nand/Kconfig | 11 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/lpc32xx_slc.c | 1065 +++++++++++++++++ 4 files changed, 1129 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt create mode 100644 drivers/mtd/nand/lpc32xx_slc.c diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt new file mode 100644 index 000000000000..d94edc0fc554 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt @@ -0,0 +1,52 @@ +NXP LPC32xx SoC NAND SLC controller + +Required properties: +- compatible: "nxp,lpc3220-slc" +- reg: Address and size of the controller +- nand-on-flash-bbt: Use bad block table on flash +- gpios: GPIO specification for NAND write protect + +The following required properties are very controller specific. See the LPC32xx +User Manual: +- nxp,wdr-clks: Delay before Ready signal is tested on write (W_RDY) +- nxp,rdr-clks: Delay before Ready signal is tested on read (R_RDY) +(The following values are specified in Hz, to make them independent of actual +clock speed:) +- nxp,wwidth: Write pulse width (W_WIDTH) +- nxp,whold: Write hold time (W_HOLD) +- nxp,wsetup: Write setup time (W_SETUP) +- nxp,rwidth: Read pulse width (R_WIDTH) +- nxp,rhold: Read hold time (R_HOLD) +- nxp,rsetup: Read setup time (R_SETUP) + +Optional subnodes: +- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt + +Example: + + slc: flash@20020000 { + compatible = "nxp,lpc3220-slc"; + reg = <0x20020000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + nxp,wdr-clks = <14>; + nxp,wwidth = <40000000>; + nxp,whold = <100000000>; + nxp,wsetup = <100000000>; + nxp,rdr-clks = <14>; + nxp,rwidth = <40000000>; + nxp,rhold = <66666666>; + nxp,rsetup = <100000000>; + nand-on-flash-bbt; + gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */ + + mtd0@00000000 { + label = "phy3250-boot"; + reg = <0x00000000 0x00064000>; + read-only; + }; + + ... + + }; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 31bb7e5b504a..b28b57ed51bc 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -454,6 +454,17 @@ config MTD_NAND_PXA3xx This enables the driver for the NAND flash device found on PXA3xx processors +config MTD_NAND_SLC_LPC32XX + tristate "NXP LPC32xx SLC Controller" + depends on ARCH_LPC32XX + help + Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell + chips) NAND controller. This is the default for the PHYTEC 3250 + reference board which contains a NAND256R3A2CZA6 chip. + + Please check the actual NAND chip connected and its support + by the SLC NAND controller. + config MTD_NAND_CM_X270 tristate "Support for NAND Flash on CM-X270 modules" depends on MACH_ARMCORE diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index d4b4d8739bd8..d29a893608e7 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o +obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_slc.o obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c new file mode 100644 index 000000000000..1d837b92ac79 --- /dev/null +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -0,0 +1,1065 @@ +/* + * NXP LPC32XX NAND SLC driver + * + * Authors: + * Kevin Wells + * Roland Stigge + * + * Copyright © 2011 NXP Semiconductors + * Copyright © 2012 Roland Stigge + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#define LPC32XX_MODNAME "lpc32xx-nand" + +/********************************************************************** +* SLC NAND controller register offsets +**********************************************************************/ + +#define SLC_DATA(x) (x + 0x000) +#define SLC_ADDR(x) (x + 0x004) +#define SLC_CMD(x) (x + 0x008) +#define SLC_STOP(x) (x + 0x00C) +#define SLC_CTRL(x) (x + 0x010) +#define SLC_CFG(x) (x + 0x014) +#define SLC_STAT(x) (x + 0x018) +#define SLC_INT_STAT(x) (x + 0x01C) +#define SLC_IEN(x) (x + 0x020) +#define SLC_ISR(x) (x + 0x024) +#define SLC_ICR(x) (x + 0x028) +#define SLC_TAC(x) (x + 0x02C) +#define SLC_TC(x) (x + 0x030) +#define SLC_ECC(x) (x + 0x034) +#define SLC_DMA_DATA(x) (x + 0x038) + +/********************************************************************** +* slc_ctrl register definitions +**********************************************************************/ +#define SLCCTRL_SW_RESET (1 << 2) /* Reset the NAND controller bit */ +#define SLCCTRL_ECC_CLEAR (1 << 1) /* Reset ECC bit */ +#define SLCCTRL_DMA_START (1 << 0) /* Start DMA channel bit */ + +/********************************************************************** +* slc_cfg register definitions +**********************************************************************/ +#define SLCCFG_CE_LOW (1 << 5) /* Force CE low bit */ +#define SLCCFG_DMA_ECC (1 << 4) /* Enable DMA ECC bit */ +#define SLCCFG_ECC_EN (1 << 3) /* ECC enable bit */ +#define SLCCFG_DMA_BURST (1 << 2) /* DMA burst bit */ +#define SLCCFG_DMA_DIR (1 << 1) /* DMA write(0)/read(1) bit */ +#define SLCCFG_WIDTH (1 << 0) /* External device width, 0=8bit */ + +/********************************************************************** +* slc_stat register definitions +**********************************************************************/ +#define SLCSTAT_DMA_FIFO (1 << 2) /* DMA FIFO has data bit */ +#define SLCSTAT_SLC_FIFO (1 << 1) /* SLC FIFO has data bit */ +#define SLCSTAT_NAND_READY (1 << 0) /* NAND device is ready bit */ + +/********************************************************************** +* slc_int_stat, slc_ien, slc_isr, and slc_icr register definitions +**********************************************************************/ +#define SLCSTAT_INT_TC (1 << 1) /* Transfer count bit */ +#define SLCSTAT_INT_RDY_EN (1 << 0) /* Ready interrupt bit */ + +/********************************************************************** +* slc_tac register definitions +**********************************************************************/ +/* Clock setting for RDY write sample wait time in 2*n clocks */ +#define SLCTAC_WDR(n) (((n) & 0xF) << 28) +/* Write pulse width in clock cycles, 1 to 16 clocks */ +#define SLCTAC_WWIDTH(n) (((n) & 0xF) << 24) +/* Write hold time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_WHOLD(n) (((n) & 0xF) << 20) +/* Write setup time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_WSETUP(n) (((n) & 0xF) << 16) +/* Clock setting for RDY read sample wait time in 2*n clocks */ +#define SLCTAC_RDR(n) (((n) & 0xF) << 12) +/* Read pulse width in clock cycles, 1 to 16 clocks */ +#define SLCTAC_RWIDTH(n) (((n) & 0xF) << 8) +/* Read hold time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_RHOLD(n) (((n) & 0xF) << 4) +/* Read setup time of control and data signals, 1 to 16 clocks */ +#define SLCTAC_RSETUP(n) (((n) & 0xF) << 0) + +/********************************************************************** +* slc_ecc register definitions +**********************************************************************/ +/* ECC line party fetch macro */ +#define SLCECC_TO_LINEPAR(n) (((n) >> 6) & 0x7FFF) +#define SLCECC_TO_COLPAR(n) ((n) & 0x3F) + +/* + * DMA requires storage space for the DMA local buffer and the hardware ECC + * storage area. The DMA local buffer is only used if DMA mapping fails + * during runtime. + */ +#define LPC32XX_DMA_DATA_SIZE 4096 +#define LPC32XX_ECC_SAVE_SIZE ((4096 / 256) * 4) + +/* Number of bytes used for ECC stored in NAND per 256 bytes */ +#define LPC32XX_SLC_DEV_ECC_BYTES 3 + +/* + * If the NAND base clock frequency can't be fetched, this frequency will be + * used instead as the base. This rate is used to setup the timing registers + * used for NAND accesses. + */ +#define LPC32XX_DEF_BUS_RATE 133250000 + +/* Milliseconds for DMA FIFO timeout (unlikely anyway) */ +#define LPC32XX_DMA_TIMEOUT 100 + +/* + * NAND ECC Layout for small page NAND devices + * Note: For large and huge page devices, the default layouts are used + */ +static struct nand_ecclayout lpc32xx_nand_oob_16 = { + .eccbytes = 6, + .eccpos = {10, 11, 12, 13, 14, 15}, + .oobfree = { + { .offset = 0, .length = 4 }, + { .offset = 6, .length = 4 }, + }, +}; + +static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; +static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; + +/* + * Small page FLASH BBT descriptors, marker at offset 0, version at offset 6 + * Note: Large page devices used the default layout + */ +static struct nand_bbt_descr bbt_smallpage_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 6, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_smallpage_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 6, + .maxblocks = 4, + .pattern = mirror_pattern +}; + +/* + * NAND platform configuration structure + */ +struct lpc32xx_nand_cfg_slc { + uint32_t wdr_clks; + uint32_t wwidth; + uint32_t whold; + uint32_t wsetup; + uint32_t rdr_clks; + uint32_t rwidth; + uint32_t rhold; + uint32_t rsetup; + bool use_bbt; + unsigned wp_gpio; + struct mtd_partition *parts; + unsigned num_parts; +}; + +struct lpc32xx_nand_host { + struct nand_chip nand_chip; + struct clk *clk; + struct mtd_info mtd; + void __iomem *io_base; + struct lpc32xx_nand_cfg_slc *ncfg; + + struct completion comp; + struct dma_chan *dma_chan; + uint32_t dma_buf_len; + struct dma_slave_config dma_slave_config; + struct scatterlist sgl; + + /* + * DMA and CPU addresses of ECC work area and data buffer + */ + uint32_t *ecc_buf; + uint8_t *data_buf; + dma_addr_t io_base_dma; +}; + +static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host) +{ + uint32_t clkrate, tmp; + + /* Reset SLC controller */ + writel(SLCCTRL_SW_RESET, SLC_CTRL(host->io_base)); + udelay(1000); + + /* Basic setup */ + writel(0, SLC_CFG(host->io_base)); + writel(0, SLC_IEN(host->io_base)); + writel((SLCSTAT_INT_TC | SLCSTAT_INT_RDY_EN), + SLC_ICR(host->io_base)); + + /* Get base clock for SLC block */ + clkrate = clk_get_rate(host->clk); + if (clkrate == 0) + clkrate = LPC32XX_DEF_BUS_RATE; + + /* Compute clock setup values */ + tmp = SLCTAC_WDR(host->ncfg->wdr_clks) | + SLCTAC_WWIDTH(1 + (clkrate / host->ncfg->wwidth)) | + SLCTAC_WHOLD(1 + (clkrate / host->ncfg->whold)) | + SLCTAC_WSETUP(1 + (clkrate / host->ncfg->wsetup)) | + SLCTAC_RDR(host->ncfg->rdr_clks) | + SLCTAC_RWIDTH(1 + (clkrate / host->ncfg->rwidth)) | + SLCTAC_RHOLD(1 + (clkrate / host->ncfg->rhold)) | + SLCTAC_RSETUP(1 + (clkrate / host->ncfg->rsetup)); + writel(tmp, SLC_TAC(host->io_base)); +} + +/* + * Hardware specific access to control lines + */ +static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + uint32_t tmp; + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + + /* Does CE state need to be changed? */ + tmp = readl(SLC_CFG(host->io_base)); + if (ctrl & NAND_NCE) + tmp |= SLCCFG_CE_LOW; + else + tmp &= ~SLCCFG_CE_LOW; + writel(tmp, SLC_CFG(host->io_base)); + + if (cmd != NAND_CMD_NONE) { + if (ctrl & NAND_CLE) + writel(cmd, SLC_CMD(host->io_base)); + else + writel(cmd, SLC_ADDR(host->io_base)); + } +} + +/* + * Read the Device Ready pin + */ +static int lpc32xx_nand_device_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + int rdy = 0; + + if ((readl(SLC_STAT(host->io_base)) & SLCSTAT_NAND_READY) != 0) + rdy = 1; + + return rdy; +} + +/* + * Enable NAND write protect + */ +static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) +{ + gpio_set_value(host->ncfg->wp_gpio, 0); +} + +/* + * Disable NAND write protect + */ +static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) +{ + gpio_set_value(host->ncfg->wp_gpio, 1); +} + +/* + * Prepares SLC for transfers with H/W ECC enabled + */ +static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode) +{ + /* Hardware ECC is enabled automatically in hardware as needed */ +} + +/* + * Calculates the ECC for the data + */ +static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd, + const unsigned char *buf, + unsigned char *code) +{ + /* + * ECC is calculated automatically in hardware during syndrome read + * and write operations, so it doesn't need to be calculated here. + */ + return 0; +} + +/* + * Read a single byte from NAND device + */ +static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + + return (uint8_t)readl(SLC_DATA(host->io_base)); +} + +/* + * Simple device read without ECC + */ +static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + + /* Direct device read with no ECC */ + while (len-- > 0) + *buf++ = (uint8_t)readl(SLC_DATA(host->io_base)); +} + +/* + * Simple device write without ECC + */ +static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + + /* Direct device write with no ECC */ + while (len-- > 0) + writel((uint32_t)*buf++, SLC_DATA(host->io_base)); +} + +/* + * Verify data in buffer to data on device + */ +static int lpc32xx_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + int i; + + /* DATA register must be read as 32 bits or it will fail */ + for (i = 0; i < len; i++) { + if (buf[i] != (uint8_t)readl(SLC_DATA(host->io_base))) + return -EFAULT; + } + + return 0; +} + +/* + * Read the OOB data from the device without ECC using FIFO method + */ +static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + +/* + * Write the OOB data to the device without ECC using FIFO method + */ +static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, int page) +{ + int status; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + /* Send command to program the OOB data */ + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + status = chip->waitfunc(mtd, chip); + + return status & NAND_STATUS_FAIL ? -EIO : 0; +} + +/* + * Fills in the ECC fields in the OOB buffer with the hardware generated ECC + */ +static void lpc32xx_slc_ecc_copy(uint8_t *spare, const uint32_t *ecc, int count) +{ + int i; + + for (i = 0; i < (count * 3); i += 3) { + uint32_t ce = ecc[i / 3]; + ce = ~(ce << 2) & 0xFFFFFF; + spare[i + 2] = (uint8_t)(ce & 0xFF); + ce >>= 8; + spare[i + 1] = (uint8_t)(ce & 0xFF); + ce >>= 8; + spare[i] = (uint8_t)(ce & 0xFF); + } +} + +static void lpc32xx_dma_complete_func(void *completion) +{ + complete(completion); +} + +static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma, + void *mem, int len, enum dma_transfer_direction dir) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + struct dma_async_tx_descriptor *desc; + int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + int res; + + host->dma_slave_config.direction = dir; + host->dma_slave_config.src_addr = dma; + host->dma_slave_config.dst_addr = dma; + host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + host->dma_slave_config.src_maxburst = 4; + host->dma_slave_config.dst_maxburst = 4; + /* DMA controller does flow control: */ + host->dma_slave_config.device_fc = false; + if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) { + dev_err(mtd->dev.parent, "Failed to setup DMA slave\n"); + return -ENXIO; + } + + sg_init_one(&host->sgl, mem, len); + + res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + if (res != 1) { + dev_err(mtd->dev.parent, "Failed to map sg list\n"); + return -ENXIO; + } + desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir, + flags); + if (!desc) { + dev_err(mtd->dev.parent, "Failed to prepare slave sg\n"); + goto out1; + } + + init_completion(&host->comp); + desc->callback = lpc32xx_dma_complete_func; + desc->callback_param = &host->comp; + + dmaengine_submit(desc); + dma_async_issue_pending(host->dma_chan); + + wait_for_completion_timeout(&host->comp, msecs_to_jiffies(1000)); + + dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + + return 0; +out1: + dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + return -ENXIO; +} + +/* + * DMA read/write transfers with ECC support + */ +static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages, + int read) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + int i, status = 0; + unsigned long timeout; + int res; + enum dma_transfer_direction dir = + read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; + uint8_t *dma_buf; + bool dma_mapped; + + if ((void *)buf <= high_memory) { + dma_buf = buf; + dma_mapped = true; + } else { + dma_buf = host->data_buf; + dma_mapped = false; + if (!read) + memcpy(host->data_buf, buf, mtd->writesize); + } + + if (read) { + writel(readl(SLC_CFG(host->io_base)) | + SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC | + SLCCFG_DMA_BURST, SLC_CFG(host->io_base)); + } else { + writel((readl(SLC_CFG(host->io_base)) | + SLCCFG_ECC_EN | SLCCFG_DMA_ECC | SLCCFG_DMA_BURST) & + ~SLCCFG_DMA_DIR, + SLC_CFG(host->io_base)); + } + + /* Clear initial ECC */ + writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base)); + + /* Transfer size is data area only */ + writel(mtd->writesize, SLC_TC(host->io_base)); + + /* Start transfer in the NAND controller */ + writel(readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START, + SLC_CTRL(host->io_base)); + + for (i = 0; i < chip->ecc.steps; i++) { + /* Data */ + res = lpc32xx_xmit_dma(mtd, SLC_DMA_DATA(host->io_base_dma), + dma_buf + i * chip->ecc.size, + mtd->writesize / chip->ecc.steps, dir); + if (res) + return res; + + /* Always _read_ ECC */ + if (i == chip->ecc.steps - 1) + break; + if (!read) /* ECC availability delayed on write */ + udelay(10); + res = lpc32xx_xmit_dma(mtd, SLC_ECC(host->io_base_dma), + &host->ecc_buf[i], 4, DMA_DEV_TO_MEM); + if (res) + return res; + } + + /* + * According to NXP, the DMA can be finished here, but the NAND + * controller may still have buffered data. After porting to using the + * dmaengine DMA driver (amba-pl080), the condition (DMA_FIFO empty) + * appears to be always true, according to tests. Keeping the check for + * safety reasons for now. + */ + if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) { + dev_warn(mtd->dev.parent, "FIFO not empty!\n"); + timeout = jiffies + msecs_to_jiffies(LPC32XX_DMA_TIMEOUT); + while ((readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) && + time_before(jiffies, timeout)) + cpu_relax(); + if (!time_before(jiffies, timeout)) { + dev_err(mtd->dev.parent, "FIFO held data too long\n"); + status = -EIO; + } + } + + /* Read last calculated ECC value */ + if (!read) + udelay(10); + host->ecc_buf[chip->ecc.steps - 1] = + readl(SLC_ECC(host->io_base)); + + /* Flush DMA */ + dmaengine_terminate_all(host->dma_chan); + + if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO || + readl(SLC_TC(host->io_base))) { + /* Something is left in the FIFO, something is wrong */ + dev_err(mtd->dev.parent, "DMA FIFO failure\n"); + status = -EIO; + } + + /* Stop DMA & HW ECC */ + writel(readl(SLC_CTRL(host->io_base)) & ~SLCCTRL_DMA_START, + SLC_CTRL(host->io_base)); + writel(readl(SLC_CFG(host->io_base)) & + ~(SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC | + SLCCFG_DMA_BURST), SLC_CFG(host->io_base)); + + if (!dma_mapped && read) + memcpy(buf, host->data_buf, mtd->writesize); + + return status; +} + +/* + * Read the data and OOB data from the device, use ECC correction with the + * data, disable ECC for the OOB data + */ +static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct lpc32xx_nand_host *host = chip->priv; + int stat, i, status; + uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE]; + + /* Issue read command */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + /* Read data and oob, calculate ECC */ + status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1); + + /* Get OOB data */ + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + /* Convert to stored ECC format */ + lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps); + + /* Pointer to ECC data retrieved from NAND spare area */ + oobecc = chip->oob_poi + chip->ecc.layout->eccpos[0]; + + for (i = 0; i < chip->ecc.steps; i++) { + stat = chip->ecc.correct(mtd, buf, oobecc, + &tmpecc[i * chip->ecc.bytes]); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + + buf += chip->ecc.size; + oobecc += chip->ecc.bytes; + } + + return status; +} + +/* + * Read the data and OOB data from the device, no ECC correction with the + * data or OOB data + */ +static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int oob_required, + int page) +{ + /* Issue read command */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + /* Raw reads can just use the FIFO interface */ + chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + +/* + * Write the data and OOB data to the device, use ECC with the data, + * disable ECC for the OOB data + */ +static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, int oob_required) +{ + struct lpc32xx_nand_host *host = chip->priv; + uint8_t *pb = chip->oob_poi + chip->ecc.layout->eccpos[0]; + int error; + + /* Write data, calculate ECC on outbound data */ + error = lpc32xx_xfer(mtd, (uint8_t *)buf, chip->ecc.steps, 0); + if (error) + return error; + + /* + * The calculated ECC needs some manual work done to it before + * committing it to NAND. Process the calculated ECC and place + * the resultant values directly into the OOB buffer. */ + lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps); + + /* Write ECC data to device */ + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + return 0; +} + +/* + * Write the data and OOB data to the device, no ECC correction with the + * data or OOB data + */ +static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, + int oob_required) +{ + /* Raw writes can just use the FIFO interface */ + chip->write_buf(mtd, buf, chip->ecc.size * chip->ecc.steps); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + return 0; +} + +static bool lpc32xx_dma_filter(struct dma_chan *chan, void *param) +{ + struct pl08x_dma_chan *ch = + container_of(chan, struct pl08x_dma_chan, chan); + + /* In LPC32xx's PL080 DMA wiring, the SLC NAND DMA signal is #1 */ + if (ch->cd->min_signal == 1) + return true; + return false; +} + +static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host) +{ + struct mtd_info *mtd = &host->mtd; + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma_chan = dma_request_channel(mask, lpc32xx_dma_filter, NULL); + if (!host->dma_chan) { + dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); + return -EBUSY; + } + + return 0; +} + +#ifdef CONFIG_OF +static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) +{ + struct lpc32xx_nand_cfg_slc *pdata; + struct device_node *np = dev->of_node; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "could not allocate memory for platform data\n"); + return NULL; + } + + of_property_read_u32(np, "nxp,wdr-clks", &pdata->wdr_clks); + of_property_read_u32(np, "nxp,wwidth", &pdata->wwidth); + of_property_read_u32(np, "nxp,whold", &pdata->whold); + of_property_read_u32(np, "nxp,wsetup", &pdata->wsetup); + of_property_read_u32(np, "nxp,rdr-clks", &pdata->rdr_clks); + of_property_read_u32(np, "nxp,rwidth", &pdata->rwidth); + of_property_read_u32(np, "nxp,rhold", &pdata->rhold); + of_property_read_u32(np, "nxp,rsetup", &pdata->rsetup); + + if (!pdata->wdr_clks || !pdata->wwidth || !pdata->whold || + !pdata->wsetup || !pdata->rdr_clks || !pdata->rwidth || + !pdata->rhold || !pdata->rsetup) { + dev_err(dev, "chip parameters not specified correctly\n"); + return NULL; + } + + pdata->use_bbt = of_get_nand_on_flash_bbt(np); + pdata->wp_gpio = of_get_named_gpio_flags(np, "gpios", 0, NULL); + + return pdata; +} +#else +static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + +/* + * Probe for NAND controller + */ +static int __devinit lpc32xx_nand_probe(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *chip; + struct resource *rc; + struct mtd_part_parser_data ppdata = {}; + int res; + + rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (rc == NULL) { + dev_err(&pdev->dev, "No memory resource found for device\n"); + return -EBUSY; + } + + /* Allocate memory for the device structure (and zero it) */ + host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); + if (!host) { + dev_err(&pdev->dev, "failed to allocate device structure\n"); + return -ENOMEM; + } + host->io_base_dma = rc->start; + + host->io_base = devm_request_and_ioremap(&pdev->dev, rc); + if (host->io_base == NULL) { + dev_err(&pdev->dev, "ioremap failed\n"); + return -ENOMEM; + } + + if (pdev->dev.of_node) + host->ncfg = lpc32xx_parse_dt(&pdev->dev); + else + host->ncfg = pdev->dev.platform_data; + if (!host->ncfg) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -ENOENT; + } + if (gpio_request(host->ncfg->wp_gpio, "NAND WP")) { + dev_err(&pdev->dev, "GPIO not available\n"); + return -EBUSY; + } + lpc32xx_wp_disable(host); + + mtd = &host->mtd; + chip = &host->nand_chip; + chip->priv = host; + mtd->priv = chip; + mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; + + /* Get NAND clock */ + host->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(host->clk)) { + dev_err(&pdev->dev, "Clock failure\n"); + res = -ENOENT; + goto err_exit1; + } + clk_enable(host->clk); + + /* Set NAND IO addresses and command/ready functions */ + chip->IO_ADDR_R = SLC_DATA(host->io_base); + chip->IO_ADDR_W = SLC_DATA(host->io_base); + chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; + chip->dev_ready = lpc32xx_nand_device_ready; + chip->chip_delay = 20; /* 20us command delay time */ + + /* Init NAND controller */ + lpc32xx_nand_setup(host); + + platform_set_drvdata(pdev, host); + + /* NAND callbacks for LPC32xx SLC hardware */ + chip->ecc.mode = NAND_ECC_HW_SYNDROME; + chip->read_byte = lpc32xx_nand_read_byte; + chip->read_buf = lpc32xx_nand_read_buf; + chip->write_buf = lpc32xx_nand_write_buf; + chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome; + chip->ecc.read_page = lpc32xx_nand_read_page_syndrome; + chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome; + chip->ecc.write_page = lpc32xx_nand_write_page_syndrome; + chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome; + chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome; + chip->ecc.calculate = lpc32xx_nand_ecc_calculate; + chip->ecc.correct = nand_correct_data; + chip->ecc.strength = 1; + chip->ecc.hwctl = lpc32xx_nand_ecc_enable; + chip->verify_buf = lpc32xx_verify_buf; + + /* bitflip_threshold's default is defined as ecc_strength anyway. + * Unfortunately, it is set only later at add_mtd_device(). Meanwhile + * being 0, it causes bad block table scanning errors in + * nand_scan_tail(), so preparing it here already. */ + mtd->bitflip_threshold = chip->ecc.strength; + + /* + * Allocate a large enough buffer for a single huge page plus + * extra space for the spare area and ECC storage area + */ + host->dma_buf_len = LPC32XX_DMA_DATA_SIZE + LPC32XX_ECC_SAVE_SIZE; + host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len, + GFP_KERNEL); + if (host->data_buf == NULL) { + dev_err(&pdev->dev, "Error allocating memory\n"); + res = -ENOMEM; + goto err_exit2; + } + + res = lpc32xx_nand_dma_setup(host); + if (res) { + res = -EIO; + goto err_exit2; + } + + /* Find NAND device */ + if (nand_scan_ident(mtd, 1, NULL)) { + res = -ENXIO; + goto err_exit3; + } + + /* OOB and ECC CPU and DMA work areas */ + host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE); + + /* + * Small page FLASH has a unique OOB layout, but large and huge + * page FLASH use the standard layout. Small page FLASH uses a + * custom BBT marker layout. + */ + if (mtd->writesize <= 512) + chip->ecc.layout = &lpc32xx_nand_oob_16; + + /* These sizes remain the same regardless of page size */ + chip->ecc.size = 256; + chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES; + chip->ecc.prepad = chip->ecc.postpad = 0; + + /* Avoid extra scan if using BBT, setup BBT support */ + if (host->ncfg->use_bbt) { + chip->options |= NAND_SKIP_BBTSCAN; + chip->bbt_options |= NAND_BBT_USE_FLASH; + + /* + * Use a custom BBT marker setup for small page FLASH that + * won't interfere with the ECC layout. Large and huge page + * FLASH use the standard layout. + */ + if (mtd->writesize <= 512) { + chip->bbt_td = &bbt_smallpage_main_descr; + chip->bbt_md = &bbt_smallpage_mirror_descr; + } + } + + /* + * Fills out all the uninitialized function pointers with the defaults + */ + if (nand_scan_tail(mtd)) { + res = -ENXIO; + goto err_exit3; + } + + /* Standard layout in FLASH for bad block tables */ + if (host->ncfg->use_bbt) { + if (nand_default_bbt(mtd) < 0) + dev_err(&pdev->dev, + "Error initializing default bad block tables\n"); + } + + mtd->name = "nxp_lpc3220_slc"; + ppdata.of_node = pdev->dev.of_node; + res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts, + host->ncfg->num_parts); + if (!res) + return res; + + nand_release(mtd); + +err_exit3: + dma_release_channel(host->dma_chan); +err_exit2: + clk_disable(host->clk); + clk_put(host->clk); + platform_set_drvdata(pdev, NULL); +err_exit1: + lpc32xx_wp_enable(host); + gpio_free(host->ncfg->wp_gpio); + + return res; +} + +/* + * Remove NAND device. + */ +static int __devexit lpc32xx_nand_remove(struct platform_device *pdev) +{ + uint32_t tmp; + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + struct mtd_info *mtd = &host->mtd; + + nand_release(mtd); + dma_release_channel(host->dma_chan); + + /* Force CE high */ + tmp = readl(SLC_CTRL(host->io_base)); + tmp &= ~SLCCFG_CE_LOW; + writel(tmp, SLC_CTRL(host->io_base)); + + clk_disable(host->clk); + clk_put(host->clk); + platform_set_drvdata(pdev, NULL); + lpc32xx_wp_enable(host); + gpio_free(host->ncfg->wp_gpio); + + return 0; +} + +#ifdef CONFIG_PM +static int lpc32xx_nand_resume(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + + /* Re-enable NAND clock */ + clk_enable(host->clk); + + /* Fresh init of NAND controller */ + lpc32xx_nand_setup(host); + + /* Disable write protect */ + lpc32xx_wp_disable(host); + + return 0; +} + +static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) +{ + uint32_t tmp; + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + + /* Force CE high */ + tmp = readl(SLC_CTRL(host->io_base)); + tmp &= ~SLCCFG_CE_LOW; + writel(tmp, SLC_CTRL(host->io_base)); + + /* Enable write protect for safety */ + lpc32xx_wp_enable(host); + + /* Disable clock */ + clk_disable(host->clk); + + return 0; +} + +#else +#define lpc32xx_nand_resume NULL +#define lpc32xx_nand_suspend NULL +#endif + +#if defined(CONFIG_OF) +static const struct of_device_id lpc32xx_nand_match[] = { + { .compatible = "nxp,lpc3220-slc" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); +#endif + +static struct platform_driver lpc32xx_nand_driver = { + .probe = lpc32xx_nand_probe, + .remove = __devexit_p(lpc32xx_nand_remove), + .resume = lpc32xx_nand_resume, + .suspend = lpc32xx_nand_suspend, + .driver = { + .name = LPC32XX_MODNAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lpc32xx_nand_match), + }, +}; + +module_platform_driver(lpc32xx_nand_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Wells "); +MODULE_AUTHOR("Roland Stigge "); +MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX SLC controller"); From a5b2d76d728f135d684827d193cb7fb76d7771a5 Mon Sep 17 00:00:00 2001 From: Chunhe Lan Date: Tue, 19 Jun 2012 10:55:08 +0800 Subject: [PATCH 0038/5375] mtd: m25p80: Add support for Atmel at45db081d Signed-off-by: Chunhe Lan Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index afa77c02aaf7..b4dbcefec3e0 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -633,6 +633,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) }, + { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, + /* EON -- en25xxx */ { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, From 2e61c3a57747150a583b2fb54bddb5dba09aa2cf Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 19 Jun 2012 13:52:42 +0200 Subject: [PATCH 0039/5375] mtd: chips: reorganize Kconfig help on swapping The Kconfig help on "Flash cmd/query data swapping" still mentions LART_ENDIAN_BYTE. That option used to be relevant for setting CONFIG_MTD_CFI_LART_BIT_SWAP. That option and macro got both removed in v2.4.11-pre4. So, although LART endianness sounds intriguing, that part of the help text can be removed. And, while we're touching this choice, move the help text up one level. Currently it's available under the "NO" option, while it's relevant for all three options. Signed-off-by: Paul Bolle Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/chips/Kconfig | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index b1e3c26edd6d..e469b01d40d2 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -43,9 +43,6 @@ choice prompt "Flash cmd/query data swapping" depends on MTD_CFI_ADV_OPTIONS default MTD_CFI_NOSWAP - -config MTD_CFI_NOSWAP - bool "NO" ---help--- This option defines the way in which the CPU attempts to arrange data bits when writing the 'magic' commands to the chips. Saying @@ -55,12 +52,8 @@ config MTD_CFI_NOSWAP Specific arrangements are possible with the BIG_ENDIAN_BYTE and LITTLE_ENDIAN_BYTE, if the bytes are reversed. - If you have a LART, on which the data (and address) lines were - connected in a fashion which ensured that the nets were as short - as possible, resulting in a bit-shuffling which seems utterly - random to the untrained eye, you need the LART_ENDIAN_BYTE option. - - Yes, there really exists something sicker than PDP-endian :) +config MTD_CFI_NOSWAP + bool "NO" config MTD_CFI_BE_BYTE_SWAP bool "BIG_ENDIAN_BYTE" From 9d9a8811622e36611e8eeb2401e4e9805d4727f3 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 20 Jun 2012 16:14:02 -0700 Subject: [PATCH 0040/5375] mtd: nand: change "AMD" manuf. ID to "AMD/Spansion" This manufacturer ID is used under the name Spansion. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_ids.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index e04c675bf609..e3aa2748a6e7 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -174,7 +174,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_STMICRO, "ST Micro"}, {NAND_MFR_HYNIX, "Hynix"}, {NAND_MFR_MICRON, "Micron"}, - {NAND_MFR_AMD, "AMD"}, + {NAND_MFR_AMD, "AMD/Spansion"}, {NAND_MFR_MACRONIX, "Macronix"}, {NAND_MFR_EON, "Eon"}, {0x0, "Unknown"} From 947c9adb4280f495ff4810f52728f7e0cd3f5554 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Fri, 22 Jun 2012 15:29:28 +0200 Subject: [PATCH 0041/5375] mtd: nand: remove stale config options The commit bf4289cba02b8cf770ecd7959ca70839f0dd9d3c removed the use of CONFIG_MTD_NAND_ATMEL_ECC_NONE and CONFIG_MTD_NAND_ATMEL_ECC_HW but the Kconfig file was forgotten. This patch remove those inoperative options. Signed-off-by: Richard Genoud Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index b28b57ed51bc..de6997832dad 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -406,46 +406,6 @@ config MTD_NAND_ATMEL help Enables support for NAND Flash / Smart Media Card interface on Atmel AT91 and AVR32 processors. -choice - prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32" - depends on MTD_NAND_ATMEL - -config MTD_NAND_ATMEL_ECC_HW - bool "Hardware ECC" - depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32 - help - Use hardware ECC instead of software ECC when the chip - supports it. - - The hardware ECC controller is capable of single bit error - correction and 2-bit random detection per page. - - NB : hardware and software ECC schemes are incompatible. - If you switch from one to another, you'll have to erase your - mtd partition. - - If unsure, say Y - -config MTD_NAND_ATMEL_ECC_SOFT - bool "Software ECC" - help - Use software ECC. - - NB : hardware and software ECC schemes are incompatible. - If you switch from one to another, you'll have to erase your - mtd partition. - -config MTD_NAND_ATMEL_ECC_NONE - bool "No ECC (testing only, DANGEROUS)" - depends on DEBUG_KERNEL - help - No ECC will be used. - It's not a good idea and it should be reserved for testing - purpose only. - - If unsure, say N - -endchoice config MTD_NAND_PXA3xx tristate "Support for NAND flash devices on PXA3xx" From 9fd6b37a08d49c5f9b108509fde8d618f74fb7ad Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 22 Jun 2012 16:35:40 -0700 Subject: [PATCH 0042/5375] mtd: nand: rename "no_bbt" descriptors to "no_oob" These descriptors are for BBT's that don't use OOB; the "no_bbt" name doesn't really make sense. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_bbt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index c126469b0645..dff24fa44cd2 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -1274,7 +1274,7 @@ static struct nand_bbt_descr bbt_mirror_descr = { .pattern = mirror_pattern }; -static struct nand_bbt_descr bbt_main_no_bbt_descr = { +static struct nand_bbt_descr bbt_main_no_oob_descr = { .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP | NAND_BBT_NO_OOB, @@ -1284,7 +1284,7 @@ static struct nand_bbt_descr bbt_main_no_bbt_descr = { .pattern = bbt_pattern }; -static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { +static struct nand_bbt_descr bbt_mirror_no_oob_descr = { .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP | NAND_BBT_NO_OOB, @@ -1355,8 +1355,8 @@ int nand_default_bbt(struct mtd_info *mtd) /* Use the default pattern descriptors */ if (!this->bbt_td) { if (this->bbt_options & NAND_BBT_NO_OOB) { - this->bbt_td = &bbt_main_no_bbt_descr; - this->bbt_md = &bbt_mirror_no_bbt_descr; + this->bbt_td = &bbt_main_no_oob_descr; + this->bbt_md = &bbt_mirror_no_oob_descr; } else { this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; From 718894ad94626b72403c21fab5ccdd982147e4c6 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 22 Jun 2012 16:35:43 -0700 Subject: [PATCH 0043/5375] mtd: nand_bbt: refactor check_pattern_no_oob() This function only returns 0 or -1, so make that clear. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_bbt.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index dff24fa44cd2..3df8d92c5e08 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -71,12 +71,9 @@ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) { - int ret; - - ret = memcmp(buf, td->pattern, td->len); - if (!ret) - return ret; - return -1; + if (memcmp(buf, td->pattern, td->len)) + return -1; + return 0; } /** From b8c2d652f4f26a5cc62d93f8a1c934f45e6bf8f5 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 23 Jun 2012 20:40:43 +0200 Subject: [PATCH 0044/5375] mtd: fix bogus inequation Signed-off-by: Marek Vasut Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 4cdb2af7bf44..6cc5a1ac3802 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -97,7 +97,7 @@ config MTD_M25P80 doesn't support the JEDEC ID instruction. config M25PXX_USE_FAST_READ - bool "Use FAST_READ OPCode allowing SPI CLK <= 50MHz" + bool "Use FAST_READ OPCode allowing SPI CLK >= 50MHz" depends on MTD_M25P80 default y help From f3bae3df764737a168fbc51484b277cf0187933e Mon Sep 17 00:00:00 2001 From: Shmulik Ladkani Date: Tue, 26 Jun 2012 17:28:28 +0300 Subject: [PATCH 0045/5375] mtd: Better comment NAND_BBT_NO_OOB Amend the comment to reflect the fact NAND_BBT_NO_OOB refers to the location of the bad block table marker. Signed-off-by: Shmulik Ladkani Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- include/linux/mtd/bbm.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 5d9fcb7645ae..211ff67e8b0d 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -108,7 +108,10 @@ struct nand_bbt_descr { * OOB area. This option is passed to the default bad block table function. */ #define NAND_BBT_USE_FLASH 0x00020000 -/* Do not store flash based bad block table in OOB area; store it in-band */ +/* + * Do not store flash based bad block table marker in the OOB area; store it + * in-band. + */ #define NAND_BBT_NO_OOB 0x00040000 /* * Do not write new bad block markers to OOB; useful, e.g., when ECC covers From fae255253b393d5e4f0d77d5afa103bfc8b47a97 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 26 Jun 2012 15:54:28 -0400 Subject: [PATCH 0046/5375] mtd: delete SBC82xx/SBC8560 MTD mapping support The SBC8260 support was dropped back when we moved from ppc to powerpc. We are now also dropping the support for the EOL SBC8560, so we can also delete this mapping support, as they were the only users of it. Artem: also remove the symbol from the Makefile. Signed-off-by: Paul Gortmaker Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/maps/Kconfig | 12 -- drivers/mtd/maps/Makefile | 1 - drivers/mtd/maps/wr_sbc82xx_flash.c | 174 ---------------------------- 3 files changed, 187 deletions(-) delete mode 100644 drivers/mtd/maps/wr_sbc82xx_flash.c diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 5ba2458e799a..53850f19db8c 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -447,18 +447,6 @@ config MTD_UCLINUX help Map driver to support image based filesystems for uClinux. -config MTD_WRSBC8260 - tristate "Map driver for WindRiver PowerQUICC II MPC82xx board" - depends on (SBC82xx || SBC8560) - select MTD_MAP_BANK_WIDTH_4 - select MTD_MAP_BANK_WIDTH_1 - select MTD_CFI_I1 - select MTD_CFI_I4 - help - Map driver for WindRiver PowerQUICC II MPC82xx board. Drives - all three flash regions on CS0, CS1 and CS6 if they are configured - correctly by the boot loader. - config MTD_DMV182 tristate "Map driver for Dy-4 SVME/DMV-182 board." depends on DMV182 diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 68a9a91d344f..deb43e9a1e7f 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -47,7 +47,6 @@ obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o obj-$(CONFIG_MTD_H720X) += h720x-flash.o obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o obj-$(CONFIG_MTD_IXP2000) += ixp2000.o -obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o obj-$(CONFIG_MTD_DMV182) += dmv182.o obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c deleted file mode 100644 index e7534c82f93a..000000000000 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Map for flash chips on Wind River PowerQUICC II SBC82xx board. - * - * Copyright (C) 2004 Red Hat, Inc. - * - * Author: David Woodhouse - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static struct mtd_info *sbcmtd[3]; - -struct map_info sbc82xx_flash_map[3] = { - {.name = "Boot flash"}, - {.name = "Alternate boot flash"}, - {.name = "User flash"} -}; - -static struct mtd_partition smallflash_parts[] = { - { - .name = "space", - .size = 0x100000, - .offset = 0, - }, { - .name = "bootloader", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, - } -}; - -static struct mtd_partition bigflash_parts[] = { - { - .name = "bootloader", - .size = 0x00100000, - .offset = 0, - }, { - .name = "file system", - .size = 0x01f00000, - .offset = MTDPART_OFS_APPEND, - }, { - .name = "boot config", - .size = 0x00100000, - .offset = MTDPART_OFS_APPEND, - }, { - .name = "space", - .size = 0x01f00000, - .offset = MTDPART_OFS_APPEND, - } -}; - -static const char *part_probes[] __initconst = {"cmdlinepart", "RedBoot", NULL}; - -#define init_sbc82xx_one_flash(map, br, or) \ -do { \ - (map).phys = (br & 1) ? (br & 0xffff8000) : 0; \ - (map).size = (br & 1) ? (~(or & 0xffff8000) + 1) : 0; \ - switch (br & 0x00001800) { \ - case 0x00000000: \ - case 0x00000800: (map).bankwidth = 1; break; \ - case 0x00001000: (map).bankwidth = 2; break; \ - case 0x00001800: (map).bankwidth = 4; break; \ - } \ -} while (0); - -static int __init init_sbc82xx_flash(void) -{ - volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl; - int bigflash; - int i; - -#ifdef CONFIG_SBC8560 - mc = ioremap(0xff700000 + 0x5000, sizeof(memctl_cpm2_t)); -#else - mc = &cpm2_immr->im_memctl; -#endif - - bigflash = 1; - if ((mc->memc_br0 & 0x00001800) == 0x00001800) - bigflash = 0; - - init_sbc82xx_one_flash(sbc82xx_flash_map[0], mc->memc_br0, mc->memc_or0); - init_sbc82xx_one_flash(sbc82xx_flash_map[1], mc->memc_br6, mc->memc_or6); - init_sbc82xx_one_flash(sbc82xx_flash_map[2], mc->memc_br1, mc->memc_or1); - -#ifdef CONFIG_SBC8560 - iounmap((void *) mc); -#endif - - for (i=0; i<3; i++) { - int8_t flashcs[3] = { 0, 6, 1 }; - int nr_parts; - struct mtd_partition *defparts; - - printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d", - sbc82xx_flash_map[i].name, - (sbc82xx_flash_map[i].size >> 20), - flashcs[i]); - if (!sbc82xx_flash_map[i].phys) { - /* We know it can't be at zero. */ - printk("): disabled by bootloader.\n"); - continue; - } - printk(" at %08lx)\n", sbc82xx_flash_map[i].phys); - - sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys, - sbc82xx_flash_map[i].size); - - if (!sbc82xx_flash_map[i].virt) { - printk("Failed to ioremap\n"); - continue; - } - - simple_map_init(&sbc82xx_flash_map[i]); - - sbcmtd[i] = do_map_probe("cfi_probe", &sbc82xx_flash_map[i]); - - if (!sbcmtd[i]) - continue; - - sbcmtd[i]->owner = THIS_MODULE; - - /* No partitioning detected. Use default */ - if (i == 2) { - defparts = NULL; - nr_parts = 0; - } else if (i == bigflash) { - defparts = bigflash_parts; - nr_parts = ARRAY_SIZE(bigflash_parts); - } else { - defparts = smallflash_parts; - nr_parts = ARRAY_SIZE(smallflash_parts); - } - - mtd_device_parse_register(sbcmtd[i], part_probes, NULL, - defparts, nr_parts); - } - return 0; -} - -static void __exit cleanup_sbc82xx_flash(void) -{ - int i; - - for (i=0; i<3; i++) { - if (!sbcmtd[i]) - continue; - - mtd_device_unregister(sbcmtd[i]); - - map_destroy(sbcmtd[i]); - - iounmap((void *)sbc82xx_flash_map[i].virt); - sbc82xx_flash_map[i].virt = 0; - } -} - -module_init(init_sbc82xx_flash); -module_exit(cleanup_sbc82xx_flash); - - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("David Woodhouse "); -MODULE_DESCRIPTION("Flash map driver for WindRiver PowerQUICC II"); From a41b51a1f7c15a1b00f30a3ad2d0373ad51b883d Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 29 Jun 2012 17:47:54 +0800 Subject: [PATCH 0047/5375] mtd: at91: add dt parameters for Atmel PMECC Add DT support for PMECC parameters. Signed-off-by: Hong Xu Signed-off-by: Josh Wu Acked-by: Nicolas Ferre Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- .../devicetree/bindings/mtd/atmel-nand.txt | 40 +++++++++++++- drivers/mtd/nand/atmel_nand.c | 52 ++++++++++++++++++- 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt index a20069502f5a..d555421ea49f 100644 --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt @@ -3,7 +3,9 @@ Atmel NAND flash Required properties: - compatible : "atmel,at91rm9200-nand". - reg : should specify localbus address and size used for the chip, - and if availlable the ECC. + and hardware ECC controller if available. + If the hardware ECC is PMECC, it should contain address and size for + PMECC, PMECC Error Location controller and ROM which has lookup tables. - atmel,nand-addr-offset : offset for the address latch. - atmel,nand-cmd-offset : offset for the command latch. - #address-cells, #size-cells : Must be present if the device has sub-nodes @@ -16,6 +18,15 @@ Optional properties: - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default. Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first", "soft_bch". +- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware. + Only supported by at91sam9x5 or later sam9 product. +- atmel,pmecc-cap : error correct capability for Programmable Multibit ECC + Controller. Supported values are: 2, 4, 8, 12, 24. +- atmel,pmecc-sector-size : sector size for ECC computation. Supported values + are: 512, 1024. +- atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM + for different sector size. First one is for sector size 512, the next is for + sector size 1024. - nand-bus-width : 8 or 16 bus width if not present 8 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false @@ -39,3 +50,30 @@ nand0: nand@40000000,0 { ... }; }; + +/* for PMECC supported chips */ +nand0: nand@40000000 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = < 0x40000000 0x10000000 /* bus addr & size */ + 0xffffe000 0x00000600 /* PMECC addr & size */ + 0xffffe600 0x00000200 /* PMECC ERRLOC addr & size */ + 0x00100000 0x00100000 /* ROM addr & size */ + >; + atmel,nand-addr-offset = <21>; /* ale */ + atmel,nand-cmd-offset = <22>; /* cle */ + nand-on-flash-bbt; + nand-ecc-mode = "hw"; + atmel,has-pmecc; /* enable PMECC */ + atmel,pmecc-cap = <2>; + atmel,pmecc-sector-size = <512>; + atmel,pmecc-lookup-table-offset = <0x8000 0x10000>; + gpios = <&pioD 5 0 /* rdy */ + &pioD 4 0 /* nce */ + 0 /* cd */ + >; + partition@0 { + ... + }; +}; diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 7a41a04beb87..b97ad9f78d39 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -93,6 +93,11 @@ struct atmel_nand_host { struct completion comp; struct dma_chan *dma_chan; + + bool has_pmecc; + u8 pmecc_corr_cap; + u16 pmecc_sector_size; + u32 pmecc_lookup_table_offset; }; static int cpu_has_dma(void) @@ -481,7 +486,8 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) static int __devinit atmel_of_init_port(struct atmel_nand_host *host, struct device_node *np) { - u32 val; + u32 val, table_offset; + u32 offset[2]; int ecc_mode; struct atmel_nand_data *board = &host->board; enum of_gpio_flags flags; @@ -517,6 +523,50 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host, board->enable_pin = of_get_gpio(np, 1); board->det_pin = of_get_gpio(np, 2); + host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc"); + + if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc) + return 0; /* Not using PMECC */ + + /* use PMECC, get correction capability, sector size and lookup + * table offset. + */ + if (of_property_read_u32(np, "atmel,pmecc-cap", &val) != 0) { + dev_err(host->dev, "Cannot decide PMECC Capability\n"); + return -EINVAL; + } else if ((val != 2) && (val != 4) && (val != 8) && (val != 12) && + (val != 24)) { + dev_err(host->dev, + "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n", + val); + return -EINVAL; + } + host->pmecc_corr_cap = (u8)val; + + if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) != 0) { + dev_err(host->dev, "Cannot decide PMECC Sector Size\n"); + return -EINVAL; + } else if ((val != 512) && (val != 1024)) { + dev_err(host->dev, + "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n", + val); + return -EINVAL; + } + host->pmecc_sector_size = (u16)val; + + if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset", + offset, 2) != 0) { + dev_err(host->dev, "Cannot get PMECC lookup table offset\n"); + return -EINVAL; + } + table_offset = host->pmecc_sector_size == 512 ? offset[0] : offset[1]; + + if (!table_offset) { + dev_err(host->dev, "Invalid PMECC lookup table offset\n"); + return -EINVAL; + } + host->pmecc_lookup_table_offset = table_offset; + return 0; } #else From 1c7b874d33b463f7150b1ab4617f000af9b327fd Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 29 Jun 2012 17:47:55 +0800 Subject: [PATCH 0048/5375] mtd: at91: atmel_nand: add Programmable Multibit ECC controller support The Programmable Multibit ECC (PMECC) controller is a programmable binary BCH(Bose, Chaudhuri and Hocquenghem) encoder and decoder. This controller can be used to support both SLC and MLC NAND Flash devices. It supports to generate ECC to correct 2, 4, 8, 12 or 24 bits of error per sector of data. To use PMECC in this driver, the user needs to set the address and size of PMECC, PMECC error location controllers and ROM. And also needs to pass the correction capability, the sector size and ROM lookup table offsets via dt. This driver has been tested on AT91SAM9X5-EK and AT91SAM9N12-EK with JFFS2, YAFFS2, UBIFS and mtd-utils. Signed-off-by: Hong Xu Signed-off-by: Josh Wu Tested-by: Richard Genoud Acked-by: Nicolas Ferre Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/atmel_nand.c | 757 +++++++++++++++++++++++++++++- drivers/mtd/nand/atmel_nand_ecc.h | 114 ++++- 2 files changed, 864 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index b97ad9f78d39..647275524e09 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1,20 +1,22 @@ /* - * Copyright (C) 2003 Rick Bronson + * Copyright © 2003 Rick Bronson * * Derived from drivers/mtd/nand/autcpu12.c - * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) + * Copyright © 2001 Thomas Gleixner (gleixner@autronix.de) * * Derived from drivers/mtd/spia.c - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * Copyright © 2000 Steven J. Hill (sjhill@cotw.com) * * * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 - * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 + * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright © 2007 * * Derived from Das U-Boot source code * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) - * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas + * © Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas * + * Add Programmable Multibit ECC support for various AT91 SoC + * © Copyright 2012 ATMEL, Hong Xu * * 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 @@ -98,8 +100,31 @@ struct atmel_nand_host { u8 pmecc_corr_cap; u16 pmecc_sector_size; u32 pmecc_lookup_table_offset; + + int pmecc_bytes_per_sector; + int pmecc_sector_number; + int pmecc_degree; /* Degree of remainders */ + int pmecc_cw_len; /* Length of codeword */ + + void __iomem *pmerrloc_base; + void __iomem *pmecc_rom_base; + + /* lookup table for alpha_to and index_of */ + void __iomem *pmecc_alpha_to; + void __iomem *pmecc_index_of; + + /* data for pmecc computation */ + int16_t *pmecc_partial_syn; + int16_t *pmecc_si; + int16_t *pmecc_smu; /* Sigma table */ + int16_t *pmecc_lmu; /* polynomal order */ + int *pmecc_mu; + int *pmecc_dmu; + int *pmecc_delta; }; +static struct nand_ecclayout atmel_pmecc_oobinfo; + static int cpu_has_dma(void) { return cpu_is_at91sam9rl() || cpu_is_at91sam9g45(); @@ -292,6 +317,703 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) atmel_write_buf8(mtd, buf, len); } +/* + * Return number of ecc bytes per sector according to sector size and + * correction capability + * + * Following table shows what at91 PMECC supported: + * Correction Capability Sector_512_bytes Sector_1024_bytes + * ===================== ================ ================= + * 2-bits 4-bytes 4-bytes + * 4-bits 7-bytes 7-bytes + * 8-bits 13-bytes 14-bytes + * 12-bits 20-bytes 21-bytes + * 24-bits 39-bytes 42-bytes + */ +static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size) +{ + int m = 12 + sector_size / 512; + return (m * cap + 7) / 8; +} + +static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout, + int oobsize, int ecc_len) +{ + int i; + + layout->eccbytes = ecc_len; + + /* ECC will occupy the last ecc_len bytes continuously */ + for (i = 0; i < ecc_len; i++) + layout->eccpos[i] = oobsize - ecc_len + i; + + layout->oobfree[0].offset = 2; + layout->oobfree[0].length = + oobsize - ecc_len - layout->oobfree[0].offset; +} + +static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) +{ + int table_size; + + table_size = host->pmecc_sector_size == 512 ? + PMECC_LOOKUP_TABLE_SIZE_512 : PMECC_LOOKUP_TABLE_SIZE_1024; + + return host->pmecc_rom_base + host->pmecc_lookup_table_offset + + table_size * sizeof(int16_t); +} + +static void pmecc_data_free(struct atmel_nand_host *host) +{ + kfree(host->pmecc_partial_syn); + kfree(host->pmecc_si); + kfree(host->pmecc_lmu); + kfree(host->pmecc_smu); + kfree(host->pmecc_mu); + kfree(host->pmecc_dmu); + kfree(host->pmecc_delta); +} + +static int __devinit pmecc_data_alloc(struct atmel_nand_host *host) +{ + const int cap = host->pmecc_corr_cap; + + host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t), + GFP_KERNEL); + host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL); + host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL); + host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t), + GFP_KERNEL); + host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL); + host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL); + host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL); + + if (host->pmecc_partial_syn && + host->pmecc_si && + host->pmecc_lmu && + host->pmecc_smu && + host->pmecc_mu && + host->pmecc_dmu && + host->pmecc_delta) + return 0; + + /* error happened */ + pmecc_data_free(host); + return -ENOMEM; +} + +static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + int i; + uint32_t value; + + /* Fill odd syndromes */ + for (i = 0; i < host->pmecc_corr_cap; i++) { + value = pmecc_readl_rem_relaxed(host->ecc, sector, i / 2); + if (i & 1) + value >>= 16; + value &= 0xffff; + host->pmecc_partial_syn[(2 * i) + 1] = (int16_t)value; + } +} + +static void pmecc_substitute(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + int16_t __iomem *alpha_to = host->pmecc_alpha_to; + int16_t __iomem *index_of = host->pmecc_index_of; + int16_t *partial_syn = host->pmecc_partial_syn; + const int cap = host->pmecc_corr_cap; + int16_t *si; + int i, j; + + /* si[] is a table that holds the current syndrome value, + * an element of that table belongs to the field + */ + si = host->pmecc_si; + + memset(&si[1], 0, sizeof(int16_t) * (2 * cap - 1)); + + /* Computation 2t syndromes based on S(x) */ + /* Odd syndromes */ + for (i = 1; i < 2 * cap; i += 2) { + for (j = 0; j < host->pmecc_degree; j++) { + if (partial_syn[i] & ((unsigned short)0x1 << j)) + si[i] = readw_relaxed(alpha_to + i * j) ^ si[i]; + } + } + /* Even syndrome = (Odd syndrome) ** 2 */ + for (i = 2, j = 1; j <= cap; i = ++j << 1) { + if (si[j] == 0) { + si[i] = 0; + } else { + int16_t tmp; + + tmp = readw_relaxed(index_of + si[j]); + tmp = (tmp * 2) % host->pmecc_cw_len; + si[i] = readw_relaxed(alpha_to + tmp); + } + } + + return; +} + +static void pmecc_get_sigma(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + + int16_t *lmu = host->pmecc_lmu; + int16_t *si = host->pmecc_si; + int *mu = host->pmecc_mu; + int *dmu = host->pmecc_dmu; /* Discrepancy */ + int *delta = host->pmecc_delta; /* Delta order */ + int cw_len = host->pmecc_cw_len; + const int16_t cap = host->pmecc_corr_cap; + const int num = 2 * cap + 1; + int16_t __iomem *index_of = host->pmecc_index_of; + int16_t __iomem *alpha_to = host->pmecc_alpha_to; + int i, j, k; + uint32_t dmu_0_count, tmp; + int16_t *smu = host->pmecc_smu; + + /* index of largest delta */ + int ro; + int largest; + int diff; + + dmu_0_count = 0; + + /* First Row */ + + /* Mu */ + mu[0] = -1; + + memset(smu, 0, sizeof(int16_t) * num); + smu[0] = 1; + + /* discrepancy set to 1 */ + dmu[0] = 1; + /* polynom order set to 0 */ + lmu[0] = 0; + delta[0] = (mu[0] * 2 - lmu[0]) >> 1; + + /* Second Row */ + + /* Mu */ + mu[1] = 0; + /* Sigma(x) set to 1 */ + memset(&smu[num], 0, sizeof(int16_t) * num); + smu[num] = 1; + + /* discrepancy set to S1 */ + dmu[1] = si[1]; + + /* polynom order set to 0 */ + lmu[1] = 0; + + delta[1] = (mu[1] * 2 - lmu[1]) >> 1; + + /* Init the Sigma(x) last row */ + memset(&smu[(cap + 1) * num], 0, sizeof(int16_t) * num); + + for (i = 1; i <= cap; i++) { + mu[i + 1] = i << 1; + /* Begin Computing Sigma (Mu+1) and L(mu) */ + /* check if discrepancy is set to 0 */ + if (dmu[i] == 0) { + dmu_0_count++; + + tmp = ((cap - (lmu[i] >> 1) - 1) / 2); + if ((cap - (lmu[i] >> 1) - 1) & 0x1) + tmp += 2; + else + tmp += 1; + + if (dmu_0_count == tmp) { + for (j = 0; j <= (lmu[i] >> 1) + 1; j++) + smu[(cap + 1) * num + j] = + smu[i * num + j]; + + lmu[cap + 1] = lmu[i]; + return; + } + + /* copy polynom */ + for (j = 0; j <= lmu[i] >> 1; j++) + smu[(i + 1) * num + j] = smu[i * num + j]; + + /* copy previous polynom order to the next */ + lmu[i + 1] = lmu[i]; + } else { + ro = 0; + largest = -1; + /* find largest delta with dmu != 0 */ + for (j = 0; j < i; j++) { + if ((dmu[j]) && (delta[j] > largest)) { + largest = delta[j]; + ro = j; + } + } + + /* compute difference */ + diff = (mu[i] - mu[ro]); + + /* Compute degree of the new smu polynomial */ + if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff)) + lmu[i + 1] = lmu[i]; + else + lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2; + + /* Init smu[i+1] with 0 */ + for (k = 0; k < num; k++) + smu[(i + 1) * num + k] = 0; + + /* Compute smu[i+1] */ + for (k = 0; k <= lmu[ro] >> 1; k++) { + int16_t a, b, c; + + if (!(smu[ro * num + k] && dmu[i])) + continue; + a = readw_relaxed(index_of + dmu[i]); + b = readw_relaxed(index_of + dmu[ro]); + c = readw_relaxed(index_of + smu[ro * num + k]); + tmp = a + (cw_len - b) + c; + a = readw_relaxed(alpha_to + tmp % cw_len); + smu[(i + 1) * num + (k + diff)] = a; + } + + for (k = 0; k <= lmu[i] >> 1; k++) + smu[(i + 1) * num + k] ^= smu[i * num + k]; + } + + /* End Computing Sigma (Mu+1) and L(mu) */ + /* In either case compute delta */ + delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1; + + /* Do not compute discrepancy for the last iteration */ + if (i >= cap) + continue; + + for (k = 0; k <= (lmu[i + 1] >> 1); k++) { + tmp = 2 * (i - 1); + if (k == 0) { + dmu[i + 1] = si[tmp + 3]; + } else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) { + int16_t a, b, c; + a = readw_relaxed(index_of + + smu[(i + 1) * num + k]); + b = si[2 * (i - 1) + 3 - k]; + c = readw_relaxed(index_of + b); + tmp = a + c; + tmp %= cw_len; + dmu[i + 1] = readw_relaxed(alpha_to + tmp) ^ + dmu[i + 1]; + } + } + } + + return; +} + +static int pmecc_err_location(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + unsigned long end_time; + const int cap = host->pmecc_corr_cap; + const int num = 2 * cap + 1; + int sector_size = host->pmecc_sector_size; + int err_nbr = 0; /* number of error */ + int roots_nbr; /* number of roots */ + int i; + uint32_t val; + int16_t *smu = host->pmecc_smu; + + pmerrloc_writel(host->pmerrloc_base, ELDIS, PMERRLOC_DISABLE); + + for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) { + pmerrloc_writel_sigma_relaxed(host->pmerrloc_base, i, + smu[(cap + 1) * num + i]); + err_nbr++; + } + + val = (err_nbr - 1) << 16; + if (sector_size == 1024) + val |= 1; + + pmerrloc_writel(host->pmerrloc_base, ELCFG, val); + pmerrloc_writel(host->pmerrloc_base, ELEN, + sector_size * 8 + host->pmecc_degree * cap); + + end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS); + while (!(pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR) + & PMERRLOC_CALC_DONE)) { + if (unlikely(time_after(jiffies, end_time))) { + dev_err(host->dev, "PMECC: Timeout to calculate error location.\n"); + return -1; + } + cpu_relax(); + } + + roots_nbr = (pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR) + & PMERRLOC_ERR_NUM_MASK) >> 8; + /* Number of roots == degree of smu hence <= cap */ + if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1) + return err_nbr - 1; + + /* Number of roots does not match the degree of smu + * unable to correct error */ + return -1; +} + +static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, + int sector_num, int extra_bytes, int err_nbr) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + int i = 0; + int byte_pos, bit_pos, sector_size, pos; + uint32_t tmp; + uint8_t err_byte; + + sector_size = host->pmecc_sector_size; + + while (err_nbr) { + tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_base, i) - 1; + byte_pos = tmp / 8; + bit_pos = tmp % 8; + + if (byte_pos >= (sector_size + extra_bytes)) + BUG(); /* should never happen */ + + if (byte_pos < sector_size) { + err_byte = *(buf + byte_pos); + *(buf + byte_pos) ^= (1 << bit_pos); + + pos = sector_num * host->pmecc_sector_size + byte_pos; + dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", + pos, bit_pos, err_byte, *(buf + byte_pos)); + } else { + /* Bit flip in OOB area */ + tmp = sector_num * host->pmecc_bytes_per_sector + + (byte_pos - sector_size); + err_byte = ecc[tmp]; + ecc[tmp] ^= (1 << bit_pos); + + pos = tmp + nand_chip->ecc.layout->eccpos[0]; + dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", + pos, bit_pos, err_byte, ecc[tmp]); + } + + i++; + err_nbr--; + } + + return; +} + +static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, + u8 *ecc) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + int i, err_nbr, eccbytes; + uint8_t *buf_pos; + + eccbytes = nand_chip->ecc.bytes; + for (i = 0; i < eccbytes; i++) + if (ecc[i] != 0xff) + goto normal_check; + /* Erased page, return OK */ + return 0; + +normal_check: + for (i = 0; i < host->pmecc_sector_number; i++) { + err_nbr = 0; + if (pmecc_stat & 0x1) { + buf_pos = buf + i * host->pmecc_sector_size; + + pmecc_gen_syndrome(mtd, i); + pmecc_substitute(mtd); + pmecc_get_sigma(mtd); + + err_nbr = pmecc_err_location(mtd); + if (err_nbr == -1) { + dev_err(host->dev, "PMECC: Too many errors\n"); + mtd->ecc_stats.failed++; + return -EIO; + } else { + pmecc_correct_data(mtd, buf_pos, ecc, i, + host->pmecc_bytes_per_sector, err_nbr); + mtd->ecc_stats.corrected += err_nbr; + } + } + pmecc_stat >>= 1; + } + + return 0; +} + +static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int oob_required, int page) +{ + struct atmel_nand_host *host = chip->priv; + int eccsize = chip->ecc.size; + uint8_t *oob = chip->oob_poi; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint32_t stat; + unsigned long end_time; + + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); + pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) + & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE); + + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA); + + chip->read_buf(mtd, buf, eccsize); + chip->read_buf(mtd, oob, mtd->oobsize); + + end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS); + while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) { + if (unlikely(time_after(jiffies, end_time))) { + dev_err(host->dev, "PMECC: Timeout to get error status.\n"); + return -EIO; + } + cpu_relax(); + } + + stat = pmecc_readl_relaxed(host->ecc, ISR); + if (stat != 0) + if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0) + return -EIO; + + return 0; +} + +static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, int oob_required) +{ + struct atmel_nand_host *host = chip->priv; + uint32_t *eccpos = chip->ecc.layout->eccpos; + int i, j; + unsigned long end_time; + + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); + + pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) | + PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE); + + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA); + + chip->write_buf(mtd, (u8 *)buf, mtd->writesize); + + end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS); + while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) { + if (unlikely(time_after(jiffies, end_time))) { + dev_err(host->dev, "PMECC: Timeout to get ECC value.\n"); + return -EIO; + } + cpu_relax(); + } + + for (i = 0; i < host->pmecc_sector_number; i++) { + for (j = 0; j < host->pmecc_bytes_per_sector; j++) { + int pos; + + pos = i * host->pmecc_bytes_per_sector + j; + chip->oob_poi[eccpos[pos]] = + pmecc_readb_ecc_relaxed(host->ecc, i, j); + } + } + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; +} + +static void atmel_pmecc_core_init(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + uint32_t val = 0; + struct nand_ecclayout *ecc_layout; + + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); + + switch (host->pmecc_corr_cap) { + case 2: + val = PMECC_CFG_BCH_ERR2; + break; + case 4: + val = PMECC_CFG_BCH_ERR4; + break; + case 8: + val = PMECC_CFG_BCH_ERR8; + break; + case 12: + val = PMECC_CFG_BCH_ERR12; + break; + case 24: + val = PMECC_CFG_BCH_ERR24; + break; + } + + if (host->pmecc_sector_size == 512) + val |= PMECC_CFG_SECTOR512; + else if (host->pmecc_sector_size == 1024) + val |= PMECC_CFG_SECTOR1024; + + switch (host->pmecc_sector_number) { + case 1: + val |= PMECC_CFG_PAGE_1SECTOR; + break; + case 2: + val |= PMECC_CFG_PAGE_2SECTORS; + break; + case 4: + val |= PMECC_CFG_PAGE_4SECTORS; + break; + case 8: + val |= PMECC_CFG_PAGE_8SECTORS; + break; + } + + val |= (PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE + | PMECC_CFG_AUTO_DISABLE); + pmecc_writel(host->ecc, CFG, val); + + ecc_layout = nand_chip->ecc.layout; + pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1); + pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]); + pmecc_writel(host->ecc, EADDR, + ecc_layout->eccpos[ecc_layout->eccbytes - 1]); + /* See datasheet about PMECC Clock Control Register */ + pmecc_writel(host->ecc, CLK, 2); + pmecc_writel(host->ecc, IDR, 0xff); + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE); +} + +static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev, + struct atmel_nand_host *host) +{ + struct mtd_info *mtd = &host->mtd; + struct nand_chip *nand_chip = &host->nand_chip; + struct resource *regs, *regs_pmerr, *regs_rom; + int cap, sector_size, err_no; + + cap = host->pmecc_corr_cap; + sector_size = host->pmecc_sector_size; + dev_info(host->dev, "Initialize PMECC params, cap: %d, sector: %d\n", + cap, sector_size); + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!regs) { + dev_warn(host->dev, + "Can't get I/O resource regs for PMECC controller, rolling back on software ECC\n"); + nand_chip->ecc.mode = NAND_ECC_SOFT; + return 0; + } + + host->ecc = ioremap(regs->start, resource_size(regs)); + if (host->ecc == NULL) { + dev_err(host->dev, "ioremap failed\n"); + err_no = -EIO; + goto err_pmecc_ioremap; + } + + regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2); + regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); + if (regs_pmerr && regs_rom) { + host->pmerrloc_base = ioremap(regs_pmerr->start, + resource_size(regs_pmerr)); + host->pmecc_rom_base = ioremap(regs_rom->start, + resource_size(regs_rom)); + } + + if (!host->pmerrloc_base || !host->pmecc_rom_base) { + dev_err(host->dev, + "Can not get I/O resource for PMECC ERRLOC controller or ROM!\n"); + err_no = -EIO; + goto err_pmloc_ioremap; + } + + /* ECC is calculated for the whole page (1 step) */ + nand_chip->ecc.size = mtd->writesize; + + /* set ECC page size and oob layout */ + switch (mtd->writesize) { + case 2048: + host->pmecc_degree = PMECC_GF_DIMENSION_13; + host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; + host->pmecc_sector_number = mtd->writesize / sector_size; + host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes( + cap, sector_size); + host->pmecc_alpha_to = pmecc_get_alpha_to(host); + host->pmecc_index_of = host->pmecc_rom_base + + host->pmecc_lookup_table_offset; + + nand_chip->ecc.steps = 1; + nand_chip->ecc.strength = cap; + nand_chip->ecc.bytes = host->pmecc_bytes_per_sector * + host->pmecc_sector_number; + if (nand_chip->ecc.bytes > mtd->oobsize - 2) { + dev_err(host->dev, "No room for ECC bytes\n"); + err_no = -EINVAL; + goto err_no_ecc_room; + } + pmecc_config_ecc_layout(&atmel_pmecc_oobinfo, + mtd->oobsize, + nand_chip->ecc.bytes); + nand_chip->ecc.layout = &atmel_pmecc_oobinfo; + break; + case 512: + case 1024: + case 4096: + /* TODO */ + dev_warn(host->dev, + "Unsupported page size for PMECC, use Software ECC\n"); + default: + /* page size not handled by HW ECC */ + /* switching back to soft ECC */ + nand_chip->ecc.mode = NAND_ECC_SOFT; + return 0; + } + + /* Allocate data for PMECC computation */ + err_no = pmecc_data_alloc(host); + if (err_no) { + dev_err(host->dev, + "Cannot allocate memory for PMECC computation!\n"); + goto err_pmecc_data_alloc; + } + + nand_chip->ecc.read_page = atmel_nand_pmecc_read_page; + nand_chip->ecc.write_page = atmel_nand_pmecc_write_page; + + atmel_pmecc_core_init(mtd); + + return 0; + +err_pmecc_data_alloc: +err_no_ecc_room: +err_pmloc_ioremap: + iounmap(host->ecc); + if (host->pmerrloc_base) + iounmap(host->pmerrloc_base); + if (host->pmecc_rom_base) + iounmap(host->pmecc_rom_base); +err_pmecc_ioremap: + return err_no; +} + /* * Calculate HW ECC * @@ -747,7 +1469,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev) } if (nand_chip->ecc.mode == NAND_ECC_HW) { - res = atmel_hw_nand_init_params(pdev, host); + if (host->has_pmecc) + res = atmel_pmecc_nand_init_params(pdev, host); + else + res = atmel_hw_nand_init_params(pdev, host); + if (res != 0) goto err_hw_ecc; } @@ -766,8 +1492,16 @@ static int __init atmel_nand_probe(struct platform_device *pdev) return res; err_scan_tail: + if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) { + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); + pmecc_data_free(host); + } if (host->ecc) iounmap(host->ecc); + if (host->pmerrloc_base) + iounmap(host->pmerrloc_base); + if (host->pmecc_rom_base) + iounmap(host->pmecc_rom_base); err_hw_ecc: err_scan_ident: err_no_card: @@ -793,8 +1527,19 @@ static int __exit atmel_nand_remove(struct platform_device *pdev) atmel_nand_disable(host); + if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) { + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); + pmerrloc_writel(host->pmerrloc_base, ELDIS, + PMERRLOC_DISABLE); + pmecc_data_free(host); + } + if (host->ecc) iounmap(host->ecc); + if (host->pmecc_rom_base) + iounmap(host->pmecc_rom_base); + if (host->pmerrloc_base) + iounmap(host->pmerrloc_base); if (host->dma_chan) dma_release_channel(host->dma_chan); diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h index 578c776e1356..8a1e9a686759 100644 --- a/drivers/mtd/nand/atmel_nand_ecc.h +++ b/drivers/mtd/nand/atmel_nand_ecc.h @@ -3,7 +3,7 @@ * Based on AT91SAM9260 datasheet revision B. * * Copyright (C) 2007 Andrew Victor - * Copyright (C) 2007 Atmel Corporation. + * Copyright (C) 2007 - 2012 Atmel 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 @@ -36,4 +36,116 @@ #define ATMEL_ECC_NPR 0x10 /* NParity register */ #define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ +/* PMECC Register Definitions */ +#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */ +#define PMECC_CFG_BCH_ERR2 (0 << 0) +#define PMECC_CFG_BCH_ERR4 (1 << 0) +#define PMECC_CFG_BCH_ERR8 (2 << 0) +#define PMECC_CFG_BCH_ERR12 (3 << 0) +#define PMECC_CFG_BCH_ERR24 (4 << 0) + +#define PMECC_CFG_SECTOR512 (0 << 4) +#define PMECC_CFG_SECTOR1024 (1 << 4) + +#define PMECC_CFG_PAGE_1SECTOR (0 << 8) +#define PMECC_CFG_PAGE_2SECTORS (1 << 8) +#define PMECC_CFG_PAGE_4SECTORS (2 << 8) +#define PMECC_CFG_PAGE_8SECTORS (3 << 8) + +#define PMECC_CFG_READ_OP (0 << 12) +#define PMECC_CFG_WRITE_OP (1 << 12) + +#define PMECC_CFG_SPARE_ENABLE (1 << 16) +#define PMECC_CFG_SPARE_DISABLE (0 << 16) + +#define PMECC_CFG_AUTO_ENABLE (1 << 20) +#define PMECC_CFG_AUTO_DISABLE (0 << 20) + +#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */ +#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */ +#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */ +#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */ +#define PMECC_CLK_133MHZ (2 << 0) + +#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */ +#define PMECC_CTRL_RST (1 << 0) +#define PMECC_CTRL_DATA (1 << 1) +#define PMECC_CTRL_USER (1 << 2) +#define PMECC_CTRL_ENABLE (1 << 4) +#define PMECC_CTRL_DISABLE (1 << 5) + +#define ATMEL_PMECC_SR 0x018 /* PMECC status register */ +#define PMECC_SR_BUSY (1 << 0) +#define PMECC_SR_ENABLE (1 << 4) + +#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */ +#define PMECC_IER_ENABLE (1 << 0) +#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */ +#define PMECC_IER_DISABLE (1 << 0) +#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */ +#define PMECC_IER_MASK (1 << 0) +#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */ +#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */ +#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */ + +/* PMERRLOC Register Definitions */ +#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */ +#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0) +#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0) +#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16) + +#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */ +#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */ +#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */ +#define PMERRLOC_DISABLE (1 << 0) + +#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */ +#define PMERRLOC_ELSR_BUSY (1 << 0) +#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */ +#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */ +#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */ +#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */ +#define PMERRLOC_ERR_NUM_MASK (0x1f << 8) +#define PMERRLOC_CALC_DONE (1 << 0) +#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */ +#define ATMEL_PMERRLOC_ELx 0x08c /* Error location x */ + +/* Register access macros for PMECC */ +#define pmecc_readl_relaxed(addr, reg) \ + readl_relaxed((addr) + ATMEL_PMECC_##reg) + +#define pmecc_writel(addr, reg, value) \ + writel((value), (addr) + ATMEL_PMECC_##reg) + +#define pmecc_readb_ecc_relaxed(addr, sector, n) \ + readb_relaxed((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n)) + +#define pmecc_readl_rem_relaxed(addr, sector, n) \ + readl_relaxed((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4)) + +#define pmerrloc_readl_relaxed(addr, reg) \ + readl_relaxed((addr) + ATMEL_PMERRLOC_##reg) + +#define pmerrloc_writel(addr, reg, value) \ + writel((value), (addr) + ATMEL_PMERRLOC_##reg) + +#define pmerrloc_writel_sigma_relaxed(addr, n, value) \ + writel_relaxed((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4)) + +#define pmerrloc_readl_sigma_relaxed(addr, n) \ + readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4)) + +#define pmerrloc_readl_el_relaxed(addr, n) \ + readl_relaxed((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4)) + +/* Galois field dimension */ +#define PMECC_GF_DIMENSION_13 13 +#define PMECC_GF_DIMENSION_14 14 + +#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000 +#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000 + +/* Time out value for reading PMECC status register */ +#define PMECC_MAX_TIMEOUT_MS 100 + #endif From df63fe7657d75424f58b41ac079ed8bc4b4676fb Mon Sep 17 00:00:00 2001 From: Alexandre Pereira da Silva Date: Wed, 27 Jun 2012 17:51:13 +0200 Subject: [PATCH 0049/5375] mtd: lpc32xx_slc: Make wp gpio optional This patch supports missing wp gpio. Signed-off-by: Alexandre Pereira da Silva Signed-off-by: Roland Stigge Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/lpc32xx_slc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 1d837b92ac79..1577a9b0d0c2 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -192,7 +192,7 @@ struct lpc32xx_nand_cfg_slc { uint32_t rhold; uint32_t rsetup; bool use_bbt; - unsigned wp_gpio; + int wp_gpio; struct mtd_partition *parts; unsigned num_parts; }; @@ -295,7 +295,8 @@ static int lpc32xx_nand_device_ready(struct mtd_info *mtd) */ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) { - gpio_set_value(host->ncfg->wp_gpio, 0); + if (gpio_is_valid(host->ncfg->wp_gpio)) + gpio_set_value(host->ncfg->wp_gpio, 0); } /* @@ -303,7 +304,8 @@ static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) */ static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) { - gpio_set_value(host->ncfg->wp_gpio, 1); + if (gpio_is_valid(host->ncfg->wp_gpio)) + gpio_set_value(host->ncfg->wp_gpio, 1); } /* @@ -819,7 +821,8 @@ static int __devinit lpc32xx_nand_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Missing platform data\n"); return -ENOENT; } - if (gpio_request(host->ncfg->wp_gpio, "NAND WP")) { + if (gpio_is_valid(host->ncfg->wp_gpio) && + gpio_request(host->ncfg->wp_gpio, "NAND WP")) { dev_err(&pdev->dev, "GPIO not available\n"); return -EBUSY; } From 21535ab39a74b5ec074e2d10b132e866472e86f9 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Wed, 27 Jun 2012 17:51:14 +0200 Subject: [PATCH 0050/5375] mtd: lpc32xx_slc: Use of_get_named_gpio() This patch makes the lpc32xx_slc driver use of_get_named_gpio() instead of of_get_named_gpio_flags() whose flags are discarded anyway. Signed-off-by: Roland Stigge Acked-by: Alexandre Pereira da Silva Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/lpc32xx_slc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 1577a9b0d0c2..116665015269 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -770,7 +770,7 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) } pdata->use_bbt = of_get_nand_on_flash_bbt(np); - pdata->wp_gpio = of_get_named_gpio_flags(np, "gpios", 0, NULL); + pdata->wp_gpio = of_get_named_gpio(np, "gpios", 0); return pdata; } From d5842ab730d368ae2e8925dc00aec0ca132b72ab Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Wed, 27 Jun 2012 17:51:15 +0200 Subject: [PATCH 0051/5375] mtd: lpc32xx_slc: Make probe() return -EPROBE_DEFER if necessary Via of_get_named_gpio(), wp_gpio can become -EPROBE_DEFER which now makes probe() return -EPROBE_DEFER as well to wait until the gpio controller is probed before trying to probe lpc32xx_slc again. Signed-off-by: Roland Stigge Acked-by: Alexandre Pereira da Silva Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/lpc32xx_slc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 116665015269..1719387dd008 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -821,6 +821,8 @@ static int __devinit lpc32xx_nand_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Missing platform data\n"); return -ENOENT; } + if (host->ncfg->wp_gpio == -EPROBE_DEFER) + return -EPROBE_DEFER; if (gpio_is_valid(host->ncfg->wp_gpio) && gpio_request(host->ncfg->wp_gpio, "NAND WP")) { dev_err(&pdev->dev, "GPIO not available\n"); From 70f7cb78ec534301d13af1786b86f13fd96147eb Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Sat, 30 Jun 2012 18:50:38 +0200 Subject: [PATCH 0052/5375] mtd: add LPC32xx MLC NAND driver This patch adds a driver for the MLC NAND controller of the LPC32xx SoC. [dwmw2: 21st century pedantry] Signed-off-by: Roland Stigge Signed-off-by: David Woodhouse --- .../devicetree/bindings/mtd/lpc32xx-mlc.txt | 50 + drivers/mtd/nand/Kconfig | 11 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/lpc32xx_mlc.c | 936 ++++++++++++++++++ 4 files changed, 998 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt create mode 100644 drivers/mtd/nand/lpc32xx_mlc.c diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt new file mode 100644 index 000000000000..d0a37252eb22 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt @@ -0,0 +1,50 @@ +NXP LPC32xx SoC NAND MLC controller + +Required properties: +- compatible: "nxp,lpc3220-mlc" +- reg: Address and size of the controller +- interrupts: The NAND interrupt specification +- gpios: GPIO specification for NAND write protect + +The following required properties are very controller specific. See the LPC32xx +User Manual 7.5.14 MLC NAND Timing Register (the values here are specified in +Hz, to make them independent of actual clock speed and to provide for good +accuracy:) +- nxp,tcea_delay: TCEA_DELAY +- nxp,busy_delay: BUSY_DELAY +- nxp,nand_ta: NAND_TA +- nxp,rd_high: RD_HIGH +- nxp,rd_low: RD_LOW +- nxp,wr_high: WR_HIGH +- nxp,wr_low: WR_LOW + +Optional subnodes: +- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt + +Example: + + mlc: flash@200A8000 { + compatible = "nxp,lpc3220-mlc"; + reg = <0x200A8000 0x11000>; + interrupts = <11 0>; + #address-cells = <1>; + #size-cells = <1>; + + nxp,tcea-delay = <333333333>; + nxp,busy-delay = <10000000>; + nxp,nand-ta = <18181818>; + nxp,rd-high = <31250000>; + nxp,rd-low = <45454545>; + nxp,wr-high = <40000000>; + nxp,wr-low = <83333333>; + gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */ + + mtd0@00000000 { + label = "boot"; + reg = <0x00000000 0x00064000>; + read-only; + }; + + ... + + }; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index de6997832dad..adee4681f98f 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -425,6 +425,17 @@ config MTD_NAND_SLC_LPC32XX Please check the actual NAND chip connected and its support by the SLC NAND controller. +config MTD_NAND_MLC_LPC32XX + tristate "NXP LPC32xx MLC Controller" + depends on ARCH_LPC32XX + help + Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND + controller. This is the default for the WORK92105 controller + board. + + Please check the actual NAND chip connected and its support + by the MLC NAND controller. + config MTD_NAND_CM_X270 tristate "Support for NAND Flash on CM-X270 modules" depends on MACH_ARMCORE diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index d29a893608e7..ddee81811b4a 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o obj-$(CONFIG_MTD_NAND_SLC_LPC32XX) += lpc32xx_slc.o +obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) += lpc32xx_mlc.o obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c new file mode 100644 index 000000000000..260b2c242491 --- /dev/null +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -0,0 +1,936 @@ +/* + * Driver for NAND MLC Controller in LPC32xx + * + * Author: Roland Stigge + * + * Copyright © 2011 WORK Microwave GmbH + * Copyright © 2011, 2012 Roland Stigge + * + * 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. + * + * + * NAND Flash Controller Operation: + * - Read: Auto Decode + * - Write: Auto Encode + * - Tested Page Sizes: 2048, 4096 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "lpc32xx_mlc" + +/********************************************************************** +* MLC NAND controller register offsets +**********************************************************************/ + +#define MLC_BUFF(x) (x + 0x00000) +#define MLC_DATA(x) (x + 0x08000) +#define MLC_CMD(x) (x + 0x10000) +#define MLC_ADDR(x) (x + 0x10004) +#define MLC_ECC_ENC_REG(x) (x + 0x10008) +#define MLC_ECC_DEC_REG(x) (x + 0x1000C) +#define MLC_ECC_AUTO_ENC_REG(x) (x + 0x10010) +#define MLC_ECC_AUTO_DEC_REG(x) (x + 0x10014) +#define MLC_RPR(x) (x + 0x10018) +#define MLC_WPR(x) (x + 0x1001C) +#define MLC_RUBP(x) (x + 0x10020) +#define MLC_ROBP(x) (x + 0x10024) +#define MLC_SW_WP_ADD_LOW(x) (x + 0x10028) +#define MLC_SW_WP_ADD_HIG(x) (x + 0x1002C) +#define MLC_ICR(x) (x + 0x10030) +#define MLC_TIME_REG(x) (x + 0x10034) +#define MLC_IRQ_MR(x) (x + 0x10038) +#define MLC_IRQ_SR(x) (x + 0x1003C) +#define MLC_LOCK_PR(x) (x + 0x10044) +#define MLC_ISR(x) (x + 0x10048) +#define MLC_CEH(x) (x + 0x1004C) + +/********************************************************************** +* MLC_CMD bit definitions +**********************************************************************/ +#define MLCCMD_RESET 0xFF + +/********************************************************************** +* MLC_ICR bit definitions +**********************************************************************/ +#define MLCICR_WPROT (1 << 3) +#define MLCICR_LARGEBLOCK (1 << 2) +#define MLCICR_LONGADDR (1 << 1) +#define MLCICR_16BIT (1 << 0) /* unsupported by LPC32x0! */ + +/********************************************************************** +* MLC_TIME_REG bit definitions +**********************************************************************/ +#define MLCTIMEREG_TCEA_DELAY(n) (((n) & 0x03) << 24) +#define MLCTIMEREG_BUSY_DELAY(n) (((n) & 0x1F) << 19) +#define MLCTIMEREG_NAND_TA(n) (((n) & 0x07) << 16) +#define MLCTIMEREG_RD_HIGH(n) (((n) & 0x0F) << 12) +#define MLCTIMEREG_RD_LOW(n) (((n) & 0x0F) << 8) +#define MLCTIMEREG_WR_HIGH(n) (((n) & 0x0F) << 4) +#define MLCTIMEREG_WR_LOW(n) (((n) & 0x0F) << 0) + +/********************************************************************** +* MLC_IRQ_MR and MLC_IRQ_SR bit definitions +**********************************************************************/ +#define MLCIRQ_NAND_READY (1 << 5) +#define MLCIRQ_CONTROLLER_READY (1 << 4) +#define MLCIRQ_DECODE_FAILURE (1 << 3) +#define MLCIRQ_DECODE_ERROR (1 << 2) +#define MLCIRQ_ECC_READY (1 << 1) +#define MLCIRQ_WRPROT_FAULT (1 << 0) + +/********************************************************************** +* MLC_LOCK_PR bit definitions +**********************************************************************/ +#define MLCLOCKPR_MAGIC 0xA25E + +/********************************************************************** +* MLC_ISR bit definitions +**********************************************************************/ +#define MLCISR_DECODER_FAILURE (1 << 6) +#define MLCISR_ERRORS ((1 << 4) | (1 << 5)) +#define MLCISR_ERRORS_DETECTED (1 << 3) +#define MLCISR_ECC_READY (1 << 2) +#define MLCISR_CONTROLLER_READY (1 << 1) +#define MLCISR_NAND_READY (1 << 0) + +/********************************************************************** +* MLC_CEH bit definitions +**********************************************************************/ +#define MLCCEH_NORMAL (1 << 0) + +struct lpc32xx_nand_cfg_mlc { + uint32_t tcea_delay; + uint32_t busy_delay; + uint32_t nand_ta; + uint32_t rd_high; + uint32_t rd_low; + uint32_t wr_high; + uint32_t wr_low; + int wp_gpio; + struct mtd_partition *parts; + unsigned num_parts; +}; + +static struct nand_ecclayout lpc32xx_nand_oob = { + .eccbytes = 40, + .eccpos = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }, + .oobfree = { + { .offset = 0, + .length = 6, }, + { .offset = 16, + .length = 6, }, + { .offset = 32, + .length = 6, }, + { .offset = 48, + .length = 6, }, + }, +}; + +static struct nand_bbt_descr lpc32xx_nand_bbt = { + .options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB | + NAND_BBT_WRITE, + .pages = { 524224, 0, 0, 0, 0, 0, 0, 0 }, +}; + +static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = { + .options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB | + NAND_BBT_WRITE, + .pages = { 524160, 0, 0, 0, 0, 0, 0, 0 }, +}; + +struct lpc32xx_nand_host { + struct nand_chip nand_chip; + struct clk *clk; + struct mtd_info mtd; + void __iomem *io_base; + int irq; + struct lpc32xx_nand_cfg_mlc *ncfg; + struct completion comp_nand; + struct completion comp_controller; + uint32_t llptr; + /* + * Physical addresses of ECC buffer, DMA data buffers, OOB data buffer + */ + dma_addr_t oob_buf_phy; + /* + * Virtual addresses of ECC buffer, DMA data buffers, OOB data buffer + */ + uint8_t *oob_buf; + /* Physical address of DMA base address */ + dma_addr_t io_base_phy; + + struct completion comp_dma; + struct dma_chan *dma_chan; + struct dma_slave_config dma_slave_config; + struct scatterlist sgl; + uint8_t *dma_buf; + uint8_t *dummy_buf; + int mlcsubpages; /* number of 512bytes-subpages */ +}; + +/* + * Activate/Deactivate DMA Operation: + * + * Using the PL080 DMA Controller for transferring the 512 byte subpages + * instead of doing readl() / writel() in a loop slows it down significantly. + * Measurements via getnstimeofday() upon 512 byte subpage reads reveal: + * + * - readl() of 128 x 32 bits in a loop: ~20us + * - DMA read of 512 bytes (32 bit, 4...128 words bursts): ~60us + * - DMA read of 512 bytes (32 bit, no bursts): ~100us + * + * This applies to the transfer itself. In the DMA case: only the + * wait_for_completion() (DMA setup _not_ included). + * + * Note that the 512 bytes subpage transfer is done directly from/to a + * FIFO/buffer inside the NAND controller. Most of the time (~400-800us for a + * 2048 bytes page) is spent waiting for the NAND IRQ, anyway. (The NAND + * controller transferring data between its internal buffer to/from the NAND + * chip.) + * + * Therefore, using the PL080 DMA is disabled by default, for now. + * + */ +static int use_dma; + +static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host) +{ + uint32_t clkrate, tmp; + + /* Reset MLC controller */ + writel(MLCCMD_RESET, MLC_CMD(host->io_base)); + udelay(1000); + + /* Get base clock for MLC block */ + clkrate = clk_get_rate(host->clk); + if (clkrate == 0) + clkrate = 104000000; + + /* Unlock MLC_ICR + * (among others, will be locked again automatically) */ + writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base)); + + /* Configure MLC Controller: Large Block, 5 Byte Address */ + tmp = MLCICR_LARGEBLOCK | MLCICR_LONGADDR; + writel(tmp, MLC_ICR(host->io_base)); + + /* Unlock MLC_TIME_REG + * (among others, will be locked again automatically) */ + writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base)); + + /* Compute clock setup values, see LPC and NAND manual */ + tmp = 0; + tmp |= MLCTIMEREG_TCEA_DELAY(clkrate / host->ncfg->tcea_delay + 1); + tmp |= MLCTIMEREG_BUSY_DELAY(clkrate / host->ncfg->busy_delay + 1); + tmp |= MLCTIMEREG_NAND_TA(clkrate / host->ncfg->nand_ta + 1); + tmp |= MLCTIMEREG_RD_HIGH(clkrate / host->ncfg->rd_high + 1); + tmp |= MLCTIMEREG_RD_LOW(clkrate / host->ncfg->rd_low); + tmp |= MLCTIMEREG_WR_HIGH(clkrate / host->ncfg->wr_high + 1); + tmp |= MLCTIMEREG_WR_LOW(clkrate / host->ncfg->wr_low); + writel(tmp, MLC_TIME_REG(host->io_base)); + + /* Enable IRQ for CONTROLLER_READY and NAND_READY */ + writeb(MLCIRQ_CONTROLLER_READY | MLCIRQ_NAND_READY, + MLC_IRQ_MR(host->io_base)); + + /* Normal nCE operation: nCE controlled by controller */ + writel(MLCCEH_NORMAL, MLC_CEH(host->io_base)); +} + +/* + * Hardware specific access to control lines + */ +static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *nand_chip = mtd->priv; + struct lpc32xx_nand_host *host = nand_chip->priv; + + if (cmd != NAND_CMD_NONE) { + if (ctrl & NAND_CLE) + writel(cmd, MLC_CMD(host->io_base)); + else + writel(cmd, MLC_ADDR(host->io_base)); + } +} + +/* + * Read Device Ready (NAND device _and_ controller ready) + */ +static int lpc32xx_nand_device_ready(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct lpc32xx_nand_host *host = nand_chip->priv; + + if ((readb(MLC_ISR(host->io_base)) & + (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY)) == + (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY)) + return 1; + + return 0; +} + +static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host) +{ + uint8_t sr; + + /* Clear interrupt flag by reading status */ + sr = readb(MLC_IRQ_SR(host->io_base)); + if (sr & MLCIRQ_NAND_READY) + complete(&host->comp_nand); + if (sr & MLCIRQ_CONTROLLER_READY) + complete(&host->comp_controller); + + return IRQ_HANDLED; +} + +static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip) +{ + struct lpc32xx_nand_host *host = chip->priv; + + if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY) + goto exit; + + wait_for_completion(&host->comp_nand); + + while (!(readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)) { + /* Seems to be delayed sometimes by controller */ + dev_dbg(&mtd->dev, "Warning: NAND not ready.\n"); + cpu_relax(); + } + +exit: + return NAND_STATUS_READY; +} + +static int lpc32xx_waitfunc_controller(struct mtd_info *mtd, + struct nand_chip *chip) +{ + struct lpc32xx_nand_host *host = chip->priv; + + if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY) + goto exit; + + wait_for_completion(&host->comp_controller); + + while (!(readb(MLC_ISR(host->io_base)) & + MLCISR_CONTROLLER_READY)) { + dev_dbg(&mtd->dev, "Warning: Controller not ready.\n"); + cpu_relax(); + } + +exit: + return NAND_STATUS_READY; +} + +static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) +{ + lpc32xx_waitfunc_nand(mtd, chip); + lpc32xx_waitfunc_controller(mtd, chip); + + return NAND_STATUS_READY; +} + +/* + * Enable NAND write protect + */ +static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host) +{ + if (gpio_is_valid(host->ncfg->wp_gpio)) + gpio_set_value(host->ncfg->wp_gpio, 0); +} + +/* + * Disable NAND write protect + */ +static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host) +{ + if (gpio_is_valid(host->ncfg->wp_gpio)) + gpio_set_value(host->ncfg->wp_gpio, 1); +} + +static void lpc32xx_dma_complete_func(void *completion) +{ + complete(completion); +} + +static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len, + enum dma_transfer_direction dir) +{ + struct nand_chip *chip = mtd->priv; + struct lpc32xx_nand_host *host = chip->priv; + struct dma_async_tx_descriptor *desc; + int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + int res; + + sg_init_one(&host->sgl, mem, len); + + res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + if (res != 1) { + dev_err(mtd->dev.parent, "Failed to map sg list\n"); + return -ENXIO; + } + desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir, + flags); + if (!desc) { + dev_err(mtd->dev.parent, "Failed to prepare slave sg\n"); + goto out1; + } + + init_completion(&host->comp_dma); + desc->callback = lpc32xx_dma_complete_func; + desc->callback_param = &host->comp_dma; + + dmaengine_submit(desc); + dma_async_issue_pending(host->dma_chan); + + wait_for_completion_timeout(&host->comp_dma, msecs_to_jiffies(1000)); + + dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + return 0; +out1: + dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1, + DMA_BIDIRECTIONAL); + return -ENXIO; +} + +static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) +{ + struct lpc32xx_nand_host *host = chip->priv; + int i, j; + uint8_t *oobbuf = chip->oob_poi; + uint32_t mlc_isr; + int res; + uint8_t *dma_buf; + bool dma_mapped; + + if ((void *)buf <= high_memory) { + dma_buf = buf; + dma_mapped = true; + } else { + dma_buf = host->dma_buf; + dma_mapped = false; + } + + /* Writing Command and Address */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + /* For all sub-pages */ + for (i = 0; i < host->mlcsubpages; i++) { + /* Start Auto Decode Command */ + writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base)); + + /* Wait for Controller Ready */ + lpc32xx_waitfunc_controller(mtd, chip); + + /* Check ECC Error status */ + mlc_isr = readl(MLC_ISR(host->io_base)); + if (mlc_isr & MLCISR_DECODER_FAILURE) { + mtd->ecc_stats.failed++; + dev_warn(&mtd->dev, "%s: DECODER_FAILURE\n", __func__); + } else if (mlc_isr & MLCISR_ERRORS_DETECTED) { + mtd->ecc_stats.corrected += ((mlc_isr >> 4) & 0x3) + 1; + } + + /* Read 512 + 16 Bytes */ + if (use_dma) { + res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512, + DMA_DEV_TO_MEM); + if (res) + return res; + } else { + for (j = 0; j < (512 >> 2); j++) { + *((uint32_t *)(buf)) = + readl(MLC_BUFF(host->io_base)); + buf += 4; + } + } + for (j = 0; j < (16 >> 2); j++) { + *((uint32_t *)(oobbuf)) = + readl(MLC_BUFF(host->io_base)); + oobbuf += 4; + } + } + + if (use_dma && !dma_mapped) + memcpy(buf, dma_buf, mtd->writesize); + + return 0; +} + +static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, int oob_required) +{ + struct lpc32xx_nand_host *host = chip->priv; + const uint8_t *oobbuf = chip->oob_poi; + uint8_t *dma_buf = (uint8_t *)buf; + int res; + int i, j; + + if (use_dma && (void *)buf >= high_memory) { + dma_buf = host->dma_buf; + memcpy(dma_buf, buf, mtd->writesize); + } + + for (i = 0; i < host->mlcsubpages; i++) { + /* Start Encode */ + writeb(0x00, MLC_ECC_ENC_REG(host->io_base)); + + /* Write 512 + 6 Bytes to Buffer */ + if (use_dma) { + res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512, + DMA_MEM_TO_DEV); + if (res) + return res; + } else { + for (j = 0; j < (512 >> 2); j++) { + writel(*((uint32_t *)(buf)), + MLC_BUFF(host->io_base)); + buf += 4; + } + } + writel(*((uint32_t *)(oobbuf)), MLC_BUFF(host->io_base)); + oobbuf += 4; + writew(*((uint16_t *)(oobbuf)), MLC_BUFF(host->io_base)); + oobbuf += 12; + + /* Auto Encode w/ Bit 8 = 0 (see LPC MLC Controller manual) */ + writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base)); + + /* Wait for Controller Ready */ + lpc32xx_waitfunc_controller(mtd, chip); + } + return 0; +} + +static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page, + int cached, int raw) +{ + int res; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + res = lpc32xx_write_page_lowlevel(mtd, chip, buf, oob_required); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + lpc32xx_waitfunc(mtd, chip); + + return res; +} + +static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + struct lpc32xx_nand_host *host = chip->priv; + + /* Read whole page - necessary with MLC controller! */ + lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page); + + return 0; +} + +static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + /* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */ + return 0; +} + +/* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */ +static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode) +{ + /* Always enabled! */ +} + +static bool lpc32xx_dma_filter(struct dma_chan *chan, void *param) +{ + struct pl08x_dma_chan *ch = + container_of(chan, struct pl08x_dma_chan, chan); + + /* In LPC32xx's PL080 DMA wiring, the MLC NAND DMA signal is #12 */ + if (ch->cd->min_signal == 12) + return true; + return false; +} + +static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host) +{ + struct mtd_info *mtd = &host->mtd; + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma_chan = dma_request_channel(mask, lpc32xx_dma_filter, NULL); + if (!host->dma_chan) { + dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); + return -EBUSY; + } + + /* + * Set direction to a sensible value even if the dmaengine driver + * should ignore it. With the default (DMA_MEM_TO_MEM), the amba-pl08x + * driver criticizes it as "alien transfer direction". + */ + host->dma_slave_config.direction = DMA_DEV_TO_MEM; + host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + host->dma_slave_config.src_maxburst = 128; + host->dma_slave_config.dst_maxburst = 128; + /* DMA controller does flow control: */ + host->dma_slave_config.device_fc = false; + host->dma_slave_config.src_addr = MLC_BUFF(host->io_base_phy); + host->dma_slave_config.dst_addr = MLC_BUFF(host->io_base_phy); + if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) { + dev_err(mtd->dev.parent, "Failed to setup DMA slave\n"); + goto out1; + } + + return 0; +out1: + dma_release_channel(host->dma_chan); + return -ENXIO; +} + +#ifdef CONFIG_OF +static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev) +{ + struct lpc32xx_nand_cfg_mlc *pdata; + struct device_node *np = dev->of_node; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "could not allocate memory for platform data\n"); + return NULL; + } + + of_property_read_u32(np, "nxp,tcea-delay", &pdata->tcea_delay); + of_property_read_u32(np, "nxp,busy-delay", &pdata->busy_delay); + of_property_read_u32(np, "nxp,nand-ta", &pdata->nand_ta); + of_property_read_u32(np, "nxp,rd-high", &pdata->rd_high); + of_property_read_u32(np, "nxp,rd-low", &pdata->rd_low); + of_property_read_u32(np, "nxp,wr-high", &pdata->wr_high); + of_property_read_u32(np, "nxp,wr-low", &pdata->wr_low); + + if (!pdata->tcea_delay || !pdata->busy_delay || !pdata->nand_ta || + !pdata->rd_high || !pdata->rd_low || !pdata->wr_high || + !pdata->wr_low) { + dev_err(dev, "chip parameters not specified correctly\n"); + return NULL; + } + + pdata->wp_gpio = of_get_named_gpio(np, "gpios", 0); + + return pdata; +} +#else +static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + +/* + * Probe for NAND controller + */ +static int __devinit lpc32xx_nand_probe(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *nand_chip; + struct resource *rc; + int res; + struct mtd_part_parser_data ppdata = {}; + + /* Allocate memory for the device structure (and zero it) */ + host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); + if (!host) { + dev_err(&pdev->dev, "failed to allocate device structure.\n"); + return -ENOMEM; + } + + rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (rc == NULL) { + dev_err(&pdev->dev, "No memory resource found for device!\r\n"); + return -ENXIO; + } + + host->io_base = devm_request_and_ioremap(&pdev->dev, rc); + if (host->io_base == NULL) { + dev_err(&pdev->dev, "ioremap failed\n"); + return -EIO; + } + host->io_base_phy = rc->start; + + mtd = &host->mtd; + nand_chip = &host->nand_chip; + if (pdev->dev.of_node) + host->ncfg = lpc32xx_parse_dt(&pdev->dev); + else + host->ncfg = pdev->dev.platform_data; + if (!host->ncfg) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -ENOENT; + } + if (host->ncfg->wp_gpio == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(host->ncfg->wp_gpio) && + gpio_request(host->ncfg->wp_gpio, "NAND WP")) { + dev_err(&pdev->dev, "GPIO not available\n"); + return -EBUSY; + } + lpc32xx_wp_disable(host); + + nand_chip->priv = host; /* link the private data structures */ + mtd->priv = nand_chip; + mtd->owner = THIS_MODULE; + mtd->dev.parent = &pdev->dev; + + /* Get NAND clock */ + host->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(host->clk)) { + dev_err(&pdev->dev, "Clock initialization failure\n"); + res = -ENOENT; + goto err_exit1; + } + clk_enable(host->clk); + + nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; + nand_chip->dev_ready = lpc32xx_nand_device_ready; + nand_chip->chip_delay = 25; /* us */ + nand_chip->IO_ADDR_R = MLC_DATA(host->io_base); + nand_chip->IO_ADDR_W = MLC_DATA(host->io_base); + + /* Init NAND controller */ + lpc32xx_nand_setup(host); + + platform_set_drvdata(pdev, host); + + /* Initialize function pointers */ + nand_chip->ecc.hwctl = lpc32xx_ecc_enable; + nand_chip->ecc.read_page_raw = lpc32xx_read_page; + nand_chip->ecc.read_page = lpc32xx_read_page; + nand_chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel; + nand_chip->ecc.write_page = lpc32xx_write_page_lowlevel; + nand_chip->ecc.write_oob = lpc32xx_write_oob; + nand_chip->ecc.read_oob = lpc32xx_read_oob; + nand_chip->ecc.strength = 4; + nand_chip->write_page = lpc32xx_write_page; + nand_chip->waitfunc = lpc32xx_waitfunc; + + nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; + nand_chip->bbt_td = &lpc32xx_nand_bbt; + nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror; + + /* bitflip_threshold's default is defined as ecc_strength anyway. + * Unfortunately, it is set only later at add_mtd_device(). Meanwhile + * being 0, it causes bad block table scanning errors in + * nand_scan_tail(), so preparing it here. */ + mtd->bitflip_threshold = nand_chip->ecc.strength; + + if (use_dma) { + res = lpc32xx_dma_setup(host); + if (res) { + res = -EIO; + goto err_exit2; + } + } + + /* + * Scan to find existance of the device and + * Get the type of NAND device SMALL block or LARGE block + */ + if (nand_scan_ident(mtd, 1, NULL)) { + res = -ENXIO; + goto err_exit3; + } + + host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL); + if (!host->dma_buf) { + dev_err(&pdev->dev, "Error allocating dma_buf memory\n"); + res = -ENOMEM; + goto err_exit3; + } + + host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL); + if (!host->dummy_buf) { + dev_err(&pdev->dev, "Error allocating dummy_buf memory\n"); + res = -ENOMEM; + goto err_exit3; + } + + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.size = mtd->writesize; + nand_chip->ecc.layout = &lpc32xx_nand_oob; + host->mlcsubpages = mtd->writesize / 512; + + /* initially clear interrupt status */ + readb(MLC_IRQ_SR(host->io_base)); + + init_completion(&host->comp_nand); + init_completion(&host->comp_controller); + + host->irq = platform_get_irq(pdev, 0); + if ((host->irq < 0) || (host->irq >= NR_IRQS)) { + dev_err(&pdev->dev, "failed to get platform irq\n"); + res = -EINVAL; + goto err_exit3; + } + + if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq, + IRQF_TRIGGER_HIGH, DRV_NAME, host)) { + dev_err(&pdev->dev, "Error requesting NAND IRQ\n"); + res = -ENXIO; + goto err_exit3; + } + + /* + * Fills out all the uninitialized function pointers with the defaults + * And scans for a bad block table if appropriate. + */ + if (nand_scan_tail(mtd)) { + res = -ENXIO; + goto err_exit4; + } + + mtd->name = DRV_NAME; + + ppdata.of_node = pdev->dev.of_node; + res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts, + host->ncfg->num_parts); + if (!res) + return res; + + nand_release(mtd); + +err_exit4: + free_irq(host->irq, host); +err_exit3: + if (use_dma) + dma_release_channel(host->dma_chan); +err_exit2: + clk_disable(host->clk); + clk_put(host->clk); + platform_set_drvdata(pdev, NULL); +err_exit1: + lpc32xx_wp_enable(host); + gpio_free(host->ncfg->wp_gpio); + + return res; +} + +/* + * Remove NAND device + */ +static int __devexit lpc32xx_nand_remove(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + struct mtd_info *mtd = &host->mtd; + + nand_release(mtd); + free_irq(host->irq, host); + if (use_dma) + dma_release_channel(host->dma_chan); + + clk_disable(host->clk); + clk_put(host->clk); + platform_set_drvdata(pdev, NULL); + + lpc32xx_wp_enable(host); + gpio_free(host->ncfg->wp_gpio); + + return 0; +} + +#ifdef CONFIG_PM +static int lpc32xx_nand_resume(struct platform_device *pdev) +{ + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + + /* Re-enable NAND clock */ + clk_enable(host->clk); + + /* Fresh init of NAND controller */ + lpc32xx_nand_setup(host); + + /* Disable write protect */ + lpc32xx_wp_disable(host); + + return 0; +} + +static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm) +{ + struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + + /* Enable write protect for safety */ + lpc32xx_wp_enable(host); + + /* Disable clock */ + clk_disable(host->clk); + return 0; +} + +#else +#define lpc32xx_nand_resume NULL +#define lpc32xx_nand_suspend NULL +#endif + +#if defined(CONFIG_OF) +static const struct of_device_id lpc32xx_nand_match[] = { + { .compatible = "nxp,lpc3220-mlc" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); +#endif + +static struct platform_driver lpc32xx_nand_driver = { + .probe = lpc32xx_nand_probe, + .remove = __devexit_p(lpc32xx_nand_remove), + .resume = lpc32xx_nand_resume, + .suspend = lpc32xx_nand_suspend, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lpc32xx_nand_match), + }, +}; + +module_platform_driver(lpc32xx_nand_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Roland Stigge "); +MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX MLC controller"); From 770daa43379690667e6552d68d343111b357341d Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 2 Jul 2012 11:28:45 +0530 Subject: [PATCH 0053/5375] mtd: spear_smi: Move suspend/resume to follow dev_pm_ops Use dev_pm_ops to support PM specific callbacks. Signed-off-by: Viresh Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/spear_smi.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index 67960362681e..cffd36a916d0 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1086,29 +1087,33 @@ static int __devexit spear_smi_remove(struct platform_device *pdev) return 0; } -int spear_smi_suspend(struct platform_device *pdev, pm_message_t state) +#ifdef CONFIG_PM +static int spear_smi_suspend(struct device *dev) { - struct spear_smi *dev = platform_get_drvdata(pdev); + struct spear_smi *sdev = dev_get_drvdata(dev); - if (dev && dev->clk) - clk_disable_unprepare(dev->clk); + if (sdev && sdev->clk) + clk_disable_unprepare(sdev->clk); return 0; } -int spear_smi_resume(struct platform_device *pdev) +static int spear_smi_resume(struct device *dev) { - struct spear_smi *dev = platform_get_drvdata(pdev); + struct spear_smi *sdev = dev_get_drvdata(dev); int ret = -EPERM; - if (dev && dev->clk) - ret = clk_prepare_enable(dev->clk); + if (sdev && sdev->clk) + ret = clk_prepare_enable(sdev->clk); if (!ret) - spear_smi_hw_init(dev); + spear_smi_hw_init(sdev); return ret; } +static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume); +#endif + #ifdef CONFIG_OF static const struct of_device_id spear_smi_id_table[] = { { .compatible = "st,spear600-smi" }, @@ -1123,11 +1128,12 @@ static struct platform_driver spear_smi_driver = { .bus = &platform_bus_type, .owner = THIS_MODULE, .of_match_table = of_match_ptr(spear_smi_id_table), +#ifdef CONFIG_PM + .pm = &spear_smi_pm_ops, +#endif }, .probe = spear_smi_probe, .remove = __devexit_p(spear_smi_remove), - .suspend = spear_smi_suspend, - .resume = spear_smi_resume, }; static int spear_smi_init(void) From 4dc48c37d1ce968b5ade7d1646927199ee536129 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Mon, 2 Jul 2012 11:28:46 +0530 Subject: [PATCH 0054/5375] mtd: spear_smi: clear status register on init It was observed that sometimes smi returned errors while resume from suspend. For safety reasons clear status register for any errors during init. In absence of it smi can return failures during command transmissions. Signed-off-by: Shiraz Hashim Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/spear_smi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index cffd36a916d0..aec941e74e67 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -336,6 +336,9 @@ static void spear_smi_hw_init(struct spear_smi *dev) val = HOLD1 | BANK_EN | DSEL_TIME | (prescale << 8); mutex_lock(&dev->lock); + /* clear all interrupt conditions */ + writel(0, dev->io_base + SMI_SR); + writel(val, dev->io_base + SMI_CR1); mutex_unlock(&dev->lock); } From 2c99b8bfb22342ab0c06e07ee54fa0d5e638e52a Mon Sep 17 00:00:00 2001 From: Vipin Kumar Date: Mon, 2 Jul 2012 11:28:47 +0530 Subject: [PATCH 0055/5375] mtd: spear_smi: handle return value of timeouts properly Handle timouts in general and return value of 'wait_event_interruptible_timeout' in particular, to capture all conditions. 'wait_event_interruptible_timeout' returns either of the following three values :- * 0 - time out occurred. * negative * -ERESTARTSYS - return because of a signal * other - for a real error * positive - time remaining Fix particularly 'ERESTARTSYS' condition which is not properly handled by the smi driver at a couple of places leading to an erroneous situation. Signed-off-by: Antonio BORNEO Signed-off-by: Shiraz Hashim Signed-off-by: Vipin Kumar Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/spear_smi.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index aec941e74e67..b85f183d24c0 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -241,8 +241,8 @@ static int spear_smi_read_sr(struct spear_smi *dev, u32 bank) /* copy dev->status (lower 16 bits) in order to release lock */ if (ret > 0) ret = dev->status & 0xffff; - else - ret = -EIO; + else if (ret == 0) + ret = -ETIMEDOUT; /* restore the ctrl regs state */ writel(ctrlreg1, dev->io_base + SMI_CR1); @@ -270,16 +270,19 @@ static int spear_smi_wait_till_ready(struct spear_smi *dev, u32 bank, finish = jiffies + timeout; do { status = spear_smi_read_sr(dev, bank); - if (status < 0) - continue; /* try till timeout */ - else if (!(status & SR_WIP)) + if (status < 0) { + if (status == -ETIMEDOUT) + continue; /* try till finish */ + return status; + } else if (!(status & SR_WIP)) { return 0; + } cond_resched(); } while (!time_after_eq(jiffies, finish)); dev_err(&dev->pdev->dev, "smi controller is busy, timeout\n"); - return status; + return -EBUSY; } /** @@ -395,11 +398,11 @@ static int spear_smi_write_enable(struct spear_smi *dev, u32 bank) writel(ctrlreg1, dev->io_base + SMI_CR1); writel(0, dev->io_base + SMI_CR2); - if (ret <= 0) { + if (ret == 0) { ret = -EIO; dev_err(&dev->pdev->dev, "smi controller failed on write enable\n"); - } else { + } else if (ret > 0) { /* check whether write mode status is set for required bank */ if (dev->status & (1 << (bank + WM_SHIFT))) ret = 0; @@ -466,10 +469,10 @@ static int spear_smi_erase_sector(struct spear_smi *dev, ret = wait_event_interruptible_timeout(dev->cmd_complete, dev->status & TFF, SMI_CMD_TIMEOUT); - if (ret <= 0) { + if (ret == 0) { ret = -EIO; dev_err(&dev->pdev->dev, "sector erase failed\n"); - } else + } else if (ret > 0) ret = 0; /* success */ /* restore ctrl regs */ From 314a15664e028e6bcafc03495cc492645d9df4df Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Thu, 12 Jul 2012 14:22:56 +0200 Subject: [PATCH 0056/5375] mtd: lpc32xx_slc: Adjust to pl08x DMA interface changes This patch adjusts the LPC32xx SLC NAND driver to the new pl08x DMA interface, fixing the compile error resulting from changed pl08x structures. Signed-off-by: Roland Stigge Acked-By: Alexandre Pereira da Silva Signed-off-by: David Woodhouse --- drivers/mtd/nand/lpc32xx_slc.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 1719387dd008..c8c1d06b35ab 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -714,17 +714,6 @@ static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd, return 0; } -static bool lpc32xx_dma_filter(struct dma_chan *chan, void *param) -{ - struct pl08x_dma_chan *ch = - container_of(chan, struct pl08x_dma_chan, chan); - - /* In LPC32xx's PL080 DMA wiring, the SLC NAND DMA signal is #1 */ - if (ch->cd->min_signal == 1) - return true; - return false; -} - static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host) { struct mtd_info *mtd = &host->mtd; @@ -732,7 +721,7 @@ static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - host->dma_chan = dma_request_channel(mask, lpc32xx_dma_filter, NULL); + host->dma_chan = dma_request_channel(mask, pl08x_filter_id, "nand-slc"); if (!host->dma_chan) { dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); return -EBUSY; From 79f9df7c0027742ae7c913367b6d88dec242fa63 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Thu, 12 Jul 2012 14:22:57 +0200 Subject: [PATCH 0057/5375] mtd: lpc32xx_mlc: Adjust to pl08x DMA interface changes This patch adjusts the LPC32xx MLC NAND driver to the new pl08x DMA interface, fixing the compile error resulting from changed pl08x structures. Signed-off-by: Roland Stigge Acked-By: Alexandre Pereira da Silva Signed-off-by: David Woodhouse --- drivers/mtd/nand/lpc32xx_mlc.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 260b2c242491..1cf35932a4d5 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -576,17 +576,6 @@ static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode) /* Always enabled! */ } -static bool lpc32xx_dma_filter(struct dma_chan *chan, void *param) -{ - struct pl08x_dma_chan *ch = - container_of(chan, struct pl08x_dma_chan, chan); - - /* In LPC32xx's PL080 DMA wiring, the MLC NAND DMA signal is #12 */ - if (ch->cd->min_signal == 12) - return true; - return false; -} - static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host) { struct mtd_info *mtd = &host->mtd; @@ -594,7 +583,7 @@ static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - host->dma_chan = dma_request_channel(mask, lpc32xx_dma_filter, NULL); + host->dma_chan = dma_request_channel(mask, pl08x_filter_id, "nand-mlc"); if (!host->dma_chan) { dev_err(mtd->dev.parent, "Failed to request DMA channel\n"); return -EBUSY; From 4d363b5518dd6298b39653919828eb7d9061488c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 2 Jul 2012 19:00:19 -0300 Subject: [PATCH 0058/5375] mtd: mxc_nand: Select the driver via ARCH_MXC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With device tree support in place, we should not use IMX_HAVE_PLATFORM_MXC_NAND as a dependency for selecting the mxc_nand driver. Use ARCH_MXC symbol instead, so that the driver can be even selected when a single device-tree machine is selected. Signed-off-by: Fabio Estevam Acked-by: Uwe Kleine-König Acked-by: Sascha Hauer Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index adee4681f98f..f4e81a7742b8 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -532,7 +532,7 @@ config MTD_NAND_MPC5121_NFC config MTD_NAND_MXC tristate "MXC NAND support" - depends on IMX_HAVE_PLATFORM_MXC_NAND + depends on ARCH_MXC help This enables the driver for the NAND flash controller on the MXC processors. From 420962884379bd434a7f643d0936281b2ab4b30c Mon Sep 17 00:00:00 2001 From: Gerlando Falauto Date: Tue, 3 Jul 2012 09:09:47 +0200 Subject: [PATCH 0059/5375] mtd: cfi_cmdset_0002: Micron M29EW bugfixes as per TN-13-07 Fix the following issues with Micron's (formerly Numonyx) M29EW NOR flash chips, as documented on TN-13-07: - Correcting Erase Suspend Hang Ups (page 20) - Resolving the Delay After Resume Issue (page 22) Signed-off-by: Gerlando Falauto Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0002.c | 67 +++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 22d0493a026f..5ff5c4a16943 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -431,6 +431,68 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi, } } +static int is_m29ew(struct cfi_private *cfi) +{ + if (cfi->mfr == CFI_MFR_INTEL && + ((cfi->device_type == CFI_DEVICETYPE_X8 && (cfi->id & 0xff) == 0x7e) || + (cfi->device_type == CFI_DEVICETYPE_X16 && cfi->id == 0x227e))) + return 1; + return 0; +} + +/* + * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 20: + * Some revisions of the M29EW suffer from erase suspend hang ups. In + * particular, it can occur when the sequence + * Erase Confirm -> Suspend -> Program -> Resume + * causes a lockup due to internal timing issues. The consequence is that the + * erase cannot be resumed without inserting a dummy command after programming + * and prior to resuming. [...] The work-around is to issue a dummy write cycle + * that writes an F0 command code before the RESUME command. + */ +static void cfi_fixup_m29ew_erase_suspend(struct map_info *map, + unsigned long adr) +{ + struct cfi_private *cfi = map->fldrv_priv; + /* before resume, insert a dummy 0xF0 cycle for Micron M29EW devices */ + if (is_m29ew(cfi)) + map_write(map, CMD(0xF0), adr); +} + +/* + * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 22: + * + * Some revisions of the M29EW (for example, A1 and A2 step revisions) + * are affected by a problem that could cause a hang up when an ERASE SUSPEND + * command is issued after an ERASE RESUME operation without waiting for a + * minimum delay. The result is that once the ERASE seems to be completed + * (no bits are toggling), the contents of the Flash memory block on which + * the erase was ongoing could be inconsistent with the expected values + * (typically, the array value is stuck to the 0xC0, 0xC4, 0x80, or 0x84 + * values), causing a consequent failure of the ERASE operation. + * The occurrence of this issue could be high, especially when file system + * operations on the Flash are intensive. As a result, it is recommended + * that a patch be applied. Intensive file system operations can cause many + * calls to the garbage routine to free Flash space (also by erasing physical + * Flash blocks) and as a result, many consecutive SUSPEND and RESUME + * commands can occur. The problem disappears when a delay is inserted after + * the RESUME command by using the udelay() function available in Linux. + * The DELAY value must be tuned based on the customer's platform. + * The maximum value that fixes the problem in all cases is 500us. + * But, in our experience, a delay of 30 µs to 50 µs is sufficient + * in most cases. + * We have chosen 500µs because this latency is acceptable. + */ +static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi) +{ + /* + * Resolving the Delay After Resume Issue see Micron TN-13-07 + * Worst case delay must be 500µs but 30-50µs should be ok as well + */ + if (is_m29ew(cfi)) + cfi_udelay(500); +} + struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; @@ -776,7 +838,10 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad switch(chip->oldstate) { case FL_ERASING: + cfi_fixup_m29ew_erase_suspend(map, + chip->in_progress_block_addr); map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); + cfi_fixup_m29ew_delay_after_resume(cfi); chip->oldstate = FL_READY; chip->state = FL_ERASING; break; @@ -916,6 +981,8 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, /* Disallow XIP again */ local_irq_disable(); + /* Correct Erase Suspend Hangups for M29EW */ + cfi_fixup_m29ew_erase_suspend(map, adr); /* Resume the write or erase operation */ map_write(map, cfi->sector_erase_cmd, adr); chip->state = oldstate; From 11041ae65abfeaea959060ad17d167732f604ecf Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Tue, 3 Jul 2012 16:44:14 +0800 Subject: [PATCH 0060/5375] mtd: use MTD_OPS_PLACE_OOB macro consistently Use the MTD_OPS_PLACE_OOB to replace the hard code "0". Make the code more readable. Signed-off-by: Huang Shijie Acked-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 98ba46ecd5d8..ead301a455ee 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1625,7 +1625,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, ops.len = len; ops.datbuf = buf; ops.oobbuf = NULL; - ops.mode = 0; + ops.mode = MTD_OPS_PLACE_OOB; ret = nand_do_read_ops(mtd, from, &ops); *retlen = ops.retlen; nand_release_device(mtd); @@ -2331,7 +2331,7 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, ops.len = len; ops.datbuf = (uint8_t *)buf; ops.oobbuf = NULL; - ops.mode = 0; + ops.mode = MTD_OPS_PLACE_OOB; ret = nand_do_write_ops(mtd, to, &ops); @@ -2360,7 +2360,7 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, ops.len = len; ops.datbuf = (uint8_t *)buf; ops.oobbuf = NULL; - ops.mode = 0; + ops.mode = MTD_OPS_PLACE_OOB; ret = nand_do_write_ops(mtd, to, &ops); *retlen = ops.retlen; nand_release_device(mtd); From 44ed0ffdbc0e7ce2bd8954b79626df45d679d189 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Tue, 3 Jul 2012 16:44:15 +0800 Subject: [PATCH 0061/5375] mtd: fix typo in comment fix the comment for nand_bbt.c Signed-off-by: Huang Shijie Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_bbt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 3df8d92c5e08..2d1d2fa9dfc5 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -22,7 +22,7 @@ * BBT on flash. If a BBT is found then the contents are read and the memory * based BBT is created. If a mirrored BBT is selected then the mirror is * searched too and the versions are compared. If the mirror has a greater - * version number than the mirror BBT is used to build the memory based BBT. + * version number, then the mirror BBT is used to build the memory based BBT. * If the tables are not versioned, then we "or" the bad block information. * If one of the BBTs is out of date or does not exist it is (re)created. * If no BBT exists at all then the device is scanned for factory marked From c50c69402ac24641da38c146796c199387b97f8d Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Tue, 3 Jul 2012 16:24:32 +0800 Subject: [PATCH 0062/5375] mtd: gpmi: add on-flash BBT support for gpmi nand add the on flash bbt support for gpmi nand driver. Signed-off-by: Huang Shijie Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- Documentation/devicetree/bindings/mtd/gpmi-nand.txt | 4 ++++ drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt index 1a5bbd346d22..3fb3f9015365 100644 --- a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt @@ -12,6 +12,10 @@ Required properties: - interrupt-names : The interrupt names "gpmi-dma", "bch"; - fsl,gpmi-dma-channel : Should contain the dma channel it uses. +Optional properties: + - nand-on-flash-bbt: boolean to enable on flash bbt option if not + present false + The device tree may optionally contain sub-nodes describing partitions of the address space. See partition.txt for more detail. diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index d6fa8f4779ce..5d9796acc49a 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "gpmi-nand.h" /* add our owner bbt descriptor */ @@ -1502,6 +1503,8 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) chip->ecc.size = 1; chip->ecc.strength = 8; chip->ecc.layout = &gpmi_hw_ecclayout; + if (of_get_nand_on_flash_bbt(this->dev->of_node)) + chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; /* Allocate a temporary DMA buffer for reading ID in the nand_scan() */ this->bch_geometry.payload_size = 1024; From e0dd89c56edc9274c513dbd2ba6dc8229aeeaa44 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Tue, 3 Jul 2012 16:24:33 +0800 Subject: [PATCH 0063/5375] mtd: gpmi: update the bitflip_threshold The origin code misses to update the bitflip_threshold when we have already get the right ecc_strength. The patch fixes it. Signed-off-by: Huang Shijie Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 5d9796acc49a..9da9ee88a824 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1442,6 +1442,7 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) /* Adjust the ECC strength according to the chip. */ this->nand.ecc.strength = this->bch_geometry.ecc_strength; this->mtd.ecc_strength = this->bch_geometry.ecc_strength; + this->mtd.bitflip_threshold = this->bch_geometry.ecc_strength; /* NAND boot init, depends on the gpmi_set_geometry(). */ return nand_boot_init(this); From 4800399e335658aae632f587f6759a860f584804 Mon Sep 17 00:00:00 2001 From: Knut Wohlrab Date: Tue, 17 Jul 2012 15:45:53 +0200 Subject: [PATCH 0064/5375] mtd: m25p80: Add support for serial flash STM/Micron N25Q032 Signed-off-by: Knut Wohlrab Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index b4dbcefec3e0..525734573822 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -702,6 +702,7 @@ static const struct spi_device_id m25p_ids[] = { { "m25p32", INFO(0x202016, 0, 64 * 1024, 64, 0) }, { "m25p64", INFO(0x202017, 0, 64 * 1024, 128, 0) }, { "m25p128", INFO(0x202018, 0, 256 * 1024, 64, 0) }, + { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) }, { "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2, 0) }, { "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4, 0) }, From 9594a4986192f99c01a7c0a1779b5ac0eff8e208 Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Mon, 2 Jul 2012 17:53:25 +0900 Subject: [PATCH 0065/5375] KVM: MMU: Use __gfn_to_rmap() to clean up kvm_handle_hva() We can treat every level uniformly. Signed-off-by: Takuya Yoshikawa Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/mmu.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 28c8fbcc6763..2beb95b57cbe 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1281,14 +1281,14 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; gfn_t gfn = memslot->base_gfn + gfn_offset; - ret = handler(kvm, &memslot->rmap[gfn_offset], data); + ret = 0; - for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) { - struct kvm_lpage_info *linfo; + for (j = PT_PAGE_TABLE_LEVEL; + j < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++j) { + unsigned long *rmapp; - linfo = lpage_info_slot(gfn, memslot, - PT_DIRECTORY_LEVEL + j); - ret |= handler(kvm, &linfo->rmap_pde, data); + rmapp = __gfn_to_rmap(gfn, j, memslot); + ret |= handler(kvm, rmapp, data); } trace_kvm_age_page(hva, memslot, ret); retval |= ret; From d19a748b1c42b133e9263e9023c1d162efa6f4ad Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Mon, 2 Jul 2012 17:54:30 +0900 Subject: [PATCH 0066/5375] KVM: Introduce hva_to_gfn_memslot() for kvm_handle_hva() This restricts hva handling in mmu code and makes it easier to extend kvm_handle_hva() so that it can treat a range of addresses later in this patch series. Signed-off-by: Takuya Yoshikawa Cc: Alexander Graf Cc: Paul Mackerras Signed-off-by: Marcelo Tosatti --- arch/powerpc/kvm/book3s_64_mmu_hv.c | 6 +++--- arch/x86/kvm/mmu.c | 3 +-- include/linux/kvm_host.h | 8 ++++++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index d03eb6f7b058..37037553fe60 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -772,10 +772,10 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, end = start + (memslot->npages << PAGE_SHIFT); if (hva >= start && hva < end) { - gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; + gfn_t gfn = hva_to_gfn_memslot(hva, memslot); + gfn_t gfn_offset = gfn - memslot->base_gfn; - ret = handler(kvm, &memslot->rmap[gfn_offset], - memslot->base_gfn + gfn_offset); + ret = handler(kvm, &memslot->rmap[gfn_offset], gfn); retval |= ret; } } diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 2beb95b57cbe..170a632d9d34 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1278,8 +1278,7 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, end = start + (memslot->npages << PAGE_SHIFT); if (hva >= start && hva < end) { - gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; - gfn_t gfn = memslot->base_gfn + gfn_offset; + gfn_t gfn = hva_to_gfn_memslot(hva, memslot); ret = 0; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index e3c86f8c86c9..6f6c18a03c50 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -740,6 +740,14 @@ static inline gfn_t gfn_to_index(gfn_t gfn, gfn_t base_gfn, int level) (base_gfn >> KVM_HPAGE_GFN_SHIFT(level)); } +static inline gfn_t +hva_to_gfn_memslot(unsigned long hva, struct kvm_memory_slot *slot) +{ + gfn_t gfn_offset = (hva - slot->userspace_addr) >> PAGE_SHIFT; + + return slot->base_gfn + gfn_offset; +} + static inline unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn) { From 84504ef38673fa021b3d8f3da2b79cf878b33315 Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Mon, 2 Jul 2012 17:55:48 +0900 Subject: [PATCH 0067/5375] KVM: MMU: Make kvm_handle_hva() handle range of addresses When guest's memory is backed by THP pages, MMU notifier needs to call kvm_unmap_hva(), which in turn leads to kvm_handle_hva(), in a loop to invalidate a range of pages which constitute one huge page: for each page for each memslot if page is in memslot unmap using rmap This means although every page in that range is expected to be found in the same memslot, we are forced to check unrelated memslots many times. If the guest has more memslots, the situation will become worse. Furthermore, if the range does not include any pages in the guest's memory, the loop over the pages will just consume extra time. This patch, together with the following patches, solves this problem by introducing kvm_handle_hva_range() which makes the loop look like this: for each memslot for each page in memslot unmap using rmap In this new processing, the actual work is converted to a loop over rmap which is much more cache friendly than before. Signed-off-by: Takuya Yoshikawa Cc: Alexander Graf Cc: Paul Mackerras Signed-off-by: Marcelo Tosatti --- arch/powerpc/kvm/book3s_64_mmu_hv.c | 36 +++++++++++++++++++------ arch/x86/kvm/mmu.c | 42 ++++++++++++++++++++++------- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 37037553fe60..1a470bc28763 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -756,9 +756,12 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, goto out_put; } -static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, - int (*handler)(struct kvm *kvm, unsigned long *rmapp, - unsigned long gfn)) +static int kvm_handle_hva_range(struct kvm *kvm, + unsigned long start, + unsigned long end, + int (*handler)(struct kvm *kvm, + unsigned long *rmapp, + unsigned long gfn)) { int ret; int retval = 0; @@ -767,12 +770,22 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, slots = kvm_memslots(kvm); kvm_for_each_memslot(memslot, slots) { - unsigned long start = memslot->userspace_addr; - unsigned long end; + unsigned long hva_start, hva_end; + gfn_t gfn, gfn_end; - end = start + (memslot->npages << PAGE_SHIFT); - if (hva >= start && hva < end) { - gfn_t gfn = hva_to_gfn_memslot(hva, memslot); + hva_start = max(start, memslot->userspace_addr); + hva_end = min(end, memslot->userspace_addr + + (memslot->npages << PAGE_SHIFT)); + if (hva_start >= hva_end) + continue; + /* + * {gfn(page) | page intersects with [hva_start, hva_end)} = + * {gfn, gfn+1, ..., gfn_end-1}. + */ + gfn = hva_to_gfn_memslot(hva_start, memslot); + gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot); + + for (; gfn < gfn_end; ++gfn) { gfn_t gfn_offset = gfn - memslot->base_gfn; ret = handler(kvm, &memslot->rmap[gfn_offset], gfn); @@ -783,6 +796,13 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, return retval; } +static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, + int (*handler)(struct kvm *kvm, unsigned long *rmapp, + unsigned long gfn)) +{ + return kvm_handle_hva_range(kvm, hva, hva + 1, handler); +} + static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, unsigned long gfn) { diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 170a632d9d34..7235b0c9587d 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1259,10 +1259,13 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, return 0; } -static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, - unsigned long data, - int (*handler)(struct kvm *kvm, unsigned long *rmapp, - unsigned long data)) +static int kvm_handle_hva_range(struct kvm *kvm, + unsigned long start, + unsigned long end, + unsigned long data, + int (*handler)(struct kvm *kvm, + unsigned long *rmapp, + unsigned long data)) { int j; int ret; @@ -1273,13 +1276,22 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, slots = kvm_memslots(kvm); kvm_for_each_memslot(memslot, slots) { - unsigned long start = memslot->userspace_addr; - unsigned long end; + unsigned long hva_start, hva_end; + gfn_t gfn, gfn_end; - end = start + (memslot->npages << PAGE_SHIFT); - if (hva >= start && hva < end) { - gfn_t gfn = hva_to_gfn_memslot(hva, memslot); + hva_start = max(start, memslot->userspace_addr); + hva_end = min(end, memslot->userspace_addr + + (memslot->npages << PAGE_SHIFT)); + if (hva_start >= hva_end) + continue; + /* + * {gfn(page) | page intersects with [hva_start, hva_end)} = + * {gfn, gfn+1, ..., gfn_end-1}. + */ + gfn = hva_to_gfn_memslot(hva_start, memslot); + gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot); + for (; gfn < gfn_end; ++gfn) { ret = 0; for (j = PT_PAGE_TABLE_LEVEL; @@ -1289,7 +1301,9 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, rmapp = __gfn_to_rmap(gfn, j, memslot); ret |= handler(kvm, rmapp, data); } - trace_kvm_age_page(hva, memslot, ret); + trace_kvm_age_page(memslot->userspace_addr + + (gfn - memslot->base_gfn) * PAGE_SIZE, + memslot, ret); retval |= ret; } } @@ -1297,6 +1311,14 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, return retval; } +static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, + unsigned long data, + int (*handler)(struct kvm *kvm, unsigned long *rmapp, + unsigned long data)) +{ + return kvm_handle_hva_range(kvm, hva, hva + 1, data, handler); +} + int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) { return kvm_handle_hva(kvm, hva, 0, kvm_unmap_rmapp); From b3ae2096974b12c3af2ad1a4e7716b084949867f Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Mon, 2 Jul 2012 17:56:33 +0900 Subject: [PATCH 0068/5375] KVM: Introduce kvm_unmap_hva_range() for kvm_mmu_notifier_invalidate_range_start() When we tested KVM under memory pressure, with THP enabled on the host, we noticed that MMU notifier took a long time to invalidate huge pages. Since the invalidation was done with mmu_lock held, it not only wasted the CPU but also made the host harder to respond. This patch mitigates this by using kvm_handle_hva_range(). Signed-off-by: Takuya Yoshikawa Cc: Alexander Graf Cc: Paul Mackerras Signed-off-by: Marcelo Tosatti --- arch/powerpc/include/asm/kvm_host.h | 2 ++ arch/powerpc/kvm/book3s_64_mmu_hv.c | 7 +++++++ arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/mmu.c | 5 +++++ virt/kvm/kvm_main.c | 3 +-- 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 50ea12fd7bf5..572ad0141268 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -52,6 +52,8 @@ struct kvm; extern int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); +extern int kvm_unmap_hva_range(struct kvm *kvm, + unsigned long start, unsigned long end); extern int kvm_age_hva(struct kvm *kvm, unsigned long hva); extern int kvm_test_age_hva(struct kvm *kvm, unsigned long hva); extern void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 1a470bc28763..3c635c0616b0 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -870,6 +870,13 @@ int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) return 0; } +int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end) +{ + if (kvm->arch.using_mmu_notifiers) + kvm_handle_hva_range(kvm, start, end, kvm_unmap_rmapp); + return 0; +} + static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, unsigned long gfn) { diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index a3e9409e90b6..d4aab865606c 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -944,6 +944,7 @@ extern bool kvm_rebooting; #define KVM_ARCH_WANT_MMU_NOTIFIER int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); +int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end); int kvm_age_hva(struct kvm *kvm, unsigned long hva); int kvm_test_age_hva(struct kvm *kvm, unsigned long hva); void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 7235b0c9587d..d2855f895fde 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1324,6 +1324,11 @@ int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) return kvm_handle_hva(kvm, hva, 0, kvm_unmap_rmapp); } +int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end) +{ + return kvm_handle_hva_range(kvm, start, end, 0, kvm_unmap_rmapp); +} + void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte) { kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index b3ce91c623e2..e2b1a159e5df 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -332,8 +332,7 @@ static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, * count is also read inside the mmu_lock critical section. */ kvm->mmu_notifier_count++; - for (; start < end; start += PAGE_SIZE) - need_tlb_flush |= kvm_unmap_hva(kvm, start); + need_tlb_flush = kvm_unmap_hva_range(kvm, start, end); need_tlb_flush |= kvm->tlbs_dirty; /* we've to flush the tlb before the pages can be freed */ if (need_tlb_flush) From 77d11309b3a10e1ce112058ec2c9b7b979bcf311 Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Mon, 2 Jul 2012 17:57:17 +0900 Subject: [PATCH 0069/5375] KVM: Separate rmap_pde from kvm_lpage_info->write_count This makes it possible to loop over rmap_pde arrays in the same way as we do over rmap so that we can optimize kvm_handle_hva_range() easily in the following patch. Signed-off-by: Takuya Yoshikawa Signed-off-by: Marcelo Tosatti --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/mmu.c | 6 +++--- arch/x86/kvm/x86.c | 11 +++++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index d4aab865606c..4f98da9243fc 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -500,11 +500,11 @@ struct kvm_vcpu_arch { }; struct kvm_lpage_info { - unsigned long rmap_pde; int write_count; }; struct kvm_arch_memory_slot { + unsigned long *rmap_pde[KVM_NR_PAGE_SIZES - 1]; struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1]; }; diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index d2855f895fde..3b3f5ae5da6a 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -960,13 +960,13 @@ static void pte_list_walk(unsigned long *pte_list, pte_list_walk_fn fn) static unsigned long *__gfn_to_rmap(gfn_t gfn, int level, struct kvm_memory_slot *slot) { - struct kvm_lpage_info *linfo; + unsigned long idx; if (likely(level == PT_PAGE_TABLE_LEVEL)) return &slot->rmap[gfn - slot->base_gfn]; - linfo = lpage_info_slot(gfn, slot, level); - return &linfo->rmap_pde; + idx = gfn_to_index(gfn, slot->base_gfn, level); + return &slot->arch.rmap_pde[level - PT_DIRECTORY_LEVEL][idx]; } /* diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 59b59508ff07..829b4e972558 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6314,6 +6314,10 @@ void kvm_arch_free_memslot(struct kvm_memory_slot *free, int i; for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) { + if (!dont || free->arch.rmap_pde[i] != dont->arch.rmap_pde[i]) { + kvm_kvfree(free->arch.rmap_pde[i]); + free->arch.rmap_pde[i] = NULL; + } if (!dont || free->arch.lpage_info[i] != dont->arch.lpage_info[i]) { kvm_kvfree(free->arch.lpage_info[i]); free->arch.lpage_info[i] = NULL; @@ -6333,6 +6337,11 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) lpages = gfn_to_index(slot->base_gfn + npages - 1, slot->base_gfn, level) + 1; + slot->arch.rmap_pde[i] = + kvm_kvzalloc(lpages * sizeof(*slot->arch.rmap_pde[i])); + if (!slot->arch.rmap_pde[i]) + goto out_free; + slot->arch.lpage_info[i] = kvm_kvzalloc(lpages * sizeof(*slot->arch.lpage_info[i])); if (!slot->arch.lpage_info[i]) @@ -6361,7 +6370,9 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) out_free: for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) { + kvm_kvfree(slot->arch.rmap_pde[i]); kvm_kvfree(slot->arch.lpage_info[i]); + slot->arch.rmap_pde[i] = NULL; slot->arch.lpage_info[i] = NULL; } return -ENOMEM; From 048212d0bc0b1769a4bbecd7ace8c8d237577d1b Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Mon, 2 Jul 2012 17:57:59 +0900 Subject: [PATCH 0070/5375] KVM: MMU: Add memslot parameter to hva handlers This is needed to push trace_kvm_age_page() into kvm_age_rmapp() in the following patch. Signed-off-by: Takuya Yoshikawa Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/mmu.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 3b3f5ae5da6a..dfd7a9a31154 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1200,7 +1200,7 @@ static bool rmap_write_protect(struct kvm *kvm, u64 gfn) } static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, - unsigned long data) + struct kvm_memory_slot *slot, unsigned long data) { u64 *sptep; struct rmap_iterator iter; @@ -1218,7 +1218,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, } static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, - unsigned long data) + struct kvm_memory_slot *slot, unsigned long data) { u64 *sptep; struct rmap_iterator iter; @@ -1265,6 +1265,7 @@ static int kvm_handle_hva_range(struct kvm *kvm, unsigned long data, int (*handler)(struct kvm *kvm, unsigned long *rmapp, + struct kvm_memory_slot *slot, unsigned long data)) { int j; @@ -1299,7 +1300,7 @@ static int kvm_handle_hva_range(struct kvm *kvm, unsigned long *rmapp; rmapp = __gfn_to_rmap(gfn, j, memslot); - ret |= handler(kvm, rmapp, data); + ret |= handler(kvm, rmapp, memslot, data); } trace_kvm_age_page(memslot->userspace_addr + (gfn - memslot->base_gfn) * PAGE_SIZE, @@ -1314,6 +1315,7 @@ static int kvm_handle_hva_range(struct kvm *kvm, static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, unsigned long data, int (*handler)(struct kvm *kvm, unsigned long *rmapp, + struct kvm_memory_slot *slot, unsigned long data)) { return kvm_handle_hva_range(kvm, hva, hva + 1, data, handler); @@ -1335,7 +1337,7 @@ void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte) } static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, - unsigned long data) + struct kvm_memory_slot *slot, unsigned long data) { u64 *sptep; struct rmap_iterator uninitialized_var(iter); @@ -1350,7 +1352,7 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, * out actively used pages or breaking up actively used hugepages. */ if (!shadow_accessed_mask) - return kvm_unmap_rmapp(kvm, rmapp, data); + return kvm_unmap_rmapp(kvm, rmapp, slot, data); for (sptep = rmap_get_first(*rmapp, &iter); sptep; sptep = rmap_get_next(&iter)) { @@ -1367,7 +1369,7 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, } static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp, - unsigned long data) + struct kvm_memory_slot *slot, unsigned long data) { u64 *sptep; struct rmap_iterator iter; @@ -1405,7 +1407,7 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); - kvm_unmap_rmapp(vcpu->kvm, rmapp, 0); + kvm_unmap_rmapp(vcpu->kvm, rmapp, NULL, 0); kvm_flush_remote_tlbs(vcpu->kvm); } From f395302e09ef783b8f82d1160510a95aa8c66dbc Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Mon, 2 Jul 2012 17:58:48 +0900 Subject: [PATCH 0071/5375] KVM: MMU: Push trace_kvm_age_page() into kvm_age_rmapp() This restricts the tracing to page aging and makes it possible to optimize kvm_handle_hva_range() further in the following patch. Signed-off-by: Takuya Yoshikawa Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/mmu.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index dfd7a9a31154..58adec384489 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1269,8 +1269,7 @@ static int kvm_handle_hva_range(struct kvm *kvm, unsigned long data)) { int j; - int ret; - int retval = 0; + int ret = 0; struct kvm_memslots *slots; struct kvm_memory_slot *memslot; @@ -1293,8 +1292,6 @@ static int kvm_handle_hva_range(struct kvm *kvm, gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot); for (; gfn < gfn_end; ++gfn) { - ret = 0; - for (j = PT_PAGE_TABLE_LEVEL; j < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++j) { unsigned long *rmapp; @@ -1302,14 +1299,10 @@ static int kvm_handle_hva_range(struct kvm *kvm, rmapp = __gfn_to_rmap(gfn, j, memslot); ret |= handler(kvm, rmapp, memslot, data); } - trace_kvm_age_page(memslot->userspace_addr + - (gfn - memslot->base_gfn) * PAGE_SIZE, - memslot, ret); - retval |= ret; } } - return retval; + return ret; } static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, @@ -1351,8 +1344,10 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, * This has some overhead, but not as much as the cost of swapping * out actively used pages or breaking up actively used hugepages. */ - if (!shadow_accessed_mask) - return kvm_unmap_rmapp(kvm, rmapp, slot, data); + if (!shadow_accessed_mask) { + young = kvm_unmap_rmapp(kvm, rmapp, slot, data); + goto out; + } for (sptep = rmap_get_first(*rmapp, &iter); sptep; sptep = rmap_get_next(&iter)) { @@ -1364,7 +1359,9 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, (unsigned long *)sptep); } } - +out: + /* @data has hva passed to kvm_age_hva(). */ + trace_kvm_age_page(data, slot, young); return young; } @@ -1413,7 +1410,7 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) int kvm_age_hva(struct kvm *kvm, unsigned long hva) { - return kvm_handle_hva(kvm, hva, 0, kvm_age_rmapp); + return kvm_handle_hva(kvm, hva, hva, kvm_age_rmapp); } int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) From bcd3ef58283a471d6b65855b83f78bd39eb55391 Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Mon, 2 Jul 2012 17:59:33 +0900 Subject: [PATCH 0072/5375] KVM: MMU: Avoid handling same rmap_pde in kvm_handle_hva_range() When we invalidate a THP page, we call the handler with the same rmap_pde argument 512 times in the following loop: for each guest page in the range for each level unmap using rmap This patch avoids these extra handler calls by changing the loop order like this: for each level for each rmap in the range unmap using rmap With the preceding patches in the patch series, this made THP page invalidation more than 5 times faster on our x86 host: the host became more responsive during swapping the guest's memory as a result. Signed-off-by: Takuya Yoshikawa Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/mmu.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 58adec384489..a5d6ef785b7e 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1277,7 +1277,7 @@ static int kvm_handle_hva_range(struct kvm *kvm, kvm_for_each_memslot(memslot, slots) { unsigned long hva_start, hva_end; - gfn_t gfn, gfn_end; + gfn_t gfn_start, gfn_end; hva_start = max(start, memslot->userspace_addr); hva_end = min(end, memslot->userspace_addr + @@ -1286,19 +1286,27 @@ static int kvm_handle_hva_range(struct kvm *kvm, continue; /* * {gfn(page) | page intersects with [hva_start, hva_end)} = - * {gfn, gfn+1, ..., gfn_end-1}. + * {gfn_start, gfn_start+1, ..., gfn_end-1}. */ - gfn = hva_to_gfn_memslot(hva_start, memslot); + gfn_start = hva_to_gfn_memslot(hva_start, memslot); gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot); - for (; gfn < gfn_end; ++gfn) { - for (j = PT_PAGE_TABLE_LEVEL; - j < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++j) { - unsigned long *rmapp; + for (j = PT_PAGE_TABLE_LEVEL; + j < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++j) { + unsigned long idx, idx_end; + unsigned long *rmapp; - rmapp = __gfn_to_rmap(gfn, j, memslot); - ret |= handler(kvm, rmapp, memslot, data); - } + /* + * {idx(page_j) | page_j intersects with + * [hva_start, hva_end)} = {idx, idx+1, ..., idx_end}. + */ + idx = gfn_to_index(gfn_start, memslot->base_gfn, j); + idx_end = gfn_to_index(gfn_end - 1, memslot->base_gfn, j); + + rmapp = __gfn_to_rmap(gfn_start, j, memslot); + + for (; idx <= idx_end; ++idx) + ret |= handler(kvm, rmapp++, memslot, data); } } From c129ef6d0f76a809b0a96fd52b9509856722e74b Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Thu, 19 Jul 2012 18:51:22 -0400 Subject: [PATCH 0073/5375] mm: frontswap: remove unneeded headers Signed-off-by: Sasha Levin [v1: Rebased with tracing removed] Signed-off-by: Konrad Rzeszutek Wilk --- mm/frontswap.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mm/frontswap.c b/mm/frontswap.c index 7fb9538bec23..5318b3a57080 100644 --- a/mm/frontswap.c +++ b/mm/frontswap.c @@ -11,15 +11,11 @@ * This work is licensed under the terms of the GNU GPL, version 2. */ -#include #include #include #include -#include #include -#include #include -#include #include #include #include From 88610238d9a0a5998c4deba201332dd1e35b4199 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Sat, 16 Jun 2012 20:37:48 +0800 Subject: [PATCH 0074/5375] mm/frontswap: cleanup doc and comment error Signed-off-by: Wanpeng Li Signed-off-by: Konrad Rzeszutek Wilk --- Documentation/vm/frontswap.txt | 4 ++-- mm/frontswap.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/vm/frontswap.txt b/Documentation/vm/frontswap.txt index 37067cf455f4..5ef2d1366425 100644 --- a/Documentation/vm/frontswap.txt +++ b/Documentation/vm/frontswap.txt @@ -25,7 +25,7 @@ with the specified swap device number (aka "type"). A "store" will copy the page to transcendent memory and associate it with the type and offset associated with the page. A "load" will copy the page, if found, from transcendent memory into kernel memory, but will NOT remove the page -from from transcendent memory. An "invalidate_page" will remove the page +from transcendent memory. An "invalidate_page" will remove the page from transcendent memory and an "invalidate_area" will remove ALL pages associated with the swap type (e.g., like swapoff) and notify the "device" to refuse further stores with that swap type. @@ -99,7 +99,7 @@ server configured with a large amount of RAM... without pre-configuring how much of the RAM is available for each of the clients! In the virtual case, the whole point of virtualization is to statistically -multiplex physical resources acrosst the varying demands of multiple +multiplex physical resources across the varying demands of multiple virtual machines. This is really hard to do with RAM and efforts to do it well with no kernel changes have essentially failed (except in some well-publicized special-case workloads). diff --git a/mm/frontswap.c b/mm/frontswap.c index 5318b3a57080..6b3e71a2cd48 100644 --- a/mm/frontswap.c +++ b/mm/frontswap.c @@ -120,7 +120,7 @@ static inline void __frontswap_clear(struct swap_info_struct *sis, pgoff_t offse * "Store" data from a page to frontswap and associate it with the page's * swaptype and offset. Page must be locked and in the swap cache. * If frontswap already contains a page with matching swaptype and - * offset, the frontswap implmentation may either overwrite the data and + * offset, the frontswap implementation may either overwrite the data and * return success or invalidate the page from frontswap and return failure. */ int __frontswap_store(struct page *page) From 9d3c92af47d853d4e31ee971dba7bc086275b7b3 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Tue, 17 Jul 2012 21:50:48 +0800 Subject: [PATCH 0075/5375] KVM: x86: remove unnecessary mark_page_dirty fix: [ 132.474633] 3.5.0-rc1+ #50 Not tainted [ 132.474634] ------------------------------- [ 132.474635] include/linux/kvm_host.h:369 suspicious rcu_dereference_check() usage! [ 132.474636] [ 132.474636] other info that might help us debug this: [ 132.474636] [ 132.474638] [ 132.474638] rcu_scheduler_active = 1, debug_locks = 1 [ 132.474640] 1 lock held by qemu-kvm/2832: [ 132.474657] #0: (&vcpu->mutex){+.+.+.}, at: [] vcpu_load+0x1e/0x91 [kvm] [ 132.474658] [ 132.474658] stack backtrace: [ 132.474660] Pid: 2832, comm: qemu-kvm Not tainted 3.5.0-rc1+ #50 [ 132.474661] Call Trace: [ 132.474665] [] lockdep_rcu_suspicious+0xfc/0x105 [ 132.474675] [] kvm_memslots+0x6d/0x75 [kvm] [ 132.474683] [] gfn_to_memslot+0x14/0x4c [kvm] [ 132.474693] [] mark_page_dirty+0x17/0x2a [kvm] [ 132.474706] [] kvm_arch_vcpu_ioctl+0xbcf/0xc07 [kvm] Actually, we do not write vcpu->arch.time at this time, mark_page_dirty should be removed. Signed-off-by: Xiao Guangrong Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/x86.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 829b4e972558..ecc71dde4bb3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2632,7 +2632,6 @@ static int kvm_set_guest_paused(struct kvm_vcpu *vcpu) if (!vcpu->arch.time_page) return -EINVAL; src->flags |= PVCLOCK_GUEST_STOPPED; - mark_page_dirty(vcpu->kvm, vcpu->arch.time >> PAGE_SHIFT); kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); return 0; } From 86fde74cf5b829627b37ca86322acfdd99b524b8 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Tue, 17 Jul 2012 21:52:52 +0800 Subject: [PATCH 0076/5375] KVM: MMU: track the refcount when unmap the page It will trigger a WARN_ON if the page has been freed but it is still used in mmu, it can help us to detect mm bug early Signed-off-by: Xiao Guangrong Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/mmu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index a5d6ef785b7e..685a48557389 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -556,6 +556,14 @@ static int mmu_spte_clear_track_bits(u64 *sptep) return 0; pfn = spte_to_pfn(old_spte); + + /* + * KVM does not hold the refcount of the page used by + * kvm mmu, before reclaiming the page, we should + * unmap it from mmu first. + */ + WARN_ON(!kvm_is_mmio_pfn(pfn) && !page_count(pfn_to_page(pfn))); + if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) kvm_set_pfn_accessed(pfn); if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask)) From 903816fa4d016e20ec71a1a97700cfcdda115580 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Tue, 17 Jul 2012 21:54:11 +0800 Subject: [PATCH 0077/5375] KVM: using get_fault_pfn to get the fault pfn Using get_fault_pfn to cleanup the code Signed-off-by: Xiao Guangrong Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/mmu.c | 6 ++---- include/linux/kvm_host.h | 5 +---- virt/kvm/kvm_main.c | 13 ++++--------- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 685a48557389..f85cc21ae95d 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -2513,10 +2513,8 @@ static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, unsigned long hva; slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, no_dirty_log); - if (!slot) { - get_page(fault_page); - return page_to_pfn(fault_page); - } + if (!slot) + return get_fault_pfn(); hva = gfn_to_hva_memslot(slot, gfn); diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 6f6c18a03c50..1a7f838d30c6 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -383,15 +383,11 @@ id_to_memslot(struct kvm_memslots *slots, int id) static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } extern struct page *bad_page; -extern struct page *fault_page; - extern pfn_t bad_pfn; -extern pfn_t fault_pfn; int is_error_page(struct page *page); int is_error_pfn(pfn_t pfn); int is_hwpoison_pfn(pfn_t pfn); -int is_fault_pfn(pfn_t pfn); int is_noslot_pfn(pfn_t pfn); int is_invalid_pfn(pfn_t pfn); int kvm_is_error_hva(unsigned long addr); @@ -441,6 +437,7 @@ void kvm_release_pfn_clean(pfn_t pfn); void kvm_set_pfn_dirty(pfn_t pfn); void kvm_set_pfn_accessed(pfn_t pfn); void kvm_get_pfn(pfn_t pfn); +pfn_t get_fault_pfn(void); int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset, int len); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index e2b1a159e5df..0fbbf2d21603 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -103,8 +103,8 @@ static bool largepages_enabled = true; static struct page *hwpoison_page; static pfn_t hwpoison_pfn; -struct page *fault_page; -pfn_t fault_pfn; +static struct page *fault_page; +static pfn_t fault_pfn; inline int kvm_is_mmio_pfn(pfn_t pfn) { @@ -949,12 +949,6 @@ int is_hwpoison_pfn(pfn_t pfn) } EXPORT_SYMBOL_GPL(is_hwpoison_pfn); -int is_fault_pfn(pfn_t pfn) -{ - return pfn == fault_pfn; -} -EXPORT_SYMBOL_GPL(is_fault_pfn); - int is_noslot_pfn(pfn_t pfn) { return pfn == bad_pfn; @@ -1038,11 +1032,12 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) } EXPORT_SYMBOL_GPL(gfn_to_hva); -static pfn_t get_fault_pfn(void) +pfn_t get_fault_pfn(void) { get_page(fault_page); return fault_pfn; } +EXPORT_SYMBOL_GPL(get_fault_pfn); int get_user_page_nowait(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int write, struct page **page) From ca0565f5736e67af3172d188577b57e303dd082a Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Tue, 17 Jul 2012 21:54:52 +0800 Subject: [PATCH 0078/5375] KVM: make bad_pfn static to kvm_main.c bad_pfn is not used out of kvm_main.c, so mark it static, also move it near hwpoison_pfn and fault_pfn Signed-off-by: Xiao Guangrong Signed-off-by: Marcelo Tosatti --- include/linux/kvm_host.h | 1 - virt/kvm/kvm_main.c | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 1a7f838d30c6..5f956cde1374 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -383,7 +383,6 @@ id_to_memslot(struct kvm_memslots *slots, int id) static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } extern struct page *bad_page; -extern pfn_t bad_pfn; int is_error_page(struct page *page); int is_error_pfn(pfn_t pfn); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 0fbbf2d21603..f955eee92aa9 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -100,6 +100,9 @@ EXPORT_SYMBOL_GPL(kvm_rebooting); static bool largepages_enabled = true; +struct page *bad_page; +static pfn_t bad_pfn; + static struct page *hwpoison_page; static pfn_t hwpoison_pfn; @@ -2691,9 +2694,6 @@ static struct syscore_ops kvm_syscore_ops = { .resume = kvm_resume, }; -struct page *bad_page; -pfn_t bad_pfn; - static inline struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn) { From f340a51b7e41abbe92ae3a327c0020974a059f95 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Tue, 17 Jul 2012 21:55:34 +0800 Subject: [PATCH 0079/5375] KVM: remove is_error_hpa Remove them since they are not used anymore Signed-off-by: Xiao Guangrong Signed-off-by: Marcelo Tosatti --- include/linux/kvm_host.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 5f956cde1374..e8d13a072d24 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -378,10 +378,6 @@ id_to_memslot(struct kvm_memslots *slots, int id) return slot; } -#define HPA_MSB ((sizeof(hpa_t) * 8) - 1) -#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB) -static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } - extern struct page *bad_page; int is_error_page(struct page *page); From d566104853361cc377c61f70e41c1ad3d44b86c6 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Tue, 17 Jul 2012 21:56:16 +0800 Subject: [PATCH 0080/5375] KVM: remove the unused parameter of gfn_to_pfn_memslot The parameter, 'kvm', is not used in gfn_to_pfn_memslot, we can happily remove it Signed-off-by: Xiao Guangrong Signed-off-by: Marcelo Tosatti --- arch/powerpc/kvm/e500_tlb.c | 2 +- arch/x86/kvm/mmu.c | 2 +- include/linux/kvm_host.h | 5 ++--- virt/kvm/iommu.c | 10 +++++----- virt/kvm/kvm_main.c | 15 +++++++-------- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c index c510fc961302..c8f6c5826742 100644 --- a/arch/powerpc/kvm/e500_tlb.c +++ b/arch/powerpc/kvm/e500_tlb.c @@ -520,7 +520,7 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, if (likely(!pfnmap)) { unsigned long tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT); - pfn = gfn_to_pfn_memslot(vcpu_e500->vcpu.kvm, slot, gfn); + pfn = gfn_to_pfn_memslot(slot, gfn); if (is_error_pfn(pfn)) { printk(KERN_ERR "Couldn't get real page for gfn %lx!\n", (long)gfn); diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index f85cc21ae95d..4f77f7ac6d25 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -2518,7 +2518,7 @@ static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, hva = gfn_to_hva_memslot(slot, gfn); - return hva_to_pfn_atomic(vcpu->kvm, hva); + return hva_to_pfn_atomic(hva); } static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu, diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index e8d13a072d24..db9aa917840a 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -418,15 +418,14 @@ void kvm_release_page_dirty(struct page *page); void kvm_set_page_dirty(struct page *page); void kvm_set_page_accessed(struct page *page); -pfn_t hva_to_pfn_atomic(struct kvm *kvm, unsigned long addr); +pfn_t hva_to_pfn_atomic(unsigned long addr); pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn); pfn_t gfn_to_pfn_async(struct kvm *kvm, gfn_t gfn, bool *async, bool write_fault, bool *writable); pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn); pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault, bool *writable); -pfn_t gfn_to_pfn_memslot(struct kvm *kvm, - struct kvm_memory_slot *slot, gfn_t gfn); +pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn); void kvm_release_pfn_dirty(pfn_t); void kvm_release_pfn_clean(pfn_t pfn); void kvm_set_pfn_dirty(pfn_t pfn); diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index e9fff9830bf0..c03f1fb26701 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -42,13 +42,13 @@ static int kvm_iommu_unmap_memslots(struct kvm *kvm); static void kvm_iommu_put_pages(struct kvm *kvm, gfn_t base_gfn, unsigned long npages); -static pfn_t kvm_pin_pages(struct kvm *kvm, struct kvm_memory_slot *slot, - gfn_t gfn, unsigned long size) +static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn, + unsigned long size) { gfn_t end_gfn; pfn_t pfn; - pfn = gfn_to_pfn_memslot(kvm, slot, gfn); + pfn = gfn_to_pfn_memslot(slot, gfn); end_gfn = gfn + (size >> PAGE_SHIFT); gfn += 1; @@ -56,7 +56,7 @@ static pfn_t kvm_pin_pages(struct kvm *kvm, struct kvm_memory_slot *slot, return pfn; while (gfn < end_gfn) - gfn_to_pfn_memslot(kvm, slot, gfn++); + gfn_to_pfn_memslot(slot, gfn++); return pfn; } @@ -105,7 +105,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) * Pin all pages we are about to map in memory. This is * important because we unmap and unpin in 4kb steps later. */ - pfn = kvm_pin_pages(kvm, slot, gfn, page_size); + pfn = kvm_pin_pages(slot, gfn, page_size); if (is_error_pfn(pfn)) { gfn += 1; continue; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index f955eee92aa9..68dda513cd72 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1062,8 +1062,8 @@ static inline int check_user_page_hwpoison(unsigned long addr) return rc == -EHWPOISON; } -static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr, bool atomic, - bool *async, bool write_fault, bool *writable) +static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, + bool write_fault, bool *writable) { struct page *page[1]; int npages = 0; @@ -1143,9 +1143,9 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr, bool atomic, return pfn; } -pfn_t hva_to_pfn_atomic(struct kvm *kvm, unsigned long addr) +pfn_t hva_to_pfn_atomic(unsigned long addr) { - return hva_to_pfn(kvm, addr, true, NULL, true, NULL); + return hva_to_pfn(addr, true, NULL, true, NULL); } EXPORT_SYMBOL_GPL(hva_to_pfn_atomic); @@ -1163,7 +1163,7 @@ static pfn_t __gfn_to_pfn(struct kvm *kvm, gfn_t gfn, bool atomic, bool *async, return page_to_pfn(bad_page); } - return hva_to_pfn(kvm, addr, atomic, async, write_fault, writable); + return hva_to_pfn(addr, atomic, async, write_fault, writable); } pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn) @@ -1192,11 +1192,10 @@ pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault, } EXPORT_SYMBOL_GPL(gfn_to_pfn_prot); -pfn_t gfn_to_pfn_memslot(struct kvm *kvm, - struct kvm_memory_slot *slot, gfn_t gfn) +pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn) { unsigned long addr = gfn_to_hva_memslot(slot, gfn); - return hva_to_pfn(kvm, addr, false, NULL, true, NULL); + return hva_to_pfn(addr, false, NULL, true, NULL); } int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages, From 0fa060714753ef65aef294b3462efb0212520933 Mon Sep 17 00:00:00 2001 From: Guo Chao Date: Thu, 28 Jun 2012 15:16:19 +0800 Subject: [PATCH 0081/5375] KVM: VMX: Fix typos Signed-off-by: Guo Chao Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/vmx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index c39b60707e02..2300e5319ed9 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1343,7 +1343,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) guest_efer = vmx->vcpu.arch.efer; /* - * NX is emulated; LMA and LME handled by hardware; SCE meaninless + * NX is emulated; LMA and LME handled by hardware; SCE meaningless * outside long mode */ ignore_bits = EFER_NX | EFER_SCE; @@ -3261,7 +3261,7 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu, * qemu binaries. * IA32 arch specifies that at the time of processor reset the * "Accessed" bit in the AR field of segment registers is 1. And qemu - * is setting it to 0 in the usedland code. This causes invalid guest + * is setting it to 0 in the userland code. This causes invalid guest * state vmexit when "unrestricted guest" mode is turned on. * Fix for this setup issue in cpu_reset is being pushed in the qemu * tree. Newer qemu binaries with that qemu fix would not need this @@ -4446,7 +4446,7 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) hypercall[2] = 0xc1; } -/* called to set cr0 as approriate for a mov-to-cr0 exit. */ +/* called to set cr0 as appropriate for a mov-to-cr0 exit. */ static int handle_set_cr0(struct kvm_vcpu *vcpu, unsigned long val) { if (to_vmx(vcpu)->nested.vmxon && From c5ec2e56d0a654797ee43a31001738ccd05eef0b Mon Sep 17 00:00:00 2001 From: Guo Chao Date: Thu, 28 Jun 2012 15:16:43 +0800 Subject: [PATCH 0082/5375] KVM: SVM: Fix typos Signed-off-by: Guo Chao Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/svm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index baead950d6c8..687d0c30e559 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -2063,7 +2063,7 @@ static inline bool nested_svm_intr(struct vcpu_svm *svm) if (svm->nested.intercept & 1ULL) { /* * The #vmexit can't be emulated here directly because this - * code path runs with irqs and preemtion disabled. A + * code path runs with irqs and preemption disabled. A * #vmexit emulation might sleep. Only signal request for * the #vmexit here. */ @@ -2409,7 +2409,7 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm) { /* * This function merges the msr permission bitmaps of kvm and the - * nested vmcb. It is omptimized in that it only merges the parts where + * nested vmcb. It is optimized in that it only merges the parts where * the kvm msr permission bitmap may contain zero bits */ int i; From 4a9699807c491740c4dfe7b6a06703e1d262e802 Mon Sep 17 00:00:00 2001 From: Guo Chao Date: Thu, 28 Jun 2012 15:17:27 +0800 Subject: [PATCH 0083/5375] KVM: x86: Fix typos in x86.c Signed-off-by: Guo Chao Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/x86.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ecc71dde4bb3..3d9d08edbf29 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1093,7 +1093,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data) * For each generation, we track the original measured * nanosecond time, offset, and write, so if TSCs are in * sync, we can match exact offset, and if not, we can match - * exact software computaion in compute_guest_tsc() + * exact software computation in compute_guest_tsc() * * These values are tracked in kvm->arch.cur_xxx variables. */ @@ -1500,7 +1500,7 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data) { gpa_t gpa = data & ~0x3f; - /* Bits 2:5 are resrved, Should be zero */ + /* Bits 2:5 are reserved, Should be zero */ if (data & 0x3c) return 1; @@ -1723,7 +1723,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) * Ignore all writes to this no longer documented MSR. * Writes are only relevant for old K7 processors, * all pre-dating SVM, but a recommended workaround from - * AMD for these chips. It is possible to speicify the + * AMD for these chips. It is possible to specify the * affected processor models on the command line, hence * the need to ignore the workaround. */ @@ -4491,7 +4491,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva) /* * if emulation was due to access to shadowed page table - * and it failed try to unshadow page and re-entetr the + * and it failed try to unshadow page and re-enter the * guest to let CPU execute the instruction. */ if (kvm_mmu_unprotect_page_virt(vcpu, gva)) @@ -5587,7 +5587,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) /* * We are here if userspace calls get_regs() in the middle of * instruction emulation. Registers state needs to be copied - * back from emulation context to vcpu. Usrapace shouldn't do + * back from emulation context to vcpu. Userspace shouldn't do * that usually, but some bad designed PV devices (vmware * backdoor interface) need this to work */ @@ -6116,7 +6116,7 @@ int kvm_arch_hardware_enable(void *garbage) * as we reset last_host_tsc on all VCPUs to stop this from being * called multiple times (one for each physical CPU bringup). * - * Platforms with unnreliable TSCs don't have to deal with this, they + * Platforms with unreliable TSCs don't have to deal with this, they * will be compensated by the logic in vcpu_load, which sets the TSC to * catchup mode. This will catchup all VCPUs to real time, but cannot * guarantee that they stay in perfect synchronization. @@ -6391,7 +6391,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, map_flags = MAP_SHARED | MAP_ANONYMOUS; /*To keep backward compatibility with older userspace, - *x86 needs to hanlde !user_alloc case. + *x86 needs to handle !user_alloc case. */ if (!user_alloc) { if (npages && !old.rmap) { From fc0586807dc4e307da6d3ba4ed5c927b6d27276c Mon Sep 17 00:00:00 2001 From: Guo Chao Date: Thu, 28 Jun 2012 15:19:51 +0800 Subject: [PATCH 0084/5375] KVM: x86: Fix typos in emulate.c Signed-off-by: Guo Chao Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/emulate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 97d9a9914ba8..85b611e13e84 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -642,7 +642,7 @@ static int __linearize(struct x86_emulate_ctxt *ctxt, if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim) goto bad; } else { - /* exapand-down segment */ + /* expand-down segment */ if (addr.ea <= lim || (u32)(addr.ea + size - 1) <= lim) goto bad; lim = desc.d ? 0xffffffff : 0xffff; @@ -1383,7 +1383,7 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, err_code = selector & 0xfffc; err_vec = GP_VECTOR; - /* can't load system descriptor into segment selecor */ + /* can't load system descriptor into segment selector */ if (seg <= VCPU_SREG_GS && !seg_desc.s) goto exception; @@ -2398,7 +2398,7 @@ static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt, set_segment_selector(ctxt, tss->ds, VCPU_SREG_DS); /* - * Now load segment descriptors. If fault happenes at this stage + * Now load segment descriptors. If fault happens at this stage * it is handled in a context of new task */ ret = load_segment_descriptor(ctxt, tss->ldt, VCPU_SREG_LDTR); @@ -2640,7 +2640,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, * * 1. jmp/call/int to task gate: Check against DPL of the task gate * 2. Exception/IRQ/iret: No check is performed - * 3. jmp/call to TSS: Check agains DPL of the TSS + * 3. jmp/call to TSS: Check against DPL of the TSS */ if (reason == TASK_SWITCH_GATE) { if (idt_index != -1) { @@ -2681,7 +2681,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, ctxt->eflags = ctxt->eflags & ~X86_EFLAGS_NT; /* set back link to prev task only if NT bit is set in eflags - note that old_tss_sel is not used afetr this point */ + note that old_tss_sel is not used after this point */ if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE) old_tss_sel = 0xffff; From bbbda79510b6e5d399fae76bdb9b999286eb1b59 Mon Sep 17 00:00:00 2001 From: Guo Chao Date: Thu, 28 Jun 2012 15:20:58 +0800 Subject: [PATCH 0085/5375] KVM: x86: Fix typos in cpuid.c Signed-off-by: Guo Chao Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/cpuid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 0595f1397b7c..b496da684bd6 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -316,7 +316,7 @@ static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, } case 7: { entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; - /* Mask ebx against host capbability word 9 */ + /* Mask ebx against host capability word 9 */ if (index == 0) { entry->ebx &= kvm_supported_word9_x86_features; cpuid_mask(&entry->ebx, 9); From d5b0b5b196b474ef26f46f2036c8fbaa8cca2cf5 Mon Sep 17 00:00:00 2001 From: Guo Chao Date: Thu, 28 Jun 2012 15:22:57 +0800 Subject: [PATCH 0086/5375] KVM: x86: Fix typos in lapic.c Signed-off-by: Guo Chao Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/lapic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index ce878788a39f..fff7173f6a71 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -719,7 +719,7 @@ static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len, { unsigned char alignment = offset & 0xf; u32 result; - /* this bitmask has a bit cleared for each reserver register */ + /* this bitmask has a bit cleared for each reserved register */ static const u64 rmask = 0x43ff01ffffffe70cULL; if ((alignment + len) > 4) { @@ -792,7 +792,7 @@ static void start_apic_timer(struct kvm_lapic *apic) atomic_set(&apic->lapic_timer.pending, 0); if (apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) { - /* lapic timer in oneshot or peroidic mode */ + /* lapic timer in oneshot or periodic mode */ now = apic->lapic_timer.timer.base->get_time(); apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT) * APIC_BUS_CYCLE_NS * apic->divide_count; From c7a7062fa00db7dc66280a72cd9dad0f3595bc66 Mon Sep 17 00:00:00 2001 From: Guo Chao Date: Thu, 28 Jun 2012 15:23:08 +0800 Subject: [PATCH 0087/5375] KVM: x86: Fix typos in pmu.c Signed-off-by: Guo Chao Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 2e88438ffd83..db206a46e0dc 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -1,5 +1,5 @@ /* - * Kernel-based Virtual Machine -- Performane Monitoring Unit support + * Kernel-based Virtual Machine -- Performance Monitoring Unit support * * Copyright 2011 Red Hat, Inc. and/or its affiliates. * From 93b6547e2219784b2df790353e083e0bdbebd2c2 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 19 Jul 2012 13:55:53 +0300 Subject: [PATCH 0088/5375] KVM: switch to symbolic name for irq_states size Use PIC_NUM_PINS instead of hard-coded 16 for pic pins. Signed-off-by: Michael S. Tsirkin Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/irq.h | 2 +- virt/kvm/irq_comm.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 2086f2bfba33..2d03568e9498 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h @@ -70,7 +70,7 @@ struct kvm_pic { struct kvm_io_device dev_slave; struct kvm_io_device dev_eclr; void (*ack_notifier)(void *opaque, int irq); - unsigned long irq_states[16]; + unsigned long irq_states[PIC_NUM_PINS]; }; struct kvm_pic *kvm_create_pic(struct kvm *kvm); diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index a6a0365475ed..22aae8fd146b 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c @@ -343,11 +343,11 @@ static int setup_routing_entry(struct kvm_irq_routing_table *rt, switch (ue->u.irqchip.irqchip) { case KVM_IRQCHIP_PIC_MASTER: e->set = kvm_set_pic_irq; - max_pin = 16; + max_pin = PIC_NUM_PINS; break; case KVM_IRQCHIP_PIC_SLAVE: e->set = kvm_set_pic_irq; - max_pin = 16; + max_pin = PIC_NUM_PINS; delta = 8; break; case KVM_IRQCHIP_IOAPIC: From f2a743473194a1ad44a85f8b63aeef9d63e5bf47 Mon Sep 17 00:00:00 2001 From: Raghavendra K T Date: Wed, 18 Jul 2012 19:07:32 +0530 Subject: [PATCH 0089/5375] KVM: Add config to support ple or cpu relax optimzation Suggested-by: Avi Kivity Signed-off-by: Raghavendra K T Reviewed-by: Marcelo Tosatti Reviewed-by: Rik van Riel Tested-by: Christian Borntraeger # on s390x Signed-off-by: Avi Kivity --- arch/s390/kvm/Kconfig | 1 + arch/x86/kvm/Kconfig | 1 + virt/kvm/Kconfig | 3 +++ 3 files changed, 5 insertions(+) diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 78eb9847008f..a6e2677724e1 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -21,6 +21,7 @@ config KVM depends on HAVE_KVM && EXPERIMENTAL select PREEMPT_NOTIFIERS select ANON_INODES + select HAVE_KVM_CPU_RELAX_INTERCEPT ---help--- Support hosting paravirtualized guest machines using the SIE virtualization capability on the mainframe. This should work diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index a28f338843ea..45c044f0fff7 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -37,6 +37,7 @@ config KVM select TASK_DELAY_ACCT select PERF_EVENTS select HAVE_KVM_MSI + select HAVE_KVM_CPU_RELAX_INTERCEPT ---help--- Support hosting fully virtualized guest machines using hardware virtualization extensions. You will need a fairly recent diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index 28694f4a9139..d01b24b72c61 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -21,3 +21,6 @@ config KVM_ASYNC_PF config HAVE_KVM_MSI bool + +config HAVE_KVM_CPU_RELAX_INTERCEPT + bool From 4c088493c8d07e4e27bad53a99dcfdc14cdf45f8 Mon Sep 17 00:00:00 2001 From: Raghavendra K T Date: Wed, 18 Jul 2012 19:07:46 +0530 Subject: [PATCH 0090/5375] KVM: Note down when cpu relax intercepted or pause loop exited Noting pause loop exited vcpu or cpu relax intercepted helps in filtering right candidate to yield. Wrong selection of vcpu; i.e., a vcpu that just did a pl-exit or cpu relax intercepted may contribute to performance degradation. Signed-off-by: Raghavendra K T Reviewed-by: Marcelo Tosatti Reviewed-by: Rik van Riel Tested-by: Christian Borntraeger # on s390x Signed-off-by: Avi Kivity --- include/linux/kvm_host.h | 34 ++++++++++++++++++++++++++++++++++ virt/kvm/kvm_main.c | 5 +++++ 2 files changed, 39 insertions(+) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index db9aa917840a..361b36fe7ecc 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -183,6 +183,18 @@ struct kvm_vcpu { } async_pf; #endif +#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT + /* + * Cpu relax intercept or pause loop exit optimization + * in_spin_loop: set when a vcpu does a pause loop exit + * or cpu relax intercepted. + * dy_eligible: indicates whether vcpu is eligible for directed yield. + */ + struct { + bool in_spin_loop; + bool dy_eligible; + } spin_loop; +#endif struct kvm_vcpu_arch arch; }; @@ -898,5 +910,27 @@ static inline bool kvm_check_request(int req, struct kvm_vcpu *vcpu) } } +#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT + +static inline void kvm_vcpu_set_in_spin_loop(struct kvm_vcpu *vcpu, bool val) +{ + vcpu->spin_loop.in_spin_loop = val; +} +static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val) +{ + vcpu->spin_loop.dy_eligible = val; +} + +#else /* !CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */ + +static inline void kvm_vcpu_set_in_spin_loop(struct kvm_vcpu *vcpu, bool val) +{ +} + +static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val) +{ +} + +#endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */ #endif diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 68dda513cd72..0892b75eeedd 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -239,6 +239,9 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) } vcpu->run = page_address(page); + kvm_vcpu_set_in_spin_loop(vcpu, false); + kvm_vcpu_set_dy_eligible(vcpu, false); + r = kvm_arch_vcpu_init(vcpu); if (r < 0) goto fail_free_run; @@ -1585,6 +1588,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me) int pass; int i; + kvm_vcpu_set_in_spin_loop(me, true); /* * We boost the priority of a VCPU that is runnable but not * currently running, because it got preempted by something @@ -1610,6 +1614,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me) } } } + kvm_vcpu_set_in_spin_loop(me, false); } EXPORT_SYMBOL_GPL(kvm_vcpu_on_spin); From 06e48c510aa37f6e791602e6420422ea7071fe94 Mon Sep 17 00:00:00 2001 From: Raghavendra K T Date: Thu, 19 Jul 2012 15:17:52 +0530 Subject: [PATCH 0091/5375] KVM: Choose better candidate for directed yield Currently, on a large vcpu guests, there is a high probability of yielding to the same vcpu who had recently done a pause-loop exit or cpu relax intercepted. Such a yield can lead to the vcpu spinning again and hence degrade the performance. The patchset keeps track of the pause loop exit/cpu relax interception and gives chance to a vcpu which: (a) Has not done pause loop exit or cpu relax intercepted at all (probably he is preempted lock-holder) (b) Was skipped in last iteration because it did pause loop exit or cpu relax intercepted, and probably has become eligible now (next eligible lock holder) Signed-off-by: Raghavendra K T Reviewed-by: Marcelo Tosatti Reviewed-by: Rik van Riel Tested-by: Christian Borntraeger # on s390x Signed-off-by: Avi Kivity --- include/linux/kvm_host.h | 5 +++++ virt/kvm/kvm_main.c | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 361b36fe7ecc..74a78d09c454 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -931,6 +931,11 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val) { } +static inline bool kvm_vcpu_eligible_for_directed_yield(struct kvm_vcpu *vcpu) +{ + return true; +} + #endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */ #endif diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 0892b75eeedd..1e10ebe1a370 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1579,6 +1579,43 @@ bool kvm_vcpu_yield_to(struct kvm_vcpu *target) } EXPORT_SYMBOL_GPL(kvm_vcpu_yield_to); +#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT +/* + * Helper that checks whether a VCPU is eligible for directed yield. + * Most eligible candidate to yield is decided by following heuristics: + * + * (a) VCPU which has not done pl-exit or cpu relax intercepted recently + * (preempted lock holder), indicated by @in_spin_loop. + * Set at the beiginning and cleared at the end of interception/PLE handler. + * + * (b) VCPU which has done pl-exit/ cpu relax intercepted but did not get + * chance last time (mostly it has become eligible now since we have probably + * yielded to lockholder in last iteration. This is done by toggling + * @dy_eligible each time a VCPU checked for eligibility.) + * + * Yielding to a recently pl-exited/cpu relax intercepted VCPU before yielding + * to preempted lock-holder could result in wrong VCPU selection and CPU + * burning. Giving priority for a potential lock-holder increases lock + * progress. + * + * Since algorithm is based on heuristics, accessing another VCPU data without + * locking does not harm. It may result in trying to yield to same VCPU, fail + * and continue with next VCPU and so on. + */ +bool kvm_vcpu_eligible_for_directed_yield(struct kvm_vcpu *vcpu) +{ + bool eligible; + + eligible = !vcpu->spin_loop.in_spin_loop || + (vcpu->spin_loop.in_spin_loop && + vcpu->spin_loop.dy_eligible); + + if (vcpu->spin_loop.in_spin_loop) + kvm_vcpu_set_dy_eligible(vcpu, !vcpu->spin_loop.dy_eligible); + + return eligible; +} +#endif void kvm_vcpu_on_spin(struct kvm_vcpu *me) { struct kvm *kvm = me->kvm; @@ -1607,6 +1644,8 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me) continue; if (waitqueue_active(&vcpu->wq)) continue; + if (!kvm_vcpu_eligible_for_directed_yield(vcpu)) + continue; if (kvm_vcpu_yield_to(vcpu)) { kvm->last_boosted_vcpu = i; yielded = 1; @@ -1615,6 +1654,9 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me) } } kvm_vcpu_set_in_spin_loop(me, false); + + /* Ensure vcpu is not eligible during next spinloop */ + kvm_vcpu_set_dy_eligible(me, false); } EXPORT_SYMBOL_GPL(kvm_vcpu_on_spin); From 54d63ca6605d5eb5d2ed52673b523f5781ead71b Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 29 Jun 2012 16:03:35 -0300 Subject: [PATCH 0092/5375] drm/i915: Move DP structs to shared location Move the DP structure to shared location so that it can be used from within the ddi module. Changes from Paulo: - Move less code to intel_drv.h - Remove #include statement - Replace a tab with a space in train_set Signed-off-by: Shobhit Kumar Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 32 -------------------------------- drivers/gpu/drm/i915/intel_drv.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0a56b9ab0f58..9f415643c8e2 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -36,42 +36,10 @@ #include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" -#include "drm_dp_helper.h" -#define DP_RECEIVER_CAP_SIZE 0xf #define DP_LINK_STATUS_SIZE 6 #define DP_LINK_CHECK_TIMEOUT (10 * 1000) -#define DP_LINK_CONFIGURATION_SIZE 9 - -struct intel_dp { - struct intel_encoder base; - uint32_t output_reg; - uint32_t DP; - uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; - bool has_audio; - enum hdmi_force_audio force_audio; - uint32_t color_range; - int dpms_mode; - uint8_t link_bw; - uint8_t lane_count; - uint8_t dpcd[DP_RECEIVER_CAP_SIZE]; - struct i2c_adapter adapter; - struct i2c_algo_dp_aux_data algo; - bool is_pch_edp; - uint8_t train_set[4]; - int panel_power_up_delay; - int panel_power_down_delay; - int panel_power_cycle_delay; - int backlight_on_delay; - int backlight_off_delay; - struct drm_display_mode *panel_fixed_mode; /* for eDP */ - struct delayed_work panel_vdd_work; - bool want_panel_vdd; - struct edid *edid; /* cached EDID for eDP */ - int edid_mode_count; -}; - /** * is_edp - is the given port attached to an eDP panel (either CPU or PCH) * @intel_dp: DP struct diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 84353559441c..35488aae5d09 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -31,6 +31,7 @@ #include "drm_crtc.h" #include "drm_crtc_helper.h" #include "drm_fb_helper.h" +#include "drm_dp_helper.h" #define _wait_for(COND, MS, W) ({ \ unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ @@ -310,6 +311,37 @@ struct intel_hdmi { struct drm_display_mode *adjusted_mode); }; +#define DP_RECEIVER_CAP_SIZE 0xf +#define DP_LINK_CONFIGURATION_SIZE 9 + +struct intel_dp { + struct intel_encoder base; + uint32_t output_reg; + uint32_t DP; + uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; + bool has_audio; + enum hdmi_force_audio force_audio; + uint32_t color_range; + int dpms_mode; + uint8_t link_bw; + uint8_t lane_count; + uint8_t dpcd[DP_RECEIVER_CAP_SIZE]; + struct i2c_adapter adapter; + struct i2c_algo_dp_aux_data algo; + bool is_pch_edp; + uint8_t train_set[4]; + int panel_power_up_delay; + int panel_power_down_delay; + int panel_power_cycle_delay; + int backlight_on_delay; + int backlight_off_delay; + struct drm_display_mode *panel_fixed_mode; /* for eDP */ + struct delayed_work panel_vdd_work; + bool want_panel_vdd; + struct edid *edid; /* cached EDID for eDP */ + int edid_mode_count; +}; + static inline struct drm_crtc * intel_get_crtc_for_pipe(struct drm_device *dev, int pipe) { From 9a3b530455380eed28e7a93121c46d7c334153d9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Jul 2012 12:34:24 +0100 Subject: [PATCH 0093/5375] drm/i915: Cleanup context switching through do_switch() When bug hunting, I found the interface to do_switch() overly complicated and I believe festered the earlier bug. This aims to make the code a little clearer. Signed-off-by: Chris Wilson Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 57 +++++++++++-------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index da8b01fb1bf8..5d0d6ad489e2 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -97,8 +97,7 @@ static struct i915_hw_context * i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); -static int do_switch(struct drm_i915_gem_object *from_obj, - struct i915_hw_context *to, u32 seqno); +static int do_switch(struct i915_hw_context *to); static int get_context_size(struct drm_device *dev) { @@ -220,19 +219,20 @@ static int create_default_context(struct drm_i915_private *dev_priv) */ dev_priv->ring[RCS].default_context = ctx; ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false); - if (ret) { - do_destroy(ctx); - return ret; - } + if (ret) + goto err_destroy; - ret = do_switch(NULL, ctx, 0); - if (ret) { - i915_gem_object_unpin(ctx->obj); - do_destroy(ctx); - } else { - DRM_DEBUG_DRIVER("Default HW context loaded\n"); - } + ret = do_switch(ctx); + if (ret) + goto err_unpin; + DRM_DEBUG_DRIVER("Default HW context loaded\n"); + return 0; + +err_unpin: + i915_gem_object_unpin(ctx->obj); +err_destroy: + do_destroy(ctx); return ret; } @@ -359,17 +359,18 @@ mi_set_context(struct intel_ring_buffer *ring, return ret; } -static int do_switch(struct drm_i915_gem_object *from_obj, - struct i915_hw_context *to, - u32 seqno) +static int do_switch(struct i915_hw_context *to) { - struct intel_ring_buffer *ring = NULL; + struct intel_ring_buffer *ring = to->ring; + struct drm_i915_gem_object *from_obj = ring->last_context_obj; u32 hw_flags = 0; int ret; - BUG_ON(to == NULL); BUG_ON(from_obj != NULL && from_obj->pin_count == 0); + if (from_obj == to->obj) + return 0; + ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false); if (ret) return ret; @@ -393,7 +394,6 @@ static int do_switch(struct drm_i915_gem_object *from_obj, else if (WARN_ON_ONCE(from_obj == to->obj)) /* not yet expected */ hw_flags |= MI_FORCE_RESTORE; - ring = to->ring; ret = mi_set_context(ring, to, hw_flags); if (ret) { i915_gem_object_unpin(to->obj); @@ -407,6 +407,7 @@ static int do_switch(struct drm_i915_gem_object *from_obj, * MI_SET_CONTEXT instead of when the next seqno has completed. */ if (from_obj != NULL) { + u32 seqno = i915_gem_next_request_seqno(ring); from_obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION; i915_gem_object_move_to_active(from_obj, ring, seqno); /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the @@ -417,7 +418,7 @@ static int do_switch(struct drm_i915_gem_object *from_obj, * swapped, but there is no way to do that yet. */ from_obj->dirty = 1; - BUG_ON(from_obj->ring != to->ring); + BUG_ON(from_obj->ring != ring); i915_gem_object_unpin(from_obj); drm_gem_object_unreference(&from_obj->base); @@ -448,10 +449,7 @@ int i915_switch_context(struct intel_ring_buffer *ring, int to_id) { struct drm_i915_private *dev_priv = ring->dev->dev_private; - struct drm_i915_file_private *file_priv = NULL; struct i915_hw_context *to; - struct drm_i915_gem_object *from_obj = ring->last_context_obj; - int ret; if (dev_priv->hw_contexts_disabled) return 0; @@ -459,21 +457,18 @@ int i915_switch_context(struct intel_ring_buffer *ring, if (ring != &dev_priv->ring[RCS]) return 0; - if (file) - file_priv = file->driver_priv; - if (to_id == DEFAULT_CONTEXT_ID) { to = ring->default_context; } else { - to = i915_gem_context_get(file_priv, to_id); + if (file == NULL) + return -EINVAL; + + to = i915_gem_context_get(file->driver_priv, to_id); if (to == NULL) return -ENOENT; } - if (from_obj == to->obj) - return 0; - - return do_switch(from_obj, to, i915_gem_next_request_seqno(to->ring)); + return do_switch(to); } int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, From ebc0fd882b000b119e0684815db8c2245e61162f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Jul 2012 16:27:56 +0200 Subject: [PATCH 0094/5375] drm/i915: group ADPA #defines together Splitting them up between pch and gmch variants just makes it harder to find things. Especially since the hotplug bits are actually valid on earlier chips, too. v2: Fixed the comment as pointed out by Paulo Zanoni. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 47 +++++++++++++++------------------ 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index acc99b21e0b6..d8af397b559e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1548,12 +1548,34 @@ /* VGA port control */ #define ADPA 0x61100 +#define PCH_ADPA 0xe1100 + #define ADPA_DAC_ENABLE (1<<31) #define ADPA_DAC_DISABLE 0 #define ADPA_PIPE_SELECT_MASK (1<<30) #define ADPA_PIPE_A_SELECT 0 #define ADPA_PIPE_B_SELECT (1<<30) #define ADPA_PIPE_SELECT(pipe) ((pipe) << 30) +/* CPT uses bits 29:30 for pch transcoder select */ +#define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */ +#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24) +#define ADPA_CRT_HOTPLUG_ENABLE (1<<23) +#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22) +#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22) +#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21) +#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21) +#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20) +#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20) +#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18) +#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17) +#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17) +#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) #define ADPA_USE_VGA_HVPOLARITY (1<<15) #define ADPA_SETS_HVPOLARITY 0 #define ADPA_VSYNC_CNTL_DISABLE (1<<11) @@ -3888,31 +3910,6 @@ #define FDI_PLL_CTL_1 0xfe000 #define FDI_PLL_CTL_2 0xfe004 -/* CRT */ -#define PCH_ADPA 0xe1100 -#define ADPA_TRANS_SELECT_MASK (1<<30) -#define ADPA_TRANS_A_SELECT 0 -#define ADPA_TRANS_B_SELECT (1<<30) -#define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */ -#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24) -#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24) -#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24) -#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24) -#define ADPA_CRT_HOTPLUG_ENABLE (1<<23) -#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22) -#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22) -#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21) -#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21) -#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20) -#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20) -#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18) -#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18) -#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18) -#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18) -#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17) -#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17) -#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) - /* or SDVOB */ #define HDMIB 0xe1140 #define PORT_ENABLE (1 << 31) From 66a9278eecbef1c746e7fac8f4bcb0485d7aa4d0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 12 Jul 2012 20:08:18 +0200 Subject: [PATCH 0095/5375] drm/i915: simplify possible_clones computation Intel hw only has one MUX for encoders, so outputs are either not cloneable or all in the same group of cloneable outputs. This neatly simplifies the code and allows us to ditch some ugly if cascades in the dp and hdmi init code (well, we need these if cascades for other stuff still, but that can be taken care of in follow-up patches). Note that this changes two things: - dvo can now be cloned with sdvo, but dvo is gen2 whereas sdvo is gen3+, so no problem. Note that the old code had a bug and didn't allow cloning crt with dvo (but only the other way round). - sdvo-lvds can now be cloned with sdvo-non-tv. Spec says this won't work, but the only reason I've found is that you can't use the panel-fitter (used for lvds upscaling) with anything else. But we don't use the panel fitter for sdvo-lvds. Imo this part of Bspec is a) rather confusing b) mostly as a guideline to implementors (i.e. explicitly stating what is already implicit from the spec, without always going into the details of why). So I think we can ignore this - worst case we'll get a bug report from a user with with sdvo-lvds and sdvo-tmds and have to add that special case back in. Because sdvo lvds is a bit special explain in comments why sdvo LVDS outputs can be cloned, but native LVDS and eDP can't be cloned - we use the panel fitter for the later, but not for sdvo. Note that this also uncoditionally initializes the panel_vdd work used by eDP. Trying to be clever doesn't buy us anything (but strange bugs) and this way we can kill the is_edp check. v2: Incorporate review from Paulo - Add in a missing space. - Pimp comment message to address his concerns. Reviewed-by: Paulo Zanoni Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 4 +--- drivers/gpu/drm/i915/intel_display.c | 18 +++++++++++++----- drivers/gpu/drm/i915/intel_dp.c | 14 +++----------- drivers/gpu/drm/i915/intel_drv.h | 25 +++++-------------------- drivers/gpu/drm/i915/intel_dvo.c | 7 ++----- drivers/gpu/drm/i915/intel_hdmi.c | 10 ++-------- drivers/gpu/drm/i915/intel_lvds.c | 2 +- drivers/gpu/drm/i915/intel_sdvo.c | 14 +++++++------- drivers/gpu/drm/i915/intel_tv.c | 2 +- 9 files changed, 35 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 7ed4a41c3965..e1d02be368a5 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -658,9 +658,7 @@ void intel_crt_init(struct drm_device *dev) intel_connector_attach_encoder(intel_connector, &crt->base); crt->base.type = INTEL_OUTPUT_ANALOG; - crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT | - 1 << INTEL_ANALOG_CLONE_BIT | - 1 << INTEL_SDVO_LVDS_CLONE_BIT); + crt->base.cloneable = true; if (IS_HASWELL(dev)) crt->base.crtc_mask = (1 << 0); else diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e9e476eca89f..5c0a72606225 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6707,15 +6707,23 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, return 0; } -static int intel_encoder_clones(struct drm_device *dev, int type_mask) +static int intel_encoder_clones(struct intel_encoder *encoder) { - struct intel_encoder *encoder; + struct drm_device *dev = encoder->base.dev; + struct intel_encoder *source_encoder; int index_mask = 0; int entry = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { - if (type_mask & encoder->clone_mask) + list_for_each_entry(source_encoder, + &dev->mode_config.encoder_list, base.head) { + + if (encoder == source_encoder) index_mask |= (1 << entry); + + /* Intel hw has only one MUX where enocoders could be cloned. */ + if (encoder->cloneable && source_encoder->cloneable) + index_mask |= (1 << entry); + entry++; } @@ -6874,7 +6882,7 @@ static void intel_setup_outputs(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { encoder->base.possible_crtcs = encoder->crtc_mask; encoder->base.possible_clones = - intel_encoder_clones(dev, encoder->clone_mask); + intel_encoder_clones(encoder); } /* disable all the possible outputs/crtcs before entering KMS mode */ diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9f415643c8e2..d1489ab56fc9 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2451,18 +2451,10 @@ intel_dp_init(struct drm_device *dev, int output_reg) connector->polled = DRM_CONNECTOR_POLL_HPD; - if (output_reg == DP_B || output_reg == PCH_DP_B) - intel_encoder->clone_mask = (1 << INTEL_DP_B_CLONE_BIT); - else if (output_reg == DP_C || output_reg == PCH_DP_C) - intel_encoder->clone_mask = (1 << INTEL_DP_C_CLONE_BIT); - else if (output_reg == DP_D || output_reg == PCH_DP_D) - intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT); + intel_encoder->cloneable = false; - if (is_edp(intel_dp)) { - intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT); - INIT_DELAYED_WORK(&intel_dp->panel_vdd_work, - ironlake_panel_vdd_work); - } + INIT_DELAYED_WORK(&intel_dp->panel_vdd_work, + ironlake_panel_vdd_work); intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 35488aae5d09..76ba554f6592 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -90,25 +90,6 @@ #define INTEL_OUTPUT_DISPLAYPORT 7 #define INTEL_OUTPUT_EDP 8 -/* Intel Pipe Clone Bit */ -#define INTEL_HDMIB_CLONE_BIT 1 -#define INTEL_HDMIC_CLONE_BIT 2 -#define INTEL_HDMID_CLONE_BIT 3 -#define INTEL_HDMIE_CLONE_BIT 4 -#define INTEL_HDMIF_CLONE_BIT 5 -#define INTEL_SDVO_NON_TV_CLONE_BIT 6 -#define INTEL_SDVO_TV_CLONE_BIT 7 -#define INTEL_SDVO_LVDS_CLONE_BIT 8 -#define INTEL_ANALOG_CLONE_BIT 9 -#define INTEL_TV_CLONE_BIT 10 -#define INTEL_DP_B_CLONE_BIT 11 -#define INTEL_DP_C_CLONE_BIT 12 -#define INTEL_DP_D_CLONE_BIT 13 -#define INTEL_LVDS_CLONE_BIT 14 -#define INTEL_DVO_TMDS_CLONE_BIT 15 -#define INTEL_DVO_LVDS_CLONE_BIT 16 -#define INTEL_EDP_CLONE_BIT 17 - #define INTEL_DVO_CHIP_NONE 0 #define INTEL_DVO_CHIP_LVDS 1 #define INTEL_DVO_CHIP_TMDS 2 @@ -153,9 +134,13 @@ struct intel_encoder { struct drm_encoder base; int type; bool needs_tv_clock; + /* + * Intel hw has only one MUX where encoders could be clone, hence a + * simple flag is enough to compute the possible_clones mask. + */ + bool cloneable; void (*hot_plug)(struct intel_encoder *); int crtc_mask; - int clone_mask; }; struct intel_connector { diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 36c542e5036b..556cf6bf2a55 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -396,17 +396,14 @@ void intel_dvo_init(struct drm_device *dev) intel_encoder->crtc_mask = (1 << 0) | (1 << 1); switch (dvo->type) { case INTEL_DVO_CHIP_TMDS: - intel_encoder->clone_mask = - (1 << INTEL_DVO_TMDS_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT); + intel_encoder->cloneable = true; drm_connector_init(dev, connector, &intel_dvo_connector_funcs, DRM_MODE_CONNECTOR_DVII); encoder_type = DRM_MODE_ENCODER_TMDS; break; case INTEL_DVO_CHIP_LVDS: - intel_encoder->clone_mask = - (1 << INTEL_DVO_LVDS_CLONE_BIT); + intel_encoder->cloneable = false; drm_connector_init(dev, connector, &intel_dvo_connector_funcs, DRM_MODE_CONNECTOR_LVDS); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 98f602427eb8..593b8fe2e00a 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -923,42 +923,36 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) connector->doublescan_allowed = 0; intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); + intel_encoder->cloneable = false; + /* Set up the DDC bus. */ if (sdvox_reg == SDVOB) { - intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); intel_hdmi->ddc_bus = GMBUS_PORT_DPB; dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == SDVOC) { - intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); intel_hdmi->ddc_bus = GMBUS_PORT_DPC; dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIB) { - intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); intel_hdmi->ddc_bus = GMBUS_PORT_DPB; dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMIC) { - intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT); intel_hdmi->ddc_bus = GMBUS_PORT_DPC; dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == HDMID) { - intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); intel_hdmi->ddc_bus = GMBUS_PORT_DPD; dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; } else if (sdvox_reg == DDI_BUF_CTL(PORT_B)) { DRM_DEBUG_DRIVER("LPT: detected output on DDI B\n"); - intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); intel_hdmi->ddc_bus = GMBUS_PORT_DPB; intel_hdmi->ddi_port = PORT_B; dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; } else if (sdvox_reg == DDI_BUF_CTL(PORT_C)) { DRM_DEBUG_DRIVER("LPT: detected output on DDI C\n"); - intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); intel_hdmi->ddc_bus = GMBUS_PORT_DPC; intel_hdmi->ddi_port = PORT_C; dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; } else if (sdvox_reg == DDI_BUF_CTL(PORT_D)) { DRM_DEBUG_DRIVER("LPT: detected output on DDI D\n"); - intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); intel_hdmi->ddc_bus = GMBUS_PORT_DPD; intel_hdmi->ddi_port = PORT_D; dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e05c0d3e3440..d789fdad5d37 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -967,7 +967,7 @@ bool intel_lvds_init(struct drm_device *dev) intel_connector_attach_encoder(intel_connector, intel_encoder); intel_encoder->type = INTEL_OUTPUT_LVDS; - intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT); + intel_encoder->cloneable = false; if (HAS_PCH_SPLIT(dev)) intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); else if (IS_GEN4(dev)) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 26a6a4d0d078..d881602a9155 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2078,8 +2078,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; intel_sdvo->is_hdmi = true; } - intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT)); + intel_sdvo->base.cloneable = true; intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); if (intel_sdvo->is_hdmi) @@ -2110,7 +2109,7 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) intel_sdvo->is_tv = true; intel_sdvo->base.needs_tv_clock = true; - intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; + intel_sdvo->base.cloneable = false; intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); @@ -2153,8 +2152,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; } - intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT)); + intel_sdvo->base.cloneable = true; intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); @@ -2186,8 +2184,10 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; } - intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | - (1 << INTEL_SDVO_LVDS_CLONE_BIT)); + /* SDVO LVDS is cloneable because the SDVO encoder does the upscaling, + * as opposed to native LVDS, where we upscale with the panel-fitter + * (and hence only the native LVDS resolution could be cloned). */ + intel_sdvo->base.cloneable = true; intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index befce6c49704..1a0bab07699e 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1622,7 +1622,7 @@ intel_tv_init(struct drm_device *dev) intel_connector_attach_encoder(intel_connector, intel_encoder); intel_encoder->type = INTEL_OUTPUT_TVOUT; intel_encoder->crtc_mask = (1 << 0) | (1 << 1); - intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT); + intel_encoder->cloneable = false; intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1)); intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT); intel_tv->type = DRM_MODE_CONNECTOR_Unknown; From 08d644add0e5f799a47dbe7849401606c522e59e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 12 Jul 2012 20:19:59 +0200 Subject: [PATCH 0096/5375] drm/i915: add port parameter to intel_hdmi_init Instead of having a giant if cascade to figure this out according to the passed-in register. We could do quite a bit more cleaning up and all by using the port at more places, but I think this should be part of a bigger rework to introduce a struct intel_digital_port which would keep track of all these things. I guess this will be part of some haswell-DP-induced refactoring. For now this rips out the big cascade, which is what annoyed me so much. v2: Add port variable name back for the func decl (I've tried to trick myself below the 80 char limit). Reviewed-by: Paulo Zanoni Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 14 +++++----- drivers/gpu/drm/i915/intel_drv.h | 3 +- drivers/gpu/drm/i915/intel_hdmi.c | 41 ++++++++-------------------- 4 files changed, 22 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 933c74859172..32604ac80204 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -250,7 +250,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) case PORT_B: case PORT_C: case PORT_D: - intel_hdmi_init(dev, DDI_BUF_CTL(port)); + intel_hdmi_init(dev, DDI_BUF_CTL(port), port); break; default: DRM_DEBUG_DRIVER("No handlers defined for port %d, skipping DDI initialization\n", diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5c0a72606225..e86fd3977f73 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6798,16 +6798,16 @@ static void intel_setup_outputs(struct drm_device *dev) /* PCH SDVOB multiplex with HDMIB */ found = intel_sdvo_init(dev, PCH_SDVOB, true); if (!found) - intel_hdmi_init(dev, HDMIB); + intel_hdmi_init(dev, HDMIB, PORT_B); if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) intel_dp_init(dev, PCH_DP_B); } if (I915_READ(HDMIC) & PORT_DETECTED) - intel_hdmi_init(dev, HDMIC); + intel_hdmi_init(dev, HDMIC, PORT_C); if (!dpd_is_edp && I915_READ(HDMID) & PORT_DETECTED) - intel_hdmi_init(dev, HDMID); + intel_hdmi_init(dev, HDMID, PORT_D); if (I915_READ(PCH_DP_C) & DP_DETECTED) intel_dp_init(dev, PCH_DP_C); @@ -6821,13 +6821,13 @@ static void intel_setup_outputs(struct drm_device *dev) /* SDVOB multiplex with HDMIB */ found = intel_sdvo_init(dev, SDVOB, true); if (!found) - intel_hdmi_init(dev, SDVOB); + intel_hdmi_init(dev, SDVOB, PORT_B); if (!found && (I915_READ(DP_B) & DP_DETECTED)) intel_dp_init(dev, DP_B); } if (I915_READ(SDVOC) & PORT_DETECTED) - intel_hdmi_init(dev, SDVOC); + intel_hdmi_init(dev, SDVOC, PORT_C); /* Shares lanes with HDMI on SDVOC */ if (I915_READ(DP_C) & DP_DETECTED) @@ -6840,7 +6840,7 @@ static void intel_setup_outputs(struct drm_device *dev) found = intel_sdvo_init(dev, SDVOB, true); if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); - intel_hdmi_init(dev, SDVOB); + intel_hdmi_init(dev, SDVOB, PORT_B); } if (!found && SUPPORTS_INTEGRATED_DP(dev)) { @@ -6860,7 +6860,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (SUPPORTS_INTEGRATED_HDMI(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOC\n"); - intel_hdmi_init(dev, SDVOC); + intel_hdmi_init(dev, SDVOC, PORT_C); } if (SUPPORTS_INTEGRATED_DP(dev)) { DRM_DEBUG_KMS("probing DP_C\n"); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 76ba554f6592..d234f1af5db5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -364,7 +364,8 @@ extern void intel_attach_force_audio_property(struct drm_connector *connector); extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector); extern void intel_crt_init(struct drm_device *dev); -extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); +extern void intel_hdmi_init(struct drm_device *dev, + int sdvox_reg, enum port port); extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 593b8fe2e00a..e4c37bb572e8 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -889,7 +889,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c intel_attach_broadcast_rgb_property(connector); } -void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) +void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_connector *connector; @@ -925,40 +925,23 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) intel_encoder->cloneable = false; - /* Set up the DDC bus. */ - if (sdvox_reg == SDVOB) { + intel_hdmi->ddi_port = port; + switch (port) { + case PORT_B: intel_hdmi->ddc_bus = GMBUS_PORT_DPB; dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == SDVOC) { + break; + case PORT_C: intel_hdmi->ddc_bus = GMBUS_PORT_DPC; dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == HDMIB) { - intel_hdmi->ddc_bus = GMBUS_PORT_DPB; - dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == HDMIC) { - intel_hdmi->ddc_bus = GMBUS_PORT_DPC; - dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == HDMID) { + break; + case PORT_D: intel_hdmi->ddc_bus = GMBUS_PORT_DPD; dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == DDI_BUF_CTL(PORT_B)) { - DRM_DEBUG_DRIVER("LPT: detected output on DDI B\n"); - intel_hdmi->ddc_bus = GMBUS_PORT_DPB; - intel_hdmi->ddi_port = PORT_B; - dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == DDI_BUF_CTL(PORT_C)) { - DRM_DEBUG_DRIVER("LPT: detected output on DDI C\n"); - intel_hdmi->ddc_bus = GMBUS_PORT_DPC; - intel_hdmi->ddi_port = PORT_C; - dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; - } else if (sdvox_reg == DDI_BUF_CTL(PORT_D)) { - DRM_DEBUG_DRIVER("LPT: detected output on DDI D\n"); - intel_hdmi->ddc_bus = GMBUS_PORT_DPD; - intel_hdmi->ddi_port = PORT_D; - dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; - } else { - /* If we got an unknown sdvox_reg, things are pretty much broken - * in a way that we should let the kernel know about it */ + break; + case PORT_A: + /* Internal port only for eDP. */ + default: BUG(); } From 47ea7542a1ac33ba9f15608d2fca00abcc1c11e5 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 17 Jul 2012 16:55:16 -0300 Subject: [PATCH 0097/5375] drm/i915: move common code to intel_dp_set_link_train We have some common code that we always run before calling intel_dp_set_link_train. This common code sets the correct training patterns to the DP variable. If we add more calls to intel_dp_set_link_train, we'll also have to duplicate this common code. So instead of repeating this code whenever we call intel_dp_set_link_train, we move the code to inside the function: now we check which training pattern we're going to set and then we set the DP register according to it. One of the side-effects of this change is that now we never forget to mask the training pattern bits before changing them. It looks like this was working before because we were first masking the bits, then writing 00, 01 and then 11. This patch also enables us to use the intel_dp_set_link_train function when disabling link training: in this case we need to avoid writing the DP_TRAINING_LANE*_SET AUX commands. As a bonus, the big intel_dp_{start,complete}_link_train functions will get smaller and a little bit easier to read. Version 2 changes: - Rewrite commit message. - Also clear the training pattern bits before changing them. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 85 ++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d1489ab56fc9..61400c1fef0f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1636,6 +1636,45 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = dev->dev_private; int ret; + if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) { + dp_reg_value &= ~DP_LINK_TRAIN_MASK_CPT; + + switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { + case DP_TRAINING_PATTERN_DISABLE: + dp_reg_value |= DP_LINK_TRAIN_OFF_CPT; + break; + case DP_TRAINING_PATTERN_1: + dp_reg_value |= DP_LINK_TRAIN_PAT_1_CPT; + break; + case DP_TRAINING_PATTERN_2: + dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT; + break; + case DP_TRAINING_PATTERN_3: + DRM_ERROR("DP training pattern 3 not supported\n"); + dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT; + break; + } + + } else { + dp_reg_value &= ~DP_LINK_TRAIN_MASK; + + switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { + case DP_TRAINING_PATTERN_DISABLE: + dp_reg_value |= DP_LINK_TRAIN_OFF; + break; + case DP_TRAINING_PATTERN_1: + dp_reg_value |= DP_LINK_TRAIN_PAT_1; + break; + case DP_TRAINING_PATTERN_2: + dp_reg_value |= DP_LINK_TRAIN_PAT_2; + break; + case DP_TRAINING_PATTERN_3: + DRM_ERROR("DP training pattern 3 not supported\n"); + dp_reg_value |= DP_LINK_TRAIN_PAT_2; + break; + } + } + I915_WRITE(intel_dp->output_reg, dp_reg_value); POSTING_READ(intel_dp->output_reg); @@ -1643,12 +1682,15 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, DP_TRAINING_PATTERN_SET, dp_train_pat); - ret = intel_dp_aux_native_write(intel_dp, - DP_TRAINING_LANE0_SET, - intel_dp->train_set, - intel_dp->lane_count); - if (ret != intel_dp->lane_count) - return false; + if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) != + DP_TRAINING_PATTERN_DISABLE) { + ret = intel_dp_aux_native_write(intel_dp, + DP_TRAINING_LANE0_SET, + intel_dp->train_set, + intel_dp->lane_count); + if (ret != intel_dp->lane_count) + return false; + } return true; } @@ -1664,7 +1706,6 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) uint8_t voltage; bool clock_recovery = false; int voltage_tries, loop_tries; - u32 reg; uint32_t DP = intel_dp->DP; /* @@ -1685,10 +1726,6 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) DP |= DP_PORT_EN; - if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) - DP &= ~DP_LINK_TRAIN_MASK_CPT; - else - DP &= ~DP_LINK_TRAIN_MASK; memset(intel_dp->train_set, 0, 4); voltage = 0xff; voltage_tries = 0; @@ -1712,12 +1749,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } - if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) - reg = DP | DP_LINK_TRAIN_PAT_1_CPT; - else - reg = DP | DP_LINK_TRAIN_PAT_1; - - if (!intel_dp_set_link_train(intel_dp, reg, + if (!intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_1 | DP_LINK_SCRAMBLING_DISABLE)) break; @@ -1772,10 +1804,8 @@ static void intel_dp_complete_link_train(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp->base.base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; bool channel_eq = false; int tries, cr_tries; - u32 reg; uint32_t DP = intel_dp->DP; /* channel equalization */ @@ -1804,13 +1834,8 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } - if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) - reg = DP | DP_LINK_TRAIN_PAT_2_CPT; - else - reg = DP | DP_LINK_TRAIN_PAT_2; - /* channel eq pattern */ - if (!intel_dp_set_link_train(intel_dp, reg, + if (!intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_2 | DP_LINK_SCRAMBLING_DISABLE)) break; @@ -1845,15 +1870,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) ++tries; } - if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) - reg = DP | DP_LINK_TRAIN_OFF_CPT; - else - reg = DP | DP_LINK_TRAIN_OFF; - - I915_WRITE(intel_dp->output_reg, reg); - POSTING_READ(intel_dp->output_reg); - intel_dp_aux_native_write_1(intel_dp, - DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE); + intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_DISABLE); } static void From ab9d7c302af858e1bc8f613c3a6f1eea3c4c0364 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 17 Jul 2012 17:53:45 -0300 Subject: [PATCH 0098/5375] drm/i915: add port field to struct intel_dp and use it This will be needed for Haswell, but already has its uses here. This patch started as a small patch written patch by Shobhit Kumar, but it has changed so much that none of its original lines remain. Credits-to: Shobhit Kumar Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 20 ++++++------- drivers/gpu/drm/i915/intel_dp.c | 44 +++++++++++++--------------- drivers/gpu/drm/i915/intel_drv.h | 4 ++- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e86fd3977f73..f8c2aa1ec27a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6764,10 +6764,10 @@ static void intel_setup_outputs(struct drm_device *dev) dpd_is_edp = intel_dpd_is_edp(dev); if (has_edp_a(dev)) - intel_dp_init(dev, DP_A); + intel_dp_init(dev, DP_A, PORT_A); if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED)) - intel_dp_init(dev, PCH_DP_D); + intel_dp_init(dev, PCH_DP_D, PORT_D); } intel_crt_init(dev); @@ -6800,7 +6800,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (!found) intel_hdmi_init(dev, HDMIB, PORT_B); if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) - intel_dp_init(dev, PCH_DP_B); + intel_dp_init(dev, PCH_DP_B, PORT_B); } if (I915_READ(HDMIC) & PORT_DETECTED) @@ -6810,10 +6810,10 @@ static void intel_setup_outputs(struct drm_device *dev) intel_hdmi_init(dev, HDMID, PORT_D); if (I915_READ(PCH_DP_C) & DP_DETECTED) - intel_dp_init(dev, PCH_DP_C); + intel_dp_init(dev, PCH_DP_C, PORT_C); if (!dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED)) - intel_dp_init(dev, PCH_DP_D); + intel_dp_init(dev, PCH_DP_D, PORT_D); } else if (IS_VALLEYVIEW(dev)) { int found; @@ -6823,7 +6823,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (!found) intel_hdmi_init(dev, SDVOB, PORT_B); if (!found && (I915_READ(DP_B) & DP_DETECTED)) - intel_dp_init(dev, DP_B); + intel_dp_init(dev, DP_B, PORT_B); } if (I915_READ(SDVOC) & PORT_DETECTED) @@ -6831,7 +6831,7 @@ static void intel_setup_outputs(struct drm_device *dev) /* Shares lanes with HDMI on SDVOC */ if (I915_READ(DP_C) & DP_DETECTED) - intel_dp_init(dev, DP_C); + intel_dp_init(dev, DP_C, PORT_C); } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { bool found = false; @@ -6845,7 +6845,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (!found && SUPPORTS_INTEGRATED_DP(dev)) { DRM_DEBUG_KMS("probing DP_B\n"); - intel_dp_init(dev, DP_B); + intel_dp_init(dev, DP_B, PORT_B); } } @@ -6864,14 +6864,14 @@ static void intel_setup_outputs(struct drm_device *dev) } if (SUPPORTS_INTEGRATED_DP(dev)) { DRM_DEBUG_KMS("probing DP_C\n"); - intel_dp_init(dev, DP_C); + intel_dp_init(dev, DP_C, PORT_C); } } if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED)) { DRM_DEBUG_KMS("probing DP_D\n"); - intel_dp_init(dev, DP_D); + intel_dp_init(dev, DP_D, PORT_D); } } else if (IS_GEN2(dev)) intel_dvo_init(dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 61400c1fef0f..ad90a499dab7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2426,7 +2426,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect } void -intel_dp_init(struct drm_device *dev, int output_reg) +intel_dp_init(struct drm_device *dev, int output_reg, enum port port) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_connector *connector; @@ -2441,6 +2441,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) return; intel_dp->output_reg = output_reg; + intel_dp->port = port; intel_dp->dpms_mode = -1; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); @@ -2486,28 +2487,25 @@ intel_dp_init(struct drm_device *dev, int output_reg) drm_sysfs_connector_add(connector); /* Set up the DDC bus. */ - switch (output_reg) { - case DP_A: - name = "DPDDC-A"; - break; - case DP_B: - case PCH_DP_B: - dev_priv->hotplug_supported_mask |= - DPB_HOTPLUG_INT_STATUS; - name = "DPDDC-B"; - break; - case DP_C: - case PCH_DP_C: - dev_priv->hotplug_supported_mask |= - DPC_HOTPLUG_INT_STATUS; - name = "DPDDC-C"; - break; - case DP_D: - case PCH_DP_D: - dev_priv->hotplug_supported_mask |= - DPD_HOTPLUG_INT_STATUS; - name = "DPDDC-D"; - break; + switch (port) { + case PORT_A: + name = "DPDDC-A"; + break; + case PORT_B: + dev_priv->hotplug_supported_mask |= DPB_HOTPLUG_INT_STATUS; + name = "DPDDC-B"; + break; + case PORT_C: + dev_priv->hotplug_supported_mask |= DPC_HOTPLUG_INT_STATUS; + name = "DPDDC-C"; + break; + case PORT_D: + dev_priv->hotplug_supported_mask |= DPD_HOTPLUG_INT_STATUS; + name = "DPDDC-D"; + break; + default: + WARN(1, "Invalid port %c\n", port_name(port)); + break; } intel_dp_i2c_init(intel_dp, intel_connector, name); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d234f1af5db5..2846f5e8cca3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -306,6 +306,7 @@ struct intel_dp { uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; bool has_audio; enum hdmi_force_audio force_audio; + enum port port; uint32_t color_range; int dpms_mode; uint8_t link_bw; @@ -375,7 +376,8 @@ extern void intel_tv_init(struct drm_device *dev); extern void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj); extern bool intel_lvds_init(struct drm_device *dev); -extern void intel_dp_init(struct drm_device *dev, int dp_reg); +extern void intel_dp_init(struct drm_device *dev, int output_reg, + enum port port); void intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); From 7434a255a5cf42819b7e42377f18aaa02f6be52b Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 18 Jul 2012 19:22:30 +0200 Subject: [PATCH 0099/5375] drm/i915: Support for ns2501-DVO This patch adds support for the ns2501 DVO, found in some older Fujitsu/Siemens Labtops. It is in the state of "works for me". Includes now proper DPMS support. Includes switching between resolutions - from 640x480 to 1024x768. Currently assumes that the native display resolution is 1024x768. The ns2501 seems to be rather critical - if the output PLL is not running, the chip doesn't seem to be clocked and then doesn't react on i2c messages. Thus, a quick'n-dirty trick ensures that the DVO is active before submitting any i2c messages to it. This is probably to be reviewed. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=17902 Signed-off-by: Thomas Richter [danvet: fixup whitespace fail.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/dvo.h | 1 + drivers/gpu/drm/i915/dvo_ns2501.c | 582 +++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 4 +- drivers/gpu/drm/i915/intel_dvo.c | 10 +- 5 files changed, 596 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/i915/dvo_ns2501.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index b0bacdba6d7e..0f2c5493242b 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -40,6 +40,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ dvo_ivch.o \ dvo_tfp410.o \ dvo_sil164.o \ + dvo_ns2501.o \ i915_gem_dmabuf.o i915-$(CONFIG_COMPAT) += i915_ioc32.o diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h index 58914691a77b..0c8ac4d92deb 100644 --- a/drivers/gpu/drm/i915/dvo.h +++ b/drivers/gpu/drm/i915/dvo.h @@ -140,5 +140,6 @@ extern struct intel_dvo_dev_ops ch7xxx_ops; extern struct intel_dvo_dev_ops ivch_ops; extern struct intel_dvo_dev_ops tfp410_ops; extern struct intel_dvo_dev_ops ch7017_ops; +extern struct intel_dvo_dev_ops ns2501_ops; #endif /* _INTEL_DVO_H */ diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c new file mode 100644 index 000000000000..1a0bad9a5fab --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_ns2501.c @@ -0,0 +1,582 @@ +/* + * + * Copyright (c) 2012 Gilles Dartiguelongue, Thomas Richter + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "dvo.h" +#include "i915_reg.h" +#include "i915_drv.h" + +#define NS2501_VID 0x1305 +#define NS2501_DID 0x6726 + +#define NS2501_VID_LO 0x00 +#define NS2501_VID_HI 0x01 +#define NS2501_DID_LO 0x02 +#define NS2501_DID_HI 0x03 +#define NS2501_REV 0x04 +#define NS2501_RSVD 0x05 +#define NS2501_FREQ_LO 0x06 +#define NS2501_FREQ_HI 0x07 + +#define NS2501_REG8 0x08 +#define NS2501_8_VEN (1<<5) +#define NS2501_8_HEN (1<<4) +#define NS2501_8_DSEL (1<<3) +#define NS2501_8_BPAS (1<<2) +#define NS2501_8_RSVD (1<<1) +#define NS2501_8_PD (1<<0) + +#define NS2501_REG9 0x09 +#define NS2501_9_VLOW (1<<7) +#define NS2501_9_MSEL_MASK (0x7<<4) +#define NS2501_9_TSEL (1<<3) +#define NS2501_9_RSEN (1<<2) +#define NS2501_9_RSVD (1<<1) +#define NS2501_9_MDI (1<<0) + +#define NS2501_REGC 0x0c + +struct ns2501_priv { + //I2CDevRec d; + bool quiet; + int reg_8_shadow; + int reg_8_set; + // Shadow registers for i915 + int dvoc; + int pll_a; + int srcdim; + int fw_blc; +}; + +#define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr)) + +/* + * Include the PLL launcher prototype + */ +extern void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe); + +/* + * For reasons unclear to me, the ns2501 at least on the Fujitsu/Siemens + * laptops does not react on the i2c bus unless + * both the PLL is running and the display is configured in its native + * resolution. + * This function forces the DVO on, and stores the registers it touches. + * Afterwards, registers are restored to regular values. + * + * This is pretty much a hack, though it works. + * Without that, ns2501_readb and ns2501_writeb fail + * when switching the resolution. + */ + +static void enable_dvo(struct intel_dvo_device *dvo) +{ + struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_gmbus *bus = container_of(adapter, + struct intel_gmbus, + adapter); + struct drm_i915_private *dev_priv = bus->dev_priv; + + DRM_DEBUG_KMS("%s: Trying to re-enable the DVO\n", __FUNCTION__); + + ns->dvoc = I915_READ(DVO_C); + ns->pll_a = I915_READ(_DPLL_A); + ns->srcdim = I915_READ(DVOC_SRCDIM); + ns->fw_blc = I915_READ(FW_BLC); + + I915_WRITE(DVOC, 0x10004084); + I915_WRITE(_DPLL_A, 0xd0820000); + I915_WRITE(DVOC_SRCDIM, 0x400300); // 1024x768 + I915_WRITE(FW_BLC, 0x1080304); + + intel_enable_pll(dev_priv, 0); + + I915_WRITE(DVOC, 0x90004084); +} + +/* + * Restore the I915 registers modified by the above + * trigger function. + */ +static void restore_dvo(struct intel_dvo_device *dvo) +{ + struct i2c_adapter *adapter = dvo->i2c_bus; + struct intel_gmbus *bus = container_of(adapter, + struct intel_gmbus, + adapter); + struct drm_i915_private *dev_priv = bus->dev_priv; + struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); + + I915_WRITE(DVOC, ns->dvoc); + I915_WRITE(_DPLL_A, ns->pll_a); + I915_WRITE(DVOC_SRCDIM, ns->srcdim); + I915_WRITE(FW_BLC, ns->fw_blc); +} + +/* +** Read a register from the ns2501. +** Returns true if successful, false otherwise. +** If it returns false, it might be wise to enable the +** DVO with the above function. +*/ +static bool ns2501_readb(struct intel_dvo_device *dvo, int addr, uint8_t * ch) +{ + struct ns2501_priv *ns = dvo->dev_priv; + struct i2c_adapter *adapter = dvo->i2c_bus; + u8 out_buf[2]; + u8 in_buf[2]; + + struct i2c_msg msgs[] = { + { + .addr = dvo->slave_addr, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = dvo->slave_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = in_buf, + } + }; + + out_buf[0] = addr; + out_buf[1] = 0; + + if (i2c_transfer(adapter, msgs, 2) == 2) { + *ch = in_buf[0]; + return true; + }; + + if (!ns->quiet) { + DRM_DEBUG_KMS + ("Unable to read register 0x%02x from %s:0x%02x.\n", addr, + adapter->name, dvo->slave_addr); + } + + return false; +} + +/* +** Write a register to the ns2501. +** Returns true if successful, false otherwise. +** If it returns false, it might be wise to enable the +** DVO with the above function. +*/ +static bool ns2501_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) +{ + struct ns2501_priv *ns = dvo->dev_priv; + struct i2c_adapter *adapter = dvo->i2c_bus; + uint8_t out_buf[2]; + + struct i2c_msg msg = { + .addr = dvo->slave_addr, + .flags = 0, + .len = 2, + .buf = out_buf, + }; + + out_buf[0] = addr; + out_buf[1] = ch; + + if (i2c_transfer(adapter, &msg, 1) == 1) { + return true; + } + + if (!ns->quiet) { + DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d\n", + addr, adapter->name, dvo->slave_addr); + } + + return false; +} + +/* National Semiconductor 2501 driver for chip on i2c bus + * scan for the chip on the bus. + * Hope the VBIOS initialized the PLL correctly so we can + * talk to it. If not, it will not be seen and not detected. + * Bummer! + */ +static bool ns2501_init(struct intel_dvo_device *dvo, + struct i2c_adapter *adapter) +{ + /* this will detect the NS2501 chip on the specified i2c bus */ + struct ns2501_priv *ns; + unsigned char ch; + + ns = kzalloc(sizeof(struct ns2501_priv), GFP_KERNEL); + if (ns == NULL) + return false; + + dvo->i2c_bus = adapter; + dvo->dev_priv = ns; + ns->quiet = true; + + if (!ns2501_readb(dvo, NS2501_VID_LO, &ch)) + goto out; + + if (ch != (NS2501_VID & 0xff)) { + DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n", + ch, adapter->name, dvo->slave_addr); + goto out; + } + + if (!ns2501_readb(dvo, NS2501_DID_LO, &ch)) + goto out; + + if (ch != (NS2501_DID & 0xff)) { + DRM_DEBUG_KMS("ns2501 not detected got %d: from %s Slave %d.\n", + ch, adapter->name, dvo->slave_addr); + goto out; + } + ns->quiet = false; + ns->reg_8_set = 0; + ns->reg_8_shadow = + NS2501_8_PD | NS2501_8_BPAS | NS2501_8_VEN | NS2501_8_HEN; + + DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n"); + return true; + +out: + kfree(ns); + return false; +} + +static enum drm_connector_status ns2501_detect(struct intel_dvo_device *dvo) +{ + /* + * This is a Laptop display, it doesn't have hotplugging. + * Even if not, the detection bit of the 2501 is unreliable as + * it only works for some display types. + * It is even more unreliable as the PLL must be active for + * allowing reading from the chiop. + */ + return connector_status_connected; +} + +static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo, + struct drm_display_mode *mode) +{ + DRM_DEBUG_KMS + ("%s: is mode valid (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d)\n", + __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay, + mode->vtotal); + + /* + * Currently, these are all the modes I have data from. + * More might exist. Unclear how to find the native resolution + * of the panel in here so we could always accept it + * by disabling the scaler. + */ + if ((mode->hdisplay == 800 && mode->vdisplay == 600) || + (mode->hdisplay == 640 && mode->vdisplay == 480) || + (mode->hdisplay == 1024 && mode->vdisplay == 768)) { + return MODE_OK; + } else { + return MODE_ONE_SIZE; /* Is this a reasonable error? */ + } +} + +static void ns2501_mode_set(struct intel_dvo_device *dvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + bool ok; + bool restore = false; + struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); + + DRM_DEBUG_KMS + ("%s: set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n", + __FUNCTION__, mode->hdisplay, mode->htotal, mode->vdisplay, + mode->vtotal); + + /* + * Where do I find the native resolution for which scaling is not required??? + * + * First trigger the DVO on as otherwise the chip does not appear on the i2c + * bus. + */ + do { + ok = true; + + if (mode->hdisplay == 800 && mode->vdisplay == 600) { + /* mode 277 */ + ns->reg_8_shadow &= ~NS2501_8_BPAS; + DRM_DEBUG_KMS("%s: switching to 800x600\n", + __FUNCTION__); + + /* + * No, I do not know where this data comes from. + * It is just what the video bios left in the DVO, so + * I'm just copying it here over. + * This also means that I cannot support any other modes + * except the ones supported by the bios. + */ + ok &= ns2501_writeb(dvo, 0x11, 0xc8); // 0xc7 also works. + ok &= ns2501_writeb(dvo, 0x1b, 0x19); + ok &= ns2501_writeb(dvo, 0x1c, 0x62); // VBIOS left 0x64 here, but 0x62 works nicer + ok &= ns2501_writeb(dvo, 0x1d, 0x02); + + ok &= ns2501_writeb(dvo, 0x34, 0x03); + ok &= ns2501_writeb(dvo, 0x35, 0xff); + + ok &= ns2501_writeb(dvo, 0x80, 0x27); + ok &= ns2501_writeb(dvo, 0x81, 0x03); + ok &= ns2501_writeb(dvo, 0x82, 0x41); + ok &= ns2501_writeb(dvo, 0x83, 0x05); + + ok &= ns2501_writeb(dvo, 0x8d, 0x02); + ok &= ns2501_writeb(dvo, 0x8e, 0x04); + ok &= ns2501_writeb(dvo, 0x8f, 0x00); + + ok &= ns2501_writeb(dvo, 0x90, 0xfe); /* vertical. VBIOS left 0xff here, but 0xfe works better */ + ok &= ns2501_writeb(dvo, 0x91, 0x07); + ok &= ns2501_writeb(dvo, 0x94, 0x00); + ok &= ns2501_writeb(dvo, 0x95, 0x00); + + ok &= ns2501_writeb(dvo, 0x96, 0x00); + + ok &= ns2501_writeb(dvo, 0x99, 0x00); + ok &= ns2501_writeb(dvo, 0x9a, 0x88); + + ok &= ns2501_writeb(dvo, 0x9c, 0x23); /* Looks like first and last line of the image. */ + ok &= ns2501_writeb(dvo, 0x9d, 0x00); + ok &= ns2501_writeb(dvo, 0x9e, 0x25); + ok &= ns2501_writeb(dvo, 0x9f, 0x03); + + ok &= ns2501_writeb(dvo, 0xa4, 0x80); + + ok &= ns2501_writeb(dvo, 0xb6, 0x00); + + ok &= ns2501_writeb(dvo, 0xb9, 0xc8); /* horizontal? */ + ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */ + + ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */ + ok &= ns2501_writeb(dvo, 0xc1, 0xd7); + + ok &= ns2501_writeb(dvo, 0xc2, 0x00); + ok &= ns2501_writeb(dvo, 0xc3, 0xf8); + + ok &= ns2501_writeb(dvo, 0xc4, 0x03); + ok &= ns2501_writeb(dvo, 0xc5, 0x1a); + + ok &= ns2501_writeb(dvo, 0xc6, 0x00); + ok &= ns2501_writeb(dvo, 0xc7, 0x73); + ok &= ns2501_writeb(dvo, 0xc8, 0x02); + + } else if (mode->hdisplay == 640 && mode->vdisplay == 480) { + /* mode 274 */ + DRM_DEBUG_KMS("%s: switching to 640x480\n", + __FUNCTION__); + /* + * No, I do not know where this data comes from. + * It is just what the video bios left in the DVO, so + * I'm just copying it here over. + * This also means that I cannot support any other modes + * except the ones supported by the bios. + */ + ns->reg_8_shadow &= ~NS2501_8_BPAS; + + ok &= ns2501_writeb(dvo, 0x11, 0xa0); + ok &= ns2501_writeb(dvo, 0x1b, 0x11); + ok &= ns2501_writeb(dvo, 0x1c, 0x54); + ok &= ns2501_writeb(dvo, 0x1d, 0x03); + + ok &= ns2501_writeb(dvo, 0x34, 0x03); + ok &= ns2501_writeb(dvo, 0x35, 0xff); + + ok &= ns2501_writeb(dvo, 0x80, 0xff); + ok &= ns2501_writeb(dvo, 0x81, 0x07); + ok &= ns2501_writeb(dvo, 0x82, 0x3d); + ok &= ns2501_writeb(dvo, 0x83, 0x05); + + ok &= ns2501_writeb(dvo, 0x8d, 0x02); + ok &= ns2501_writeb(dvo, 0x8e, 0x10); + ok &= ns2501_writeb(dvo, 0x8f, 0x00); + + ok &= ns2501_writeb(dvo, 0x90, 0xff); /* vertical */ + ok &= ns2501_writeb(dvo, 0x91, 0x07); + ok &= ns2501_writeb(dvo, 0x94, 0x00); + ok &= ns2501_writeb(dvo, 0x95, 0x00); + + ok &= ns2501_writeb(dvo, 0x96, 0x05); + + ok &= ns2501_writeb(dvo, 0x99, 0x00); + ok &= ns2501_writeb(dvo, 0x9a, 0x88); + + ok &= ns2501_writeb(dvo, 0x9c, 0x24); + ok &= ns2501_writeb(dvo, 0x9d, 0x00); + ok &= ns2501_writeb(dvo, 0x9e, 0x25); + ok &= ns2501_writeb(dvo, 0x9f, 0x03); + + ok &= ns2501_writeb(dvo, 0xa4, 0x84); + + ok &= ns2501_writeb(dvo, 0xb6, 0x09); + + ok &= ns2501_writeb(dvo, 0xb9, 0xa0); /* horizontal? */ + ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */ + + ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */ + ok &= ns2501_writeb(dvo, 0xc1, 0x90); + + ok &= ns2501_writeb(dvo, 0xc2, 0x00); + ok &= ns2501_writeb(dvo, 0xc3, 0x0f); + + ok &= ns2501_writeb(dvo, 0xc4, 0x03); + ok &= ns2501_writeb(dvo, 0xc5, 0x16); + + ok &= ns2501_writeb(dvo, 0xc6, 0x00); + ok &= ns2501_writeb(dvo, 0xc7, 0x02); + ok &= ns2501_writeb(dvo, 0xc8, 0x02); + + } else if (mode->hdisplay == 1024 && mode->vdisplay == 768) { + /* mode 280 */ + DRM_DEBUG_KMS("%s: switching to 1024x768\n", + __FUNCTION__); + /* + * This might or might not work, actually. I'm silently + * assuming here that the native panel resolution is + * 1024x768. If not, then this leaves the scaler disabled + * generating a picture that is likely not the expected. + * + * Problem is that I do not know where to take the panel + * dimensions from. + * + * Enable the bypass, scaling not required. + * + * The scaler registers are irrelevant here.... + * + */ + ns->reg_8_shadow |= NS2501_8_BPAS; + ok &= ns2501_writeb(dvo, 0x37, 0x44); + } else { + /* + * Data not known. Bummer! + * Hopefully, the code should not go here + * as mode_OK delivered no other modes. + */ + ns->reg_8_shadow |= NS2501_8_BPAS; + } + ok &= ns2501_writeb(dvo, NS2501_REG8, ns->reg_8_shadow); + + if (!ok) { + if (restore) + restore_dvo(dvo); + enable_dvo(dvo); + restore = true; + } + } while (!ok); + /* + * Restore the old i915 registers before + * forcing the ns2501 on. + */ + if (restore) + restore_dvo(dvo); +} + +/* set the NS2501 power state */ +static void ns2501_dpms(struct intel_dvo_device *dvo, int mode) +{ + bool ok; + bool restore = false; + struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); + unsigned char ch; + + DRM_DEBUG_KMS("%s: Trying set the dpms of the DVO to %d\n", + __FUNCTION__, mode); + + ch = ns->reg_8_shadow; + + if (mode == DRM_MODE_DPMS_ON) + ch |= NS2501_8_PD; + else + ch &= ~NS2501_8_PD; + + if (ns->reg_8_set == 0 || ns->reg_8_shadow != ch) { + ns->reg_8_set = 1; + ns->reg_8_shadow = ch; + + do { + ok = true; + ok &= ns2501_writeb(dvo, NS2501_REG8, ch); + ok &= + ns2501_writeb(dvo, 0x34, + (mode == + DRM_MODE_DPMS_ON) ? (0x03) : (0x00)); + ok &= + ns2501_writeb(dvo, 0x35, + (mode == + DRM_MODE_DPMS_ON) ? (0xff) : (0x00)); + if (!ok) { + if (restore) + restore_dvo(dvo); + enable_dvo(dvo); + restore = true; + } + } while (!ok); + + if (restore) + restore_dvo(dvo); + } +} + +static void ns2501_dump_regs(struct intel_dvo_device *dvo) +{ + uint8_t val; + + ns2501_readb(dvo, NS2501_FREQ_LO, &val); + DRM_LOG_KMS("NS2501_FREQ_LO: 0x%02x\n", val); + ns2501_readb(dvo, NS2501_FREQ_HI, &val); + DRM_LOG_KMS("NS2501_FREQ_HI: 0x%02x\n", val); + ns2501_readb(dvo, NS2501_REG8, &val); + DRM_LOG_KMS("NS2501_REG8: 0x%02x\n", val); + ns2501_readb(dvo, NS2501_REG9, &val); + DRM_LOG_KMS("NS2501_REG9: 0x%02x\n", val); + ns2501_readb(dvo, NS2501_REGC, &val); + DRM_LOG_KMS("NS2501_REGC: 0x%02x\n", val); +} + +static void ns2501_destroy(struct intel_dvo_device *dvo) +{ + struct ns2501_priv *ns = dvo->dev_priv; + + if (ns) { + kfree(ns); + dvo->dev_priv = NULL; + } +} + +struct intel_dvo_dev_ops ns2501_ops = { + .init = ns2501_init, + .detect = ns2501_detect, + .mode_valid = ns2501_mode_valid, + .mode_set = ns2501_mode_set, + .dpms = ns2501_dpms, + .dump_regs = ns2501_dump_regs, + .destroy = ns2501_destroy, +}; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f8c2aa1ec27a..93d9934ba328 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1428,8 +1428,10 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, * protect mechanism may be enabled. * * Note! This is for pre-ILK only. + * + * Unfortunately needed by dvo_ns2501 since the dvo depends on it running. */ -static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) { int reg; u32 val; diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 556cf6bf2a55..03dfdff8e003 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -37,6 +37,7 @@ #define SIL164_ADDR 0x38 #define CH7xxx_ADDR 0x76 #define TFP410_ADDR 0x38 +#define NS2501_ADDR 0x38 static const struct intel_dvo_device intel_dvo_devices[] = { { @@ -74,7 +75,14 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .slave_addr = 0x75, .gpio = GMBUS_PORT_DPB, .dev_ops = &ch7017_ops, - } + }, + { + .type = INTEL_DVO_CHIP_TMDS, + .name = "ns2501", + .dvo_reg = DVOC, + .slave_addr = NS2501_ADDR, + .dev_ops = &ns2501_ops, + } }; struct intel_dvo { From 2b860db67ff3ce886fcb35289a9283a041cce6a4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 18 Jul 2012 20:03:05 +0200 Subject: [PATCH 0100/5375] drm/i915: Reserve ioctl numbers for set/get_caching I'm planing to merge this next week for 3.7, but I'd like to avoid stupid conflicts with the exsting userspace when merging the new reg_read ioctl (which doesn't have userspace yet, but this caching interface has). Header extracted from Chris Wilson's patch, but fix up the copy&pasted comment in the interface struct. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- include/drm/i915_drm.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index 8cc70837f929..95648ab819ac 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -203,6 +203,8 @@ typedef struct _drm_i915_sarea { #define DRM_I915_GEM_WAIT 0x2c #define DRM_I915_GEM_CONTEXT_CREATE 0x2d #define DRM_I915_GEM_CONTEXT_DESTROY 0x2e +#define DRM_I915_GEM_SET_CACHEING 0x2f +#define DRM_I915_GEM_GET_CACHEING 0x30 #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -227,6 +229,8 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin) #define DRM_IOCTL_I915_GEM_UNPIN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin) #define DRM_IOCTL_I915_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy) +#define DRM_IOCTL_I915_GEM_SET_CACHEING DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_SET_CACHEING, struct drm_i915_gem_cacheing) +#define DRM_IOCTL_I915_GEM_GET_CACHEING DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_GET_CACHEING, struct drm_i915_gem_cacheing) #define DRM_IOCTL_I915_GEM_THROTTLE DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE) #define DRM_IOCTL_I915_GEM_ENTERVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT) #define DRM_IOCTL_I915_GEM_LEAVEVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT) @@ -702,6 +706,17 @@ struct drm_i915_gem_busy { __u32 busy; }; +#define I915_CACHEING_NONE 0 +#define I915_CACHEING_CACHED 1 + +struct drm_i915_gem_cacheing { + /** Handle of the buffer to check for busy */ + __u32 handle; + + /** Cacheing level to apply or return value */ + __u32 cacheing; +}; + #define I915_TILING_NONE 0 #define I915_TILING_X 1 #define I915_TILING_Y 2 From c0c7babc48c4f6943ed3070d04630ea3ac9272ee Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 12 Jul 2012 11:01:05 -0700 Subject: [PATCH 0101/5375] drm/i915: add register read IOCTL The interface's immediate purpose is to do synchronous timestamp queries as required by GL_TIMESTAMP. The GPU has a register for reading the timestamp but because that would normally require root access through libpciaccess, the IOCTL can provide this service instead. Currently the implementation whitelists only the render ring timestamp register, because that is the only thing we need to expose at this time. v2: make size implicit based on the register offset Add a generation check Reviewed-by: Eric Anholt Cc: Jacek Lawrynowicz Signed-off-by: Ben Widawsky [danvet: fixup the ioctl numerb:] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 1 + drivers/gpu/drm/i915/i915_drv.c | 46 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_reg.h | 1 + include/drm/i915_drm.h | 8 +++++- 5 files changed, 57 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 9cf7dfe022b9..733744f26dc6 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1857,6 +1857,7 @@ struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ed22612bc847..ab3b9d38e153 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1151,3 +1151,49 @@ __i915_write(16, w) __i915_write(32, l) __i915_write(64, q) #undef __i915_write + +static const struct register_whitelist { + uint64_t offset; + uint32_t size; + uint32_t gen_bitmask; /* support gens, 0x10 for 4, 0x30 for 4 and 5, etc. */ +} whitelist[] = { + { RING_TIMESTAMP(RENDER_RING_BASE), 8, 0xF0 }, +}; + +int i915_reg_read_ioctl(struct drm_device *dev, + void *data, struct drm_file *file) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_reg_read *reg = data; + struct register_whitelist const *entry = whitelist; + int i; + + for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) { + if (entry->offset == reg->offset && + (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask)) + break; + } + + if (i == ARRAY_SIZE(whitelist)) + return -EINVAL; + + switch (entry->size) { + case 8: + reg->val = I915_READ64(reg->offset); + break; + case 4: + reg->val = I915_READ(reg->offset); + break; + case 2: + reg->val = I915_READ16(reg->offset); + break; + case 1: + reg->val = I915_READ8(reg->offset); + break; + default: + WARN_ON(1); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 627fe35781b4..2c0d8403c5ed 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1529,6 +1529,8 @@ extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); extern int intel_enable_rc6(const struct drm_device *dev); extern bool i915_semaphore_is_enabled(struct drm_device *dev); +int i915_reg_read_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); /* overlay */ #ifdef CONFIG_DEBUG_FS diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d8af397b559e..0d1fa64b56dc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -449,6 +449,7 @@ #define RING_ACTHD(base) ((base)+0x74) #define RING_NOPID(base) ((base)+0x94) #define RING_IMR(base) ((base)+0xa8) +#define RING_TIMESTAMP(base) ((base)+0x358) #define TAIL_ADDR 0x001FFFF8 #define HEAD_WRAP_COUNT 0xFFE00000 #define HEAD_WRAP_ONE 0x00200000 diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index 95648ab819ac..b923b032743f 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -205,6 +205,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_GEM_CONTEXT_DESTROY 0x2e #define DRM_I915_GEM_SET_CACHEING 0x2f #define DRM_I915_GEM_GET_CACHEING 0x30 +#define DRM_I915_REG_READ 0x31 #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -253,6 +254,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GEM_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait) #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create) #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy) +#define DRM_IOCTL_I915_REG_READ DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. @@ -710,7 +712,7 @@ struct drm_i915_gem_busy { #define I915_CACHEING_CACHED 1 struct drm_i915_gem_cacheing { - /** Handle of the buffer to check for busy */ + /** Handle of the buffer to set/get the cacheing level of */ __u32 handle; /** Cacheing level to apply or return value */ @@ -933,4 +935,8 @@ struct drm_i915_gem_context_destroy { __u32 pad; }; +struct drm_i915_reg_read { + __u64 offset; + __u64 val; /* Return value */ +}; #endif /* _I915_DRM_H_ */ From e9808edd98679680804dfbc42c5ee8f1aa91f617 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Jul 2012 12:25:08 +0100 Subject: [PATCH 0102/5375] drm/i915: Return a mask of the active rings in the high word of busy_ioctl The intention is to help select which engine to use for copies with interoperating clients - such as a GL client making a request to the X server to perform a SwapBuffers, which may require copying from the active GL back buffer to the X front buffer. We choose to report a mask of the active rings to future proof the interface against any changes which may allow for the object to reside upon multiple rings. Signed-off-by: Chris Wilson [danvet: bikeshed away the write ring mask and add the explanation Chris sent in a follow-up mail why we decided to use masks.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 4 ++++ include/drm/i915_drm.h | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5c4657a54f97..4be096068b35 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3400,6 +3400,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, ret = i915_gem_object_flush_active(obj); args->busy = obj->active; + if (obj->ring) { + BUILD_BUG_ON(I915_NUM_RINGS > 16); + args->busy |= intel_ring_flag(obj->ring) << 16; + } drm_gem_object_unreference(&obj->base); unlock: diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index b923b032743f..0f149fe32211 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -704,7 +704,11 @@ struct drm_i915_gem_busy { /** Handle of the buffer to check for busy */ __u32 handle; - /** Return busy status (1 if busy, 0 if idle) */ + /** Return busy status (1 if busy, 0 if idle). + * The high word is used to indicate on which rings the object + * currently resides: + * 16:31 - busy (r or r/w) rings (16 render, 17 bsd, 18 blt, etc) + */ __u32 busy; }; From a7e806de4e53f7496a6701194d736a92a80db5b3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Jul 2012 16:27:55 +0200 Subject: [PATCH 0103/5375] drm/i915: create VLV_DSIPLAY_BASE #define Will be used more in the next patch. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_reg.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ab3b9d38e153..ff569cc35376 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1031,7 +1031,7 @@ static bool IS_DISPLAYREG(u32 reg) * This should make it easier to transition modules over to the * new register block scheme, since we can do it incrementally. */ - if (reg >= 0x180000) + if (reg >= VLV_DISPLAY_BASE) return false; if (reg >= RENDER_RING_BASE && diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0d1fa64b56dc..d122c93643e6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -529,6 +529,8 @@ #define GFX_PSMI_GRANULARITY (1<<10) #define GFX_PPGTT_ENABLE (1<<9) +#define VLV_DISPLAY_BASE 0x180000 + #define SCPD0 0x0209c /* 915+ only */ #define IER 0x020a0 #define IIR 0x020a4 From 540a8950047579a368a9b8fdcc15ab7fdb9921d3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Jul 2012 16:27:57 +0200 Subject: [PATCH 0104/5375] drm/i915: add inte_crt->adpa_reg With the base addresses shifting around, this is easier to handle. Also move to the real reg offset on vlv. Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_crt.c | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d122c93643e6..81a3de6b093c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1552,6 +1552,7 @@ /* VGA port control */ #define ADPA 0x61100 #define PCH_ADPA 0xe1100 +#define VLV_ADPA (VLV_DISPLAY_BASE + ADPA) #define ADPA_DAC_ENABLE (1<<31) #define ADPA_DAC_DISABLE 0 diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index e1d02be368a5..bc5e2c97db61 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -47,6 +47,7 @@ struct intel_crt { struct intel_encoder base; bool force_hotplug_required; + u32 adpa_reg; }; static struct intel_crt *intel_attached_crt(struct drm_connector *connector) @@ -55,6 +56,11 @@ static struct intel_crt *intel_attached_crt(struct drm_connector *connector) struct intel_crt, base); } +static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder) +{ + return container_of(encoder, struct intel_crt, base); +} + static void pch_crt_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; @@ -145,19 +151,15 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct drm_crtc *crtc = encoder->crtc; + struct intel_crt *crt = + intel_encoder_to_crt(to_intel_encoder(encoder)); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_i915_private *dev_priv = dev->dev_private; int dpll_md_reg; u32 adpa, dpll_md; - u32 adpa_reg; dpll_md_reg = DPLL_MD(intel_crtc->pipe); - if (HAS_PCH_SPLIT(dev)) - adpa_reg = PCH_ADPA; - else - adpa_reg = ADPA; - /* * Disable separate mode multiplier used when cloning SDVO to CRT * XXX this needs to be adjusted when we really are cloning @@ -185,7 +187,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, if (!HAS_PCH_SPLIT(dev)) I915_WRITE(BCLRPAT(intel_crtc->pipe), 0); - I915_WRITE(adpa_reg, adpa); + I915_WRITE(crt->adpa_reg, adpa); } static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) @@ -675,6 +677,13 @@ void intel_crt_init(struct drm_device *dev) else encoder_helper_funcs = &gmch_encoder_funcs; + if (HAS_PCH_SPLIT(dev)) + crt->adpa_reg = PCH_ADPA; + else if (IS_VALLEYVIEW(dev)) + crt->adpa_reg = VLV_ADPA; + else + crt->adpa_reg = ADPA; + drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); From 3bb73aba1ed5198a2c1dfaac4f3c95459930d84a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Jul 2012 12:40:59 +0100 Subject: [PATCH 0105/5375] drm/i915: Allow late allocation of request for i915_add_request() Request preallocation was added to i915_add_request() in order to support the overlay. However, not all users care and can quite happily ignore the failure to allocate the request as they will simply repeat the request in the future. By pushing the allocation down into i915_add_request(), we can then remove some rather ugly error handling in the callers. v2: Nullify request->file_priv otherwise we chase a garbage pointer when retiring requests. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 +-- drivers/gpu/drm/i915/i915_gem.c | 44 +++++++++------------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 7 +--- 3 files changed, 21 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2c0d8403c5ed..1f5f5ff6f897 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1358,9 +1358,9 @@ void i915_gem_init_ppgtt(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_idle(struct drm_device *dev); -int __must_check i915_add_request(struct intel_ring_buffer *ring, - struct drm_file *file, - struct drm_i915_gem_request *request); +int i915_add_request(struct intel_ring_buffer *ring, + struct drm_file *file, + struct drm_i915_gem_request *request); int __must_check i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4be096068b35..771b8ba36e44 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1597,7 +1597,12 @@ i915_add_request(struct intel_ring_buffer *ring, ring->gpu_caches_dirty = false; } - BUG_ON(request == NULL); + if (request == NULL) { + request = kmalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return -ENOMEM; + } + seqno = i915_gem_next_request_seqno(ring); /* Record the position of the start of the request so that @@ -1608,8 +1613,10 @@ i915_add_request(struct intel_ring_buffer *ring, request_ring_position = intel_ring_get_tail(ring); ret = ring->add_request(ring, &seqno); - if (ret) - return ret; + if (ret) { + kfree(request); + return ret; + } trace_i915_gem_request_add(ring, seqno); @@ -1619,6 +1626,7 @@ i915_add_request(struct intel_ring_buffer *ring, request->emitted_jiffies = jiffies; was_empty = list_empty(&ring->request_list); list_add_tail(&request->list, &ring->request_list); + request->file_priv = NULL; if (file) { struct drm_i915_file_private *file_priv = file->driver_priv; @@ -1859,14 +1867,8 @@ i915_gem_retire_work_handler(struct work_struct *work) */ idle = true; for_each_ring(ring, dev_priv, i) { - if (ring->gpu_caches_dirty) { - struct drm_i915_gem_request *request; - - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL || - i915_add_request(ring, NULL, request)) - kfree(request); - } + if (ring->gpu_caches_dirty) + i915_add_request(ring, NULL, NULL); idle &= list_empty(&ring->request_list); } @@ -1913,25 +1915,13 @@ i915_gem_check_wedge(struct drm_i915_private *dev_priv, static int i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno) { - int ret = 0; + int ret; BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex)); - if (seqno == ring->outstanding_lazy_request) { - struct drm_i915_gem_request *request; - - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) - return -ENOMEM; - - ret = i915_add_request(ring, NULL, request); - if (ret) { - kfree(request); - return ret; - } - - BUG_ON(seqno != request->seqno); - } + ret = 0; + if (seqno == ring->outstanding_lazy_request) + ret = i915_add_request(ring, NULL, NULL); return ret; } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 5af631e788c8..f94ec574db2b 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -972,16 +972,11 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev, struct drm_file *file, struct intel_ring_buffer *ring) { - struct drm_i915_gem_request *request; - /* Unconditionally force add_request to emit a full flush. */ ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL || i915_add_request(ring, file, request)) { - kfree(request); - } + (void)i915_add_request(ring, file, NULL); } static int From e5f1d962a8e4c5fd6b3a8155c0f7a40b0bff4a96 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Jul 2012 12:41:00 +0100 Subject: [PATCH 0106/5375] drm/i915: Remove assertion over write domain after i915_gem_object_sync() As we move to lazily clearing the GPU write domain only when the buffer becomes inactive, this leaves a window of opportunity for i915_gem_object_pin_to_display_plane() to detect a seemingly inconsistent value. This function is special as it tries to pipeline the operation to avoid the stall and so may not retires the buffer and we may not get the opportunity to clear the write domain. However, we know all is good, so drop the assertion. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 771b8ba36e44..3bef7e60ddd6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3091,7 +3091,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, /* It should now be out of any other write domains, and we can update * the domain values for our changes. */ - BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_GTT) != 0); + obj->base.write_domain = 0; obj->base.read_domains |= I915_GEM_DOMAIN_GTT; trace_i915_gem_object_change_domain(obj, From 0201f1ecf4b81f08799b1fb9c8cdf1125b9b78a6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Jul 2012 12:41:01 +0100 Subject: [PATCH 0107/5375] drm/i915: Replace the pending_gpu_write flag with an explicit seqno As we always flush the GPU cache prior to emitting the breadcrumb, we no longer have to worry about the deferred flush causing the pending_gpu_write to be delayed. So we can instead utilize the known last_write_seqno to hopefully minimise the wait times. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 9 +-- drivers/gpu/drm/i915/i915_drv.h | 12 +--- drivers/gpu/drm/i915/i915_gem.c | 66 +++++++++++++--------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/i915_irq.c | 5 +- 5 files changed, 51 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 359f6e8b9b00..a8b7db6161ca 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -121,14 +121,15 @@ static const char *cache_level_str(int type) static void describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) { - seq_printf(m, "%p: %s%s %8zdKiB %04x %04x %d %d%s%s%s", + seq_printf(m, "%p: %s%s %8zdKiB %04x %04x %d %d %d%s%s%s", &obj->base, get_pin_flag(obj), get_tiling_flag(obj), obj->base.size / 1024, obj->base.read_domains, obj->base.write_domain, - obj->last_rendering_seqno, + obj->last_read_seqno, + obj->last_write_seqno, obj->last_fenced_seqno, cache_level_str(obj->cache_level), obj->dirty ? " dirty" : "", @@ -630,12 +631,12 @@ static void print_error_buffers(struct seq_file *m, seq_printf(m, "%s [%d]:\n", name, count); while (count--) { - seq_printf(m, " %08x %8u %04x %04x %08x%s%s%s%s%s%s%s", + seq_printf(m, " %08x %8u %04x %04x %x %x%s%s%s%s%s%s%s", err->gtt_offset, err->size, err->read_domains, err->write_domain, - err->seqno, + err->rseqno, err->wseqno, pin_flag(err->pinned), tiling_flag(err->tiling), dirty_flag(err->dirty), diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1f5f5ff6f897..49a532e338e6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -221,7 +221,7 @@ struct drm_i915_error_state { struct drm_i915_error_buffer { u32 size; u32 name; - u32 seqno; + u32 rseqno, wseqno; u32 gtt_offset; u32 read_domains; u32 write_domain; @@ -894,12 +894,6 @@ struct drm_i915_gem_object { */ unsigned int dirty:1; - /** - * This is set if the object has been written to since the last - * GPU flush. - */ - unsigned int pending_gpu_write:1; - /** * Fence register bits (if any) for this object. Will be set * as needed when mapped into the GTT. @@ -992,7 +986,8 @@ struct drm_i915_gem_object { struct intel_ring_buffer *ring; /** Breadcrumb of last rendering to the buffer. */ - uint32_t last_rendering_seqno; + uint32_t last_read_seqno; + uint32_t last_write_seqno; /** Breadcrumb of last fenced GPU access to the buffer. */ uint32_t last_fenced_seqno; @@ -1291,7 +1286,6 @@ void i915_gem_lastclose(struct drm_device *dev); int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj, gfp_t gfpmask); int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); -int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj); int i915_gem_object_sync(struct drm_i915_gem_object *obj, struct intel_ring_buffer *to); void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3bef7e60ddd6..6a80d6565ef2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1441,7 +1441,7 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, list_move_tail(&obj->mm_list, &dev_priv->mm.active_list); list_move_tail(&obj->ring_list, &ring->active_list); - obj->last_rendering_seqno = seqno; + obj->last_read_seqno = seqno; if (obj->fenced_gpu_access) { obj->last_fenced_seqno = seqno; @@ -1461,7 +1461,8 @@ static void i915_gem_object_move_off_active(struct drm_i915_gem_object *obj) { list_del_init(&obj->ring_list); - obj->last_rendering_seqno = 0; + obj->last_read_seqno = 0; + obj->last_write_seqno = 0; obj->last_fenced_seqno = 0; } @@ -1493,7 +1494,6 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) obj->fenced_gpu_access = false; obj->active = 0; - obj->pending_gpu_write = false; drm_gem_object_unreference(&obj->base); WARN_ON(i915_verify_lists(dev)); @@ -1812,7 +1812,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) struct drm_i915_gem_object, ring_list); - if (!i915_seqno_passed(seqno, obj->last_rendering_seqno)) + if (!i915_seqno_passed(seqno, obj->last_read_seqno)) break; if (obj->base.write_domain != 0) @@ -2036,9 +2036,11 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno) * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. */ -int -i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj) +static __must_check int +i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, + bool readonly) { + u32 seqno; int ret; /* This function only exists to support waiting for existing rendering, @@ -2049,13 +2051,27 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj) /* If there is rendering queued on the buffer being evicted, wait for * it. */ - if (obj->active) { - ret = i915_wait_seqno(obj->ring, obj->last_rendering_seqno); - if (ret) - return ret; - i915_gem_retire_requests_ring(obj->ring); + if (readonly) + seqno = obj->last_write_seqno; + else + seqno = obj->last_read_seqno; + if (seqno == 0) + return 0; + + ret = i915_wait_seqno(obj->ring, seqno); + if (ret) + return ret; + + /* Manually manage the write flush as we may have not yet retired + * the buffer. + */ + if (obj->last_write_seqno && + i915_seqno_passed(seqno, obj->last_write_seqno)) { + obj->last_write_seqno = 0; + obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; } + i915_gem_retire_requests_ring(obj->ring); return 0; } @@ -2074,10 +2090,10 @@ i915_gem_object_flush_active(struct drm_i915_gem_object *obj) if (ret) return ret; - ret = i915_gem_check_olr(obj->ring, - obj->last_rendering_seqno); + ret = i915_gem_check_olr(obj->ring, obj->last_read_seqno); if (ret) return ret; + i915_gem_retire_requests_ring(obj->ring); } @@ -2137,7 +2153,7 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) goto out; if (obj->active) { - seqno = obj->last_rendering_seqno; + seqno = obj->last_read_seqno; ring = obj->ring; } @@ -2192,11 +2208,11 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, return 0; if (to == NULL || !i915_semaphore_is_enabled(obj->base.dev)) - return i915_gem_object_wait_rendering(obj); + return i915_gem_object_wait_rendering(obj, false); idx = intel_ring_sync_index(from, to); - seqno = obj->last_rendering_seqno; + seqno = obj->last_read_seqno; if (seqno <= from->sync_seqno[idx]) return 0; @@ -2940,11 +2956,9 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) if (ret) return ret; - if (obj->pending_gpu_write || write) { - ret = i915_gem_object_wait_rendering(obj); - if (ret) - return ret; - } + ret = i915_gem_object_wait_rendering(obj, !write); + if (ret) + return ret; i915_gem_object_flush_cpu_write_domain(obj); @@ -3115,7 +3129,7 @@ i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj) return ret; } - ret = i915_gem_object_wait_rendering(obj); + ret = i915_gem_object_wait_rendering(obj, false); if (ret) return ret; @@ -3143,11 +3157,9 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) if (ret) return ret; - if (write || obj->pending_gpu_write) { - ret = i915_gem_object_wait_rendering(obj); - if (ret) - return ret; - } + ret = i915_gem_object_wait_rendering(obj, !write); + if (ret) + return ret; i915_gem_object_flush_gtt_write_domain(obj); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index f94ec574db2b..2353e6ee2f0d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -954,7 +954,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, i915_gem_object_move_to_active(obj, ring, seqno); if (obj->base.write_domain) { obj->dirty = 1; - obj->pending_gpu_write = true; + obj->last_write_seqno = seqno; list_move_tail(&obj->gpu_write_list, &ring->gpu_write_list); if (obj->pin_count) /* check for potential scanout */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 566f61b9e47c..41ed41d70472 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -950,7 +950,8 @@ static void capture_bo(struct drm_i915_error_buffer *err, { err->size = obj->base.size; err->name = obj->base.name; - err->seqno = obj->last_rendering_seqno; + err->rseqno = obj->last_read_seqno; + err->wseqno = obj->last_write_seqno; err->gtt_offset = obj->gtt_offset; err->read_domains = obj->base.read_domains; err->write_domain = obj->base.write_domain; @@ -1045,7 +1046,7 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv, if (obj->ring != ring) continue; - if (i915_seqno_passed(seqno, obj->last_rendering_seqno)) + if (i915_seqno_passed(seqno, obj->last_read_seqno)) continue; if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0) From 65ce3027415d4dc9ee18ef0a135214b4fb76730b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Jul 2012 12:41:02 +0100 Subject: [PATCH 0108/5375] drm/i915: Remove the defunct flushing list As we guarantee to emit a flush before emitting the breadcrumb or the next batchbuffer, there is no further need for the flushing list. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 7 ---- drivers/gpu/drm/i915/i915_drv.h | 19 ++------- drivers/gpu/drm/i915/i915_gem.c | 59 +++++---------------------- drivers/gpu/drm/i915/i915_gem_evict.c | 20 --------- 4 files changed, 14 insertions(+), 91 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a8b7db6161ca..1312b79c70b3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -44,7 +44,6 @@ enum { ACTIVE_LIST, - FLUSHING_LIST, INACTIVE_LIST, PINNED_LIST, }; @@ -178,10 +177,6 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) seq_printf(m, "Inactive:\n"); head = &dev_priv->mm.inactive_list; break; - case FLUSHING_LIST: - seq_printf(m, "Flushing:\n"); - head = &dev_priv->mm.flushing_list; - break; default: mutex_unlock(&dev->struct_mutex); return -EINVAL; @@ -239,7 +234,6 @@ static int i915_gem_object_info(struct seq_file *m, void* data) size = count = mappable_size = mappable_count = 0; count_objects(&dev_priv->mm.active_list, mm_list); - count_objects(&dev_priv->mm.flushing_list, mm_list); seq_printf(m, " %u [%u] active objects, %zu [%zu] bytes\n", count, mappable_count, size, mappable_size); @@ -2007,7 +2001,6 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_gem_gtt", i915_gem_gtt_info, 0}, {"i915_gem_pinned", i915_gem_gtt_info, 0, (void *) PINNED_LIST}, {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, - {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST}, {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST}, {"i915_gem_pageflip", i915_gem_pageflip_info, 0}, {"i915_gem_request", i915_gem_request_info, 0}, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 49a532e338e6..6b91755f7743 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -695,17 +695,6 @@ typedef struct drm_i915_private { */ struct list_head active_list; - /** - * List of objects which are not in the ringbuffer but which - * still have a write_domain which needs to be flushed before - * unbinding. - * - * last_rendering_seqno is 0 while an object is in this list. - * - * A reference is held on the buffer while on this list. - */ - struct list_head flushing_list; - /** * LRU list of objects which are not in the ringbuffer and * are ready to unbind, but are still in the GTT. @@ -873,7 +862,7 @@ struct drm_i915_gem_object { struct drm_mm_node *gtt_space; struct list_head gtt_list; - /** This object's place on the active/flushing/inactive lists */ + /** This object's place on the active/inactive lists */ struct list_head ring_list; struct list_head mm_list; /** This object's place on GPU write list */ @@ -882,9 +871,9 @@ struct drm_i915_gem_object { struct list_head exec_list; /** - * This is set if the object is on the active or flushing lists - * (has pending rendering), and is not set if it's on inactive (ready - * to be unbound). + * This is set if the object is on the active lists (has pending + * rendering and so a non-zero seqno), and is not set if it i s on + * inactive (ready to be unbound) list. */ unsigned int active:1; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6a80d6565ef2..f62dd298a65d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1457,27 +1457,6 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, } } -static void -i915_gem_object_move_off_active(struct drm_i915_gem_object *obj) -{ - list_del_init(&obj->ring_list); - obj->last_read_seqno = 0; - obj->last_write_seqno = 0; - obj->last_fenced_seqno = 0; -} - -static void -i915_gem_object_move_to_flushing(struct drm_i915_gem_object *obj) -{ - struct drm_device *dev = obj->base.dev; - drm_i915_private_t *dev_priv = dev->dev_private; - - BUG_ON(!obj->active); - list_move_tail(&obj->mm_list, &dev_priv->mm.flushing_list); - - i915_gem_object_move_off_active(obj); -} - static void i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) { @@ -1487,10 +1466,17 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); BUG_ON(!list_empty(&obj->gpu_write_list)); + BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS); BUG_ON(!obj->active); + + list_del_init(&obj->ring_list); obj->ring = NULL; - i915_gem_object_move_off_active(obj); + obj->last_read_seqno = 0; + obj->last_write_seqno = 0; + obj->base.write_domain = 0; + + obj->last_fenced_seqno = 0; obj->fenced_gpu_access = false; obj->active = 0; @@ -1694,7 +1680,6 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, struct drm_i915_gem_object, ring_list); - obj->base.write_domain = 0; list_del_init(&obj->gpu_write_list); i915_gem_object_move_to_inactive(obj); } @@ -1731,20 +1716,6 @@ void i915_gem_reset(struct drm_device *dev) for_each_ring(ring, dev_priv, i) i915_gem_reset_ring_lists(dev_priv, ring); - /* Remove anything from the flushing lists. The GPU cache is likely - * to be lost on reset along with the data, so simply move the - * lost bo to the inactive list. - */ - while (!list_empty(&dev_priv->mm.flushing_list)) { - obj = list_first_entry(&dev_priv->mm.flushing_list, - struct drm_i915_gem_object, - mm_list); - - obj->base.write_domain = 0; - list_del_init(&obj->gpu_write_list); - i915_gem_object_move_to_inactive(obj); - } - /* Move everything out of the GPU domains to ensure we do any * necessary invalidation upon reuse. */ @@ -1815,10 +1786,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) if (!i915_seqno_passed(seqno, obj->last_read_seqno)) break; - if (obj->base.write_domain != 0) - i915_gem_object_move_to_flushing(obj); - else - i915_gem_object_move_to_inactive(obj); + i915_gem_object_move_to_inactive(obj); } if (unlikely(ring->trace_irq_seqno && @@ -3897,7 +3865,6 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, } BUG_ON(!list_empty(&dev_priv->mm.active_list)); - BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); BUG_ON(!list_empty(&dev_priv->mm.inactive_list)); mutex_unlock(&dev->struct_mutex); @@ -3955,7 +3922,6 @@ i915_gem_load(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; INIT_LIST_HEAD(&dev_priv->mm.active_list); - INIT_LIST_HEAD(&dev_priv->mm.flushing_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list); INIT_LIST_HEAD(&dev_priv->mm.gtt_list); @@ -4206,12 +4172,7 @@ static int i915_gpu_is_active(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - int lists_empty; - - lists_empty = list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->mm.active_list); - - return !lists_empty; + return !list_empty(&dev_priv->mm.active_list); } static int diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index eba0308f10e3..51e547c4ed89 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -93,23 +93,6 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, /* Now merge in the soon-to-be-expired objects... */ list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { - /* Does the object require an outstanding flush? */ - if (obj->base.write_domain) - continue; - - if (mark_free(obj, &unwind_list)) - goto found; - } - - /* Finally add anything with a pending flush (in order of retirement) */ - list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) { - if (mark_free(obj, &unwind_list)) - goto found; - } - list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) { - if (!obj->base.write_domain) - continue; - if (mark_free(obj, &unwind_list)) goto found; } @@ -172,7 +155,6 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only) int ret; lists_empty = (list_empty(&dev_priv->mm.inactive_list) && - list_empty(&dev_priv->mm.flushing_list) && list_empty(&dev_priv->mm.active_list)); if (lists_empty) return -ENOSPC; @@ -189,8 +171,6 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only) i915_gem_retire_requests(dev); - BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); - /* Having flushed everything, unbind() should never raise an error */ list_for_each_entry_safe(obj, next, &dev_priv->mm.inactive_list, mm_list) { From 69c2fc891343cb5217c866d10709343cff190bdc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Jul 2012 12:41:03 +0100 Subject: [PATCH 0109/5375] drm/i915: Remove the per-ring write list This is now handled by a global flag to ensure we emit a flush before the next serialisation point (if we failed to queue one previously). Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 - drivers/gpu/drm/i915/i915_gem.c | 53 +--------------------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 7 +-- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 - drivers/gpu/drm/i915/intel_ringbuffer.h | 9 ---- 5 files changed, 3 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6b91755f7743..59e3199da162 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -865,8 +865,6 @@ struct drm_i915_gem_object { /** This object's place on the active/inactive lists */ struct list_head ring_list; struct list_head mm_list; - /** This object's place on GPU write list */ - struct list_head gpu_write_list; /** This object's place in the batchbuffer or on the eviction list */ struct list_head exec_list; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f62dd298a65d..78fa9503a34d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1465,7 +1465,6 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - BUG_ON(!list_empty(&obj->gpu_write_list)); BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS); BUG_ON(!obj->active); @@ -1511,30 +1510,6 @@ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj) return obj->madv == I915_MADV_DONTNEED; } -static void -i915_gem_process_flushing_list(struct intel_ring_buffer *ring, - uint32_t flush_domains) -{ - struct drm_i915_gem_object *obj, *next; - - list_for_each_entry_safe(obj, next, - &ring->gpu_write_list, - gpu_write_list) { - if (obj->base.write_domain & flush_domains) { - uint32_t old_write_domain = obj->base.write_domain; - - obj->base.write_domain = 0; - list_del_init(&obj->gpu_write_list); - i915_gem_object_move_to_active(obj, ring, - i915_gem_next_request_seqno(ring)); - - trace_i915_gem_object_change_domain(obj, - obj->base.read_domains, - old_write_domain); - } - } -} - static u32 i915_gem_get_seqno(struct drm_device *dev) { @@ -1637,8 +1612,6 @@ i915_add_request(struct intel_ring_buffer *ring, &dev_priv->mm.retire_work, HZ); } - WARN_ON(!list_empty(&ring->gpu_write_list)); - return 0; } @@ -1680,7 +1653,6 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, struct drm_i915_gem_object, ring_list); - list_del_init(&obj->gpu_write_list); i915_gem_object_move_to_inactive(obj); } } @@ -2011,11 +1983,6 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, u32 seqno; int ret; - /* This function only exists to support waiting for existing rendering, - * not for emitting required flushes. - */ - BUG_ON((obj->base.write_domain & I915_GEM_GPU_DOMAINS) != 0); - /* If there is rendering queued on the buffer being evicted, wait for * it. */ @@ -2308,26 +2275,14 @@ i915_gem_flush_ring(struct intel_ring_buffer *ring, if (ret) return ret; - if (flush_domains & I915_GEM_GPU_DOMAINS) - i915_gem_process_flushing_list(ring, flush_domains); - return 0; } static int i915_ring_idle(struct intel_ring_buffer *ring) { - int ret; - - if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list)) + if (list_empty(&ring->active_list)) return 0; - if (!list_empty(&ring->gpu_write_list)) { - ret = i915_gem_flush_ring(ring, - I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - if (ret) - return ret; - } - return i915_wait_seqno(ring, i915_gem_next_request_seqno(ring)); } @@ -2343,10 +2298,6 @@ int i915_gpu_idle(struct drm_device *dev) if (ret) return ret; - /* Is the device fubar? */ - if (WARN_ON(!list_empty(&ring->gpu_write_list))) - return -EBUSY; - ret = i915_switch_context(ring, NULL, DEFAULT_CONTEXT_ID); if (ret) return ret; @@ -3491,7 +3442,6 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, INIT_LIST_HEAD(&obj->gtt_list); INIT_LIST_HEAD(&obj->ring_list); INIT_LIST_HEAD(&obj->exec_list); - INIT_LIST_HEAD(&obj->gpu_write_list); obj->madv = I915_MADV_WILLNEED; /* Avoid an unnecessary call to unbind on the first bind. */ obj->map_and_fenceable = true; @@ -3912,7 +3862,6 @@ init_ring_lists(struct intel_ring_buffer *ring) { INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); - INIT_LIST_HEAD(&ring->gpu_write_list); } void diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 2353e6ee2f0d..36c940c1a978 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -943,9 +943,8 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, struct drm_i915_gem_object *obj; list_for_each_entry(obj, objects, exec_list) { - u32 old_read = obj->base.read_domains; - u32 old_write = obj->base.write_domain; - + u32 old_read = obj->base.read_domains; + u32 old_write = obj->base.write_domain; obj->base.read_domains = obj->base.pending_read_domains; obj->base.write_domain = obj->base.pending_write_domain; @@ -955,8 +954,6 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, if (obj->base.write_domain) { obj->dirty = 1; obj->last_write_seqno = seqno; - list_move_tail(&obj->gpu_write_list, - &ring->gpu_write_list); if (obj->pin_count) /* check for potential scanout */ intel_mark_busy(ring->dev, obj); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index bf0195a96d53..8f221d9a7bdb 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1002,7 +1002,6 @@ static int intel_init_ring_buffer(struct drm_device *dev, ring->dev = dev; INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); - INIT_LIST_HEAD(&ring->gpu_write_list); ring->size = 32 * PAGE_SIZE; init_waitqueue_head(&ring->irq_queue); @@ -1473,7 +1472,6 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->dev = dev; INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); - INIT_LIST_HEAD(&ring->gpu_write_list); ring->size = size; ring->effective_size = ring->size; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 1d3c81fdad92..7986f3001cf0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -100,15 +100,6 @@ struct intel_ring_buffer { */ struct list_head request_list; - /** - * List of objects currently pending a GPU write flush. - * - * All elements on this list will belong to either the - * active_list or flushing_list, last_rendering_seqno can - * be used to differentiate between the two elements. - */ - struct list_head gpu_write_list; - /** * Do we have some not yet emitted requests outstanding? */ From 86d5bc37824f169a03d03bcc47259e82136d6a34 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Jul 2012 12:41:04 +0100 Subject: [PATCH 0110/5375] drm/i915: Remove explicit flush from i915_gem_object_flush_fence() As the flush is either performed explictly immediately after the execbuffer dispatch, or before the serialisation of last_fenced_seqno we can forgo the explict i915_gem_flush_ring(). Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 78fa9503a34d..feb3498cd00f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2473,21 +2473,8 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, static int i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) { - int ret; - - 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->last_fenced_seqno) { - ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno); + int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno); if (ret) return ret; @@ -2500,6 +2487,7 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) if (obj->base.read_domains & I915_GEM_DOMAIN_GTT) mb(); + obj->fenced_gpu_access = false; return 0; } From 26b9c4a57fc3ff0ae6032548870bebfa5cd0de3d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Jul 2012 12:41:05 +0100 Subject: [PATCH 0111/5375] drm/i915: Remove the explicit flush of the GPU write domain Rely instead on the insertion of the implicit flush before the seqno breadcrumb. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 34 --------------------------------- 1 file changed, 34 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index feb3498cd00f..3659d47a9f6e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -37,7 +37,6 @@ #include #include -static __must_check int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj); static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj); static __must_check int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, @@ -2021,10 +2020,6 @@ i915_gem_object_flush_active(struct drm_i915_gem_object *obj) int ret; if (obj->active) { - ret = i915_gem_object_flush_gpu_write_domain(obj); - if (ret) - return ret; - ret = i915_gem_check_olr(obj->ring, obj->last_read_seqno); if (ret) return ret; @@ -2782,17 +2777,6 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj) drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE); } -/** Flushes any GPU write domain for the object if it's dirty. */ -static int -i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj) -{ - if ((obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0) - return 0; - - /* Queue the GPU write cache flushing we need. */ - return i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain); -} - /** Flushes the GTT write domain for the object if it's dirty. */ static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj) @@ -2859,10 +2843,6 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) if (obj->base.write_domain == I915_GEM_DOMAIN_GTT) return 0; - ret = i915_gem_object_flush_gpu_write_domain(obj); - if (ret) - return ret; - ret = i915_gem_object_wait_rendering(obj, !write); if (ret) return ret; @@ -2973,10 +2953,6 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, u32 old_read_domains, old_write_domain; int ret; - ret = i915_gem_object_flush_gpu_write_domain(obj); - if (ret) - return ret; - if (pipelined != obj->ring) { ret = i915_gem_object_sync(obj, pipelined); if (ret) @@ -3030,12 +3006,6 @@ i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj) if ((obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0) return 0; - 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; - } - ret = i915_gem_object_wait_rendering(obj, false); if (ret) return ret; @@ -3060,10 +3030,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) return 0; - ret = i915_gem_object_flush_gpu_write_domain(obj); - if (ret) - return ret; - ret = i915_gem_object_wait_rendering(obj, !write); if (ret) return ret; From 6ac42f4148bc27e5ffd18a9ab0eac57f58822af4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 21 Jul 2012 12:25:01 +0200 Subject: [PATCH 0112/5375] drm/i915: Replace the complex flushing logic with simple invalidate/flush all Now that we unconditionally flush and invalidate between every batch buffer, we no longer need the complex logic to decide which domains require flushing. Remove it and rejoice. v2 (danvet): Keep around the flip waiting logic. It's gross and broken, I know, but we can't just kill that thing ... even if we just keep it around as a reminder that things are broken. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 226 ++------------------- 1 file changed, 22 insertions(+), 204 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 36c940c1a978..6c810798de92 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -34,180 +34,6 @@ #include "intel_drv.h" #include -struct change_domains { - uint32_t invalidate_domains; - uint32_t flush_domains; - uint32_t flush_rings; - uint32_t flips; -}; - -/* - * Set the next domain for the specified object. This - * may not actually perform the necessary flushing/invaliding though, - * as that may want to be batched with other set_domain operations - * - * This is (we hope) the only really tricky part of gem. The goal - * is fairly simple -- track which caches hold bits of the object - * and make sure they remain coherent. A few concrete examples may - * help to explain how it works. For shorthand, we use the notation - * (read_domains, write_domain), e.g. (CPU, CPU) to indicate the - * a pair of read and write domain masks. - * - * Case 1: the batch buffer - * - * 1. Allocated - * 2. Written by CPU - * 3. Mapped to GTT - * 4. Read by GPU - * 5. Unmapped from GTT - * 6. Freed - * - * Let's take these a step at a time - * - * 1. Allocated - * Pages allocated from the kernel may still have - * cache contents, so we set them to (CPU, CPU) always. - * 2. Written by CPU (using pwrite) - * The pwrite function calls set_domain (CPU, CPU) and - * this function does nothing (as nothing changes) - * 3. Mapped by GTT - * This function asserts that the object is not - * currently in any GPU-based read or write domains - * 4. Read by GPU - * i915_gem_execbuffer calls set_domain (COMMAND, 0). - * As write_domain is zero, this function adds in the - * current read domains (CPU+COMMAND, 0). - * flush_domains is set to CPU. - * invalidate_domains is set to COMMAND - * clflush is run to get data out of the CPU caches - * then i915_dev_set_domain calls i915_gem_flush to - * emit an MI_FLUSH and drm_agp_chipset_flush - * 5. Unmapped from GTT - * i915_gem_object_unbind calls set_domain (CPU, CPU) - * flush_domains and invalidate_domains end up both zero - * so no flushing/invalidating happens - * 6. Freed - * yay, done - * - * Case 2: The shared render buffer - * - * 1. Allocated - * 2. Mapped to GTT - * 3. Read/written by GPU - * 4. set_domain to (CPU,CPU) - * 5. Read/written by CPU - * 6. Read/written by GPU - * - * 1. Allocated - * Same as last example, (CPU, CPU) - * 2. Mapped to GTT - * Nothing changes (assertions find that it is not in the GPU) - * 3. Read/written by GPU - * execbuffer calls set_domain (RENDER, RENDER) - * flush_domains gets CPU - * invalidate_domains gets GPU - * clflush (obj) - * MI_FLUSH and drm_agp_chipset_flush - * 4. set_domain (CPU, CPU) - * flush_domains gets GPU - * invalidate_domains gets CPU - * wait_rendering (obj) to make sure all drawing is complete. - * This will include an MI_FLUSH to get the data from GPU - * to memory - * clflush (obj) to invalidate the CPU cache - * Another MI_FLUSH in i915_gem_flush (eliminate this somehow?) - * 5. Read/written by CPU - * cache lines are loaded and dirtied - * 6. Read written by GPU - * Same as last GPU access - * - * Case 3: The constant buffer - * - * 1. Allocated - * 2. Written by CPU - * 3. Read by GPU - * 4. Updated (written) by CPU again - * 5. Read by GPU - * - * 1. Allocated - * (CPU, CPU) - * 2. Written by CPU - * (CPU, CPU) - * 3. Read by GPU - * (CPU+RENDER, 0) - * flush_domains = CPU - * invalidate_domains = RENDER - * clflush (obj) - * MI_FLUSH - * drm_agp_chipset_flush - * 4. Updated (written) by CPU again - * (CPU, CPU) - * flush_domains = 0 (no previous write domain) - * invalidate_domains = 0 (no new read domains) - * 5. Read by GPU - * (CPU+RENDER, 0) - * flush_domains = CPU - * invalidate_domains = RENDER - * clflush (obj) - * MI_FLUSH - * drm_agp_chipset_flush - */ -static void -i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *ring, - struct change_domains *cd) -{ - uint32_t invalidate_domains = 0, flush_domains = 0; - - /* - * If the object isn't moving to a new write domain, - * let the object stay in multiple read domains - */ - if (obj->base.pending_write_domain == 0) - obj->base.pending_read_domains |= obj->base.read_domains; - - /* - * Flush the current write domain if - * the new read domains don't match. Invalidate - * any read domains which differ from the old - * write domain - */ - if (obj->base.write_domain && - (((obj->base.write_domain != obj->base.pending_read_domains || - obj->ring != ring)) || - (obj->fenced_gpu_access && !obj->pending_fenced_gpu_access))) { - flush_domains |= obj->base.write_domain; - invalidate_domains |= - obj->base.pending_read_domains & ~obj->base.write_domain; - } - /* - * Invalidate any read caches which may have - * stale data. That is, any new read domains. - */ - invalidate_domains |= obj->base.pending_read_domains & ~obj->base.read_domains; - if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) - i915_gem_clflush_object(obj); - - if (obj->base.pending_write_domain) - cd->flips |= atomic_read(&obj->pending_flip); - - /* The actual obj->write_domain will be updated with - * pending_write_domain after we emit the accumulated flush for all - * of our domain changes in execbuffers (which clears objects' - * write_domains). So if we have a current write domain that we - * aren't changing, set pending_write_domain to that. - */ - if (flush_domains == 0 && obj->base.pending_write_domain == 0) - obj->base.pending_write_domain = obj->base.write_domain; - - cd->invalidate_domains |= invalidate_domains; - cd->flush_domains |= flush_domains; - if (flush_domains & I915_GEM_GPU_DOMAINS) - cd->flush_rings |= intel_ring_flag(obj->ring); - if (invalidate_domains & I915_GEM_GPU_DOMAINS) - cd->flush_rings |= intel_ring_flag(ring); -} - struct eb_objects { int and; struct hlist_head buckets[0]; @@ -810,18 +636,6 @@ err: return ret; } -static void -i915_gem_execbuffer_flush(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains) -{ - if (flush_domains & I915_GEM_DOMAIN_CPU) - intel_gtt_chipset_flush(); - - if (flush_domains & I915_GEM_DOMAIN_GTT) - wmb(); -} - static int i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips) { @@ -854,37 +668,41 @@ i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips) return 0; } - static int i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, struct list_head *objects) { struct drm_i915_gem_object *obj; - struct change_domains cd; + uint32_t flush_domains = 0; + uint32_t flips = 0; int ret; - memset(&cd, 0, sizeof(cd)); - list_for_each_entry(obj, objects, exec_list) - i915_gem_object_set_to_gpu_domain(obj, ring, &cd); - - if (cd.invalidate_domains | cd.flush_domains) { - i915_gem_execbuffer_flush(ring->dev, - cd.invalidate_domains, - cd.flush_domains); - } - - if (cd.flips) { - ret = i915_gem_execbuffer_wait_for_flips(ring, cd.flips); - if (ret) - return ret; - } - list_for_each_entry(obj, objects, exec_list) { ret = i915_gem_object_sync(obj, ring); if (ret) return ret; + + if (obj->base.write_domain & I915_GEM_DOMAIN_CPU) + i915_gem_clflush_object(obj); + + if (obj->base.pending_write_domain) + flips |= atomic_read(&obj->pending_flip); + + flush_domains |= obj->base.write_domain; } + if (flips) { + ret = i915_gem_execbuffer_wait_for_flips(ring, flips); + if (ret) + return ret; + } + + if (flush_domains & I915_GEM_DOMAIN_CPU) + intel_gtt_chipset_flush(); + + if (flush_domains & I915_GEM_DOMAIN_GTT) + wmb(); + /* Unconditionally invalidate gpu caches and ensure that we do flush * any residual writes from the previous batch. */ From 016fd0c1aee31902d82c1ac32312f1cc32298b66 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Jul 2012 12:41:07 +0100 Subject: [PATCH 0113/5375] drm/i915: Clear the pending_gpu_fenced_access flag at the start of execbuffer Otherwise once we use the buffer with a BLT command on gen2/3, we will always regard future command submissions as continuing the fenced access. However, now that we flush/invalidate between every batch we can drop this pessimism. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6c810798de92..55a94c1a1f59 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -413,6 +413,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, obj->base.pending_read_domains = 0; obj->base.pending_write_domain = 0; + obj->pending_fenced_gpu_access = false; } list_splice(&ordered_objects, objects); From a7b9761d0a2ded58170ffb4d423ff3d7228103f4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Jul 2012 12:41:08 +0100 Subject: [PATCH 0114/5375] drm/i915: Split i915_gem_flush_ring() into seperate invalidate/flush funcs By moving the function to intel_ringbuffer and currying the appropriate parameter, hopefully we make the callsites easier to read and understand. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 -- drivers/gpu/drm/i915/i915_gem.c | 29 ++--------------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 9 +---- drivers/gpu/drm/i915/intel_ringbuffer.c | 38 ++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.h | 2 ++ 5 files changed, 44 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 59e3199da162..700dc838c57f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1256,9 +1256,6 @@ int i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_load(struct drm_device *dev); int i915_gem_init_object(struct drm_gem_object *obj); -int __must_check i915_gem_flush_ring(struct intel_ring_buffer *ring, - uint32_t invalidate_domains, - uint32_t flush_domains); struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, size_t size); void i915_gem_free_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3659d47a9f6e..f26e2b201bad 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1549,13 +1549,9 @@ i915_add_request(struct intel_ring_buffer *ring, * is that the flush _must_ happen before the next request, no matter * what. */ - if (ring->gpu_caches_dirty) { - ret = i915_gem_flush_ring(ring, 0, I915_GEM_GPU_DOMAINS); - if (ret) - return ret; - - ring->gpu_caches_dirty = false; - } + ret = intel_ring_flush_all_caches(ring); + if (ret) + return ret; if (request == NULL) { request = kmalloc(sizeof(*request), GFP_KERNEL); @@ -2254,25 +2250,6 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) return ret; } -int -i915_gem_flush_ring(struct intel_ring_buffer *ring, - uint32_t invalidate_domains, - uint32_t flush_domains) -{ - 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; - - return 0; -} - static int i915_ring_idle(struct intel_ring_buffer *ring) { if (list_empty(&ring->active_list)) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 55a94c1a1f59..6be1a8920a84 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -707,14 +707,7 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, /* Unconditionally invalidate gpu caches and ensure that we do flush * any residual writes from the previous batch. */ - ret = i915_gem_flush_ring(ring, - I915_GEM_GPU_DOMAINS, - ring->gpu_caches_dirty ? I915_GEM_GPU_DOMAINS : 0); - if (ret) - return ret; - - ring->gpu_caches_dirty = false; - return 0; + return intel_ring_invalidate_all_caches(ring); } static bool diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 8f221d9a7bdb..8b7085e4cf84 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1564,3 +1564,41 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) return intel_init_ring_buffer(dev, ring); } + +int +intel_ring_flush_all_caches(struct intel_ring_buffer *ring) +{ + int ret; + + if (!ring->gpu_caches_dirty) + return 0; + + ret = ring->flush(ring, 0, I915_GEM_GPU_DOMAINS); + if (ret) + return ret; + + trace_i915_gem_ring_flush(ring, 0, I915_GEM_GPU_DOMAINS); + + ring->gpu_caches_dirty = false; + return 0; +} + +int +intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring) +{ + uint32_t flush_domains; + int ret; + + flush_domains = 0; + if (ring->gpu_caches_dirty) + flush_domains = I915_GEM_GPU_DOMAINS; + + ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, flush_domains); + if (ret) + return ret; + + trace_i915_gem_ring_flush(ring, I915_GEM_GPU_DOMAINS, flush_domains); + + ring->gpu_caches_dirty = false; + return 0; +} diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 7986f3001cf0..8b2b92e00e9d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -195,6 +195,8 @@ static inline void intel_ring_emit(struct intel_ring_buffer *ring, void intel_ring_advance(struct intel_ring_buffer *ring); u32 intel_ring_get_seqno(struct intel_ring_buffer *ring); +int intel_ring_flush_all_caches(struct intel_ring_buffer *ring); +int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring); int intel_init_render_ring_buffer(struct drm_device *dev); int intel_init_bsd_ring_buffer(struct drm_device *dev); From f047e395ddc9da6c307a10629a237502e627ed85 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 21 Jul 2012 12:31:41 +0100 Subject: [PATCH 0115/5375] drm/i915: Avoid concurrent access when marking the device as idle/busy As suggested by Daniel, rip out the independent timers for device and crtc busyness and integrate the manual powermanagement of the display engine into the GEM core and its request tracking. The benefits are that the code is a lot smaller, fewer moving parts and should fit more neatly into the overall activity tracking of the driver. v2: Complete overhaul and removal of the racy timers and workers. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 - drivers/gpu/drm/i915/i915_gem.c | 13 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 +- drivers/gpu/drm/i915/intel_display.c | 146 ++++----------------- drivers/gpu/drm/i915/intel_drv.h | 8 +- drivers/gpu/drm/i915/intel_pm.c | 5 +- 6 files changed, 41 insertions(+), 138 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 700dc838c57f..f1765893da60 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -785,9 +785,6 @@ typedef struct drm_i915_private { bool lvds_downclock_avail; /* indicates the reduced downclock for LVDS*/ int lvds_downclock; - struct work_struct idle_work; - struct timer_list idle_timer; - bool busy; u16 orig_clock; int child_dev_num; struct child_device_config *child_dev; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f26e2b201bad..b274810eaeab 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1462,11 +1462,14 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); - BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS); BUG_ON(!obj->active); + if (obj->pin_count) /* are we a framebuffer? */ + intel_mark_fb_idle(obj); + + list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list); + list_del_init(&obj->ring_list); obj->ring = NULL; @@ -1602,9 +1605,11 @@ i915_add_request(struct intel_ring_buffer *ring, jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); } - if (was_empty) + if (was_empty) { queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); + intel_mark_busy(dev_priv->dev); + } } return 0; @@ -1810,6 +1815,8 @@ i915_gem_retire_work_handler(struct work_struct *work) if (!dev_priv->mm.suspended && !idle) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); + if (idle) + intel_mark_idle(dev); mutex_unlock(&dev->struct_mutex); } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6be1a8920a84..25b2c54e1261 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -767,13 +767,11 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, obj->dirty = 1; obj->last_write_seqno = seqno; if (obj->pin_count) /* check for potential scanout */ - intel_mark_busy(ring->dev, obj); + intel_mark_fb_busy(obj); } trace_i915_gem_object_change_domain(obj, old_read, old_write); } - - intel_mark_busy(ring->dev, NULL); } static void diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 93d9934ba328..b463829b92eb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5860,46 +5860,6 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, return mode; } -#define GPU_IDLE_TIMEOUT 500 /* ms */ - -/* When this timer fires, we've been idle for awhile */ -static void intel_gpu_idle_timer(unsigned long arg) -{ - struct drm_device *dev = (struct drm_device *)arg; - drm_i915_private_t *dev_priv = dev->dev_private; - - if (!list_empty(&dev_priv->mm.active_list)) { - /* Still processing requests, so just re-arm the timer. */ - mod_timer(&dev_priv->idle_timer, jiffies + - msecs_to_jiffies(GPU_IDLE_TIMEOUT)); - return; - } - - dev_priv->busy = false; - queue_work(dev_priv->wq, &dev_priv->idle_work); -} - -#define CRTC_IDLE_TIMEOUT 1000 /* ms */ - -static void intel_crtc_idle_timer(unsigned long arg) -{ - struct intel_crtc *intel_crtc = (struct intel_crtc *)arg; - struct drm_crtc *crtc = &intel_crtc->base; - drm_i915_private_t *dev_priv = crtc->dev->dev_private; - struct intel_framebuffer *intel_fb; - - intel_fb = to_intel_framebuffer(crtc->fb); - if (intel_fb && intel_fb->obj->active) { - /* The framebuffer is still being accessed by the GPU. */ - mod_timer(&intel_crtc->idle_timer, jiffies + - msecs_to_jiffies(CRTC_IDLE_TIMEOUT)); - return; - } - - intel_crtc->busy = false; - queue_work(dev_priv->wq, &dev_priv->idle_work); -} - static void intel_increase_pllclock(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -5929,10 +5889,6 @@ static void intel_increase_pllclock(struct drm_crtc *crtc) if (dpll & DISPLAY_RATE_SELECT_FPA1) DRM_DEBUG_DRIVER("failed to upclock LVDS!\n"); } - - /* Schedule downclock */ - mod_timer(&intel_crtc->idle_timer, jiffies + - msecs_to_jiffies(CRTC_IDLE_TIMEOUT)); } static void intel_decrease_pllclock(struct drm_crtc *crtc) @@ -5971,89 +5927,48 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc) } -/** - * intel_idle_update - adjust clocks for idleness - * @work: work struct - * - * Either the GPU or display (or both) went idle. Check the busy status - * here and adjust the CRTC and GPU clocks as necessary. - */ -static void intel_idle_update(struct work_struct *work) +void intel_mark_busy(struct drm_device *dev) { - drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, - idle_work); - struct drm_device *dev = dev_priv->dev; + intel_sanitize_pm(dev); + i915_update_gfx_val(dev->dev_private); +} + +void intel_mark_idle(struct drm_device *dev) +{ + intel_sanitize_pm(dev); +} + +void intel_mark_fb_busy(struct drm_i915_gem_object *obj) +{ + struct drm_device *dev = obj->base.dev; struct drm_crtc *crtc; - struct intel_crtc *intel_crtc; if (!i915_powersave) return; - mutex_lock(&dev->struct_mutex); - - i915_update_gfx_val(dev_priv); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - /* Skip inactive CRTCs */ if (!crtc->fb) continue; - intel_crtc = to_intel_crtc(crtc); - if (!intel_crtc->busy) - intel_decrease_pllclock(crtc); + if (to_intel_framebuffer(crtc->fb)->obj == obj) + intel_increase_pllclock(crtc); } - - - mutex_unlock(&dev->struct_mutex); } -/** - * intel_mark_busy - mark the GPU and possibly the display busy - * @dev: drm device - * @obj: object we're operating on - * - * Callers can use this function to indicate that the GPU is busy processing - * commands. If @obj matches one of the CRTC objects (i.e. it's a scanout - * buffer), we'll also mark the display as busy, so we know to increase its - * clock frequency. - */ -void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj) +void intel_mark_fb_idle(struct drm_i915_gem_object *obj) { - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_crtc *crtc = NULL; - struct intel_framebuffer *intel_fb; - struct intel_crtc *intel_crtc; + struct drm_device *dev = obj->base.dev; + struct drm_crtc *crtc; - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return; - - if (!dev_priv->busy) { - intel_sanitize_pm(dev); - dev_priv->busy = true; - } else - mod_timer(&dev_priv->idle_timer, jiffies + - msecs_to_jiffies(GPU_IDLE_TIMEOUT)); - - if (obj == NULL) + if (!i915_powersave) return; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (!crtc->fb) continue; - intel_crtc = to_intel_crtc(crtc); - intel_fb = to_intel_framebuffer(crtc->fb); - if (intel_fb->obj == obj) { - if (!intel_crtc->busy) { - /* Non-busy -> busy, upclock */ - intel_increase_pllclock(crtc); - intel_crtc->busy = true; - } else { - /* Busy -> busy, put off timer */ - mod_timer(&intel_crtc->idle_timer, jiffies + - msecs_to_jiffies(CRTC_IDLE_TIMEOUT)); - } - } + if (to_intel_framebuffer(crtc->fb)->obj == obj) + intel_decrease_pllclock(crtc); } } @@ -6512,7 +6427,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, goto cleanup_pending; intel_disable_fbc(dev); - intel_mark_busy(dev, obj); + intel_mark_fb_busy(obj); mutex_unlock(&dev->struct_mutex); trace_i915_flip_request(intel_crtc->plane, obj); @@ -6678,11 +6593,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) } drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); - - intel_crtc->busy = false; - - setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer, - (unsigned long)intel_crtc); } int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, @@ -7265,10 +7175,6 @@ void intel_modeset_init(struct drm_device *dev) /* Just disable it once at startup */ i915_disable_vga(dev); intel_setup_outputs(dev); - - INIT_WORK(&dev_priv->idle_work, intel_idle_update); - setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, - (unsigned long)dev); } void intel_modeset_gem_init(struct drm_device *dev) @@ -7319,14 +7225,6 @@ void intel_modeset_cleanup(struct drm_device *dev) /* flush any delayed tasks or pending work */ flush_scheduled_work(); - /* Shut off idle work before the crtcs get freed. */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - intel_crtc = to_intel_crtc(crtc); - del_timer_sync(&intel_crtc->idle_timer); - } - del_timer_sync(&dev_priv->idle_timer); - cancel_work_sync(&dev_priv->idle_work); - drm_mode_config_cleanup(dev); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2846f5e8cca3..8c7f48310842 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -156,8 +156,6 @@ struct intel_crtc { int dpms_mode; bool active; /* is the crtc on? independent of the dpms mode */ bool primary_disabled; /* is the crtc obscured by a plane? */ - bool busy; /* is scanout buffer being updated frequently? */ - struct timer_list idle_timer; bool lowfreq_avail; struct intel_overlay *overlay; struct intel_unpin_work *unpin_work; @@ -373,8 +371,10 @@ extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); -extern void intel_mark_busy(struct drm_device *dev, - struct drm_i915_gem_object *obj); +extern void intel_mark_busy(struct drm_device *dev); +extern void intel_mark_idle(struct drm_device *dev); +extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj); +extern void intel_mark_fb_idle(struct drm_i915_gem_object *obj); extern bool intel_lvds_init(struct drm_device *dev); extern void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 94aabcaa3a67..85d1b1c57df2 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3075,14 +3075,17 @@ EXPORT_SYMBOL_GPL(i915_gpu_lower); bool i915_gpu_busy(void) { struct drm_i915_private *dev_priv; + struct intel_ring_buffer *ring; bool ret = false; + int i; spin_lock(&mchdev_lock); if (!i915_mch_dev) goto out_unlock; dev_priv = i915_mch_dev; - ret = dev_priv->busy; + for_each_ring(ring, dev_priv, i) + ret |= !list_empty(&ring->request_list); out_unlock: spin_unlock(&mchdev_lock); From 2e4291e0bc6cff9514515a899a8158ea62b3ff90 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 24 Jul 2012 20:47:30 -0700 Subject: [PATCH 0116/5375] drm/i915: Add contexts for HSW Basic context support on HSW is no different than previous generations. The size of the context object changes, but that's about it. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 5 ++++- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 5d0d6ad489e2..5c2d354cebbd 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -112,7 +112,10 @@ static int get_context_size(struct drm_device *dev) break; case 7: reg = I915_READ(GEN7_CXT_SIZE); - ret = GEN7_CXT_TOTAL_SIZE(reg) * 64; + if (IS_HASWELL(dev)) + ret = HSW_CXT_TOTAL_SIZE(reg) * 64; + else + ret = GEN7_CXT_TOTAL_SIZE(reg) * 64; break; default: BUG(); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 81a3de6b093c..1310caaaafd6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1498,6 +1498,14 @@ GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \ GEN7_CXT_GT1_SIZE(ctx_reg) + \ GEN7_CXT_VFSTATE_SIZE(ctx_reg)) +#define HSW_CXT_POWER_SIZE(ctx_reg) ((ctx_reg >> 26) & 0x3f) +#define HSW_CXT_RING_SIZE(ctx_reg) ((ctx_reg >> 23) & 0x7) +#define HSW_CXT_RENDER_SIZE(ctx_reg) ((ctx_reg >> 15) & 0xff) +#define HSW_CXT_TOTAL_SIZE(ctx_reg) (HSW_CXT_POWER_SIZE(ctx_reg) + \ + HSW_CXT_RING_SIZE(ctx_reg) + \ + HSW_CXT_RENDER_SIZE(ctx_reg) + \ + GEN7_CXT_VFSTATE_SIZE(ctx_reg)) + /* * Overlay regs From e1ef7cc299839e68dae3f1843f62e52acda04538 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 24 Jul 2012 20:47:31 -0700 Subject: [PATCH 0117/5375] drm/i915: Macro to determine DPF support Originally I had a macro specifically for DPF support, and Daniel, with good reason asked me to change it to this. It's not the way I would have gone (and indeed I didn't), but for now there is no distinction as all platforms with L3 also have DPF. Note: The good reasons are that dpf is a l3$ feature (at least on currrent hw), hence I don't expect one to go without the other. Signed-off-by: Ben Widawsky [danvet: added note] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_irq.c | 2 +- drivers/gpu/drm/i915/i915_sysfs.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +++--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f1765893da60..35a90da64149 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1114,6 +1114,8 @@ struct drm_i915_file_private { #define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake) +#define HAS_L3_GPU_CACHE(dev) (IS_IVYBRIDGE(dev)) + #include "i915_trace.h" /** diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 41ed41d70472..440c9051aa9b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -444,7 +444,7 @@ static void ivybridge_handle_parity_error(struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long flags; - if (!IS_IVYBRIDGE(dev)) + if (!HAS_L3_GPU_CACHE(dev)) return; spin_lock_irqsave(&dev_priv->irq_lock, flags); diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 2f5388af8df9..77a97bfabb6b 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -212,7 +212,7 @@ void i915_setup_sysfs(struct drm_device *dev) DRM_ERROR("RC6 residency sysfs setup failed\n"); } - if (IS_IVYBRIDGE(dev)) { + if (HAS_L3_GPU_CACHE(dev)) { ret = device_create_bin_file(&dev->primary->kdev, &dpf_attrs); if (ret) DRM_ERROR("l3 parity sysfs setup failed\n"); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 8b7085e4cf84..c58f1b91d08b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -454,7 +454,7 @@ static int init_render_ring(struct intel_ring_buffer *ring) if (INTEL_INFO(dev)->gen >= 6) I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); - if (IS_IVYBRIDGE(dev)) + if (HAS_L3_GPU_CACHE(dev)) I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR); return ret; @@ -844,7 +844,7 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring) spin_lock_irqsave(&dev_priv->irq_lock, flags); if (ring->irq_refcount++ == 0) { - if (IS_IVYBRIDGE(dev) && ring->id == RCS) + if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS) I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | GEN6_RENDER_L3_PARITY_ERROR)); else @@ -867,7 +867,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) spin_lock_irqsave(&dev_priv->irq_lock, flags); if (--ring->irq_refcount == 0) { - if (IS_IVYBRIDGE(dev) && ring->id == RCS) + if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS) I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR); else I915_WRITE_IMR(ring, ~0); From f27b92651d72e863c308ea5dca5615fc98e38ca6 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 24 Jul 2012 20:47:32 -0700 Subject: [PATCH 0118/5375] drm/i915: Expand DPF support to Haswell Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 35a90da64149..e6e63c1aee68 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1114,7 +1114,7 @@ struct drm_i915_file_private { #define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake) -#define HAS_L3_GPU_CACHE(dev) (IS_IVYBRIDGE(dev)) +#define HAS_L3_GPU_CACHE(dev) (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) #include "i915_trace.h" From dbde5c2934d10f87cc45ed9a9b95cac6f0c0fdd2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 24 Jul 2012 11:00:55 +0300 Subject: [PATCH 0119/5375] dw_dmac: use devm_* functions to simplify code Use devm_kzalloc, devm_clk_get, devm_request_irq, and devm_request_and_ioremap to reduce the code and to simplify the error path. Signed-off-by: Andy Shevchenko Cc: Viresh Kumar Acked-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 53 +++++++------------------------------- drivers/dma/dw_dmac_regs.h | 2 -- 2 files changed, 10 insertions(+), 45 deletions(-) diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 57beb5c8e3fd..ed2c9499d3ea 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1392,26 +1392,17 @@ static int __devinit dw_probe(struct platform_device *pdev) size = sizeof(struct dw_dma); size += pdata->nr_channels * sizeof(struct dw_dma_chan); - dw = kzalloc(size, GFP_KERNEL); + dw = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (!dw) return -ENOMEM; - if (!request_mem_region(io->start, DW_REGLEN, pdev->dev.driver->name)) { - err = -EBUSY; - goto err_kfree; - } + dw->regs = devm_request_and_ioremap(&pdev->dev, io); + if (!dw->regs) + return -EBUSY; - dw->regs = ioremap(io->start, DW_REGLEN); - if (!dw->regs) { - err = -ENOMEM; - goto err_release_r; - } - - dw->clk = clk_get(&pdev->dev, "hclk"); - if (IS_ERR(dw->clk)) { - err = PTR_ERR(dw->clk); - goto err_clk; - } + dw->clk = devm_clk_get(&pdev->dev, "hclk"); + if (IS_ERR(dw->clk)) + return PTR_ERR(dw->clk); clk_prepare_enable(dw->clk); /* Calculate all channel mask before DMA setup */ @@ -1423,9 +1414,10 @@ static int __devinit dw_probe(struct platform_device *pdev) /* disable BLOCK interrupts as well */ channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask); - err = request_irq(irq, dw_dma_interrupt, 0, "dw_dmac", dw); + err = devm_request_irq(&pdev->dev, irq, dw_dma_interrupt, 0, + "dw_dmac", dw); if (err) - goto err_irq; + return err; platform_set_drvdata(pdev, dw); @@ -1491,30 +1483,16 @@ static int __devinit dw_probe(struct platform_device *pdev) dma_async_device_register(&dw->dma); return 0; - -err_irq: - clk_disable_unprepare(dw->clk); - clk_put(dw->clk); -err_clk: - iounmap(dw->regs); - dw->regs = NULL; -err_release_r: - release_resource(io); -err_kfree: - kfree(dw); - return err; } static int __devexit dw_remove(struct platform_device *pdev) { struct dw_dma *dw = platform_get_drvdata(pdev); struct dw_dma_chan *dwc, *_dwc; - struct resource *io; dw_dma_off(dw); dma_async_device_unregister(&dw->dma); - free_irq(platform_get_irq(pdev, 0), dw); tasklet_kill(&dw->tasklet); list_for_each_entry_safe(dwc, _dwc, &dw->dma.channels, @@ -1523,17 +1501,6 @@ static int __devexit dw_remove(struct platform_device *pdev) channel_clear_bit(dw, CH_EN, dwc->mask); } - clk_disable_unprepare(dw->clk); - clk_put(dw->clk); - - iounmap(dw->regs); - dw->regs = NULL; - - io = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(io->start, DW_REGLEN); - - kfree(dw); - return 0; } diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index 50830bee087a..f6d92d72ae40 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h @@ -140,8 +140,6 @@ struct dw_dma_regs { /* Bitfields in CFG */ #define DW_CFG_DMA_EN (1 << 0) -#define DW_REGLEN 0x400 - enum dw_dmac_flags { DW_DMA_IS_CYCLIC = 0, }; From 3b2bd2f800ba9488d9ad493216a0c07d71055b56 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 26 Jul 2012 11:57:43 +0800 Subject: [PATCH 0120/5375] KVM: MMU: use kvm_release_pfn_clean to release pfn The current code depends on the fact that fault_page is the normal page, however, we will use the error code instead of these dummy pages in the later patch, so we use kvm_release_pfn_clean to release pfn which will release the error code properly Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- arch/x86/kvm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 241993443599..a9a20528e700 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3275,7 +3275,7 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, if (!async) return false; /* *pfn has correct page already */ - put_page(pfn_to_page(*pfn)); + kvm_release_pfn_clean(*pfn); if (!prefault && can_do_async_pf(vcpu)) { trace_kvm_try_async_get_page(gva, gfn); From 2b4b5af8f8e7296bc27c52023ab6bb8f53db3a2b Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 26 Jul 2012 11:58:17 +0800 Subject: [PATCH 0121/5375] KVM: use kvm_release_page_clean to release the page In kvm_async_pf_wakeup_all, it uses bad_page to generate broadcast wakeup, and uses put_page to release bad_page, the work depends on the fact that bad_page is the normal page. But we will use the error code instead of bad_page, so use kvm_release_page_clean to release the page which will release the error code properly Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- virt/kvm/async_pf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 74268b4c2ee1..ebae24b62c90 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -112,7 +112,7 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu) typeof(*work), link); list_del(&work->link); if (work->page) - put_page(work->page); + kvm_release_page_clean(work->page); kmem_cache_free(async_pf_cache, work); } spin_unlock(&vcpu->async_pf.lock); @@ -139,7 +139,7 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu) list_del(&work->queue); vcpu->async_pf.queued--; if (work->page) - put_page(work->page); + kvm_release_page_clean(work->page); kmem_cache_free(async_pf_cache, work); } } From a2766325cf9f9e36d1225145f1ce1b066f001837 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 26 Jul 2012 11:58:59 +0800 Subject: [PATCH 0122/5375] KVM: remove dummy pages Currently, kvm allocates some pages and use them as error indicators, it wastes memory and is not good for scalability Base on Avi's suggestion, we use the error codes instead of these pages to indicate the error conditions Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- include/linux/kvm_host.h | 3 +- virt/kvm/async_pf.c | 3 +- virt/kvm/kvm_main.c | 121 ++++++++++++++++----------------------- 3 files changed, 52 insertions(+), 75 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 1993eb1cb2cd..4e60d3695e4e 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -423,6 +423,7 @@ void kvm_arch_flush_shadow(struct kvm *kvm); int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages, int nr_pages); +struct page *get_bad_page(void); struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn); void kvm_release_page_clean(struct page *page); @@ -576,7 +577,7 @@ void kvm_arch_sync_events(struct kvm *kvm); int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu); void kvm_vcpu_kick(struct kvm_vcpu *vcpu); -int kvm_is_mmio_pfn(pfn_t pfn); +bool kvm_is_mmio_pfn(pfn_t pfn); struct kvm_irq_ack_notifier { struct hlist_node link; diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index ebae24b62c90..79722782d9d7 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -203,8 +203,7 @@ int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu) if (!work) return -ENOMEM; - work->page = bad_page; - get_page(bad_page); + work->page = get_bad_page(); INIT_LIST_HEAD(&work->queue); /* for list_del to work */ spin_lock(&vcpu->async_pf.lock); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 0014ee99dc7f..de89497fe4c7 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -100,17 +100,11 @@ EXPORT_SYMBOL_GPL(kvm_rebooting); static bool largepages_enabled = true; -struct page *bad_page; -static pfn_t bad_pfn; - -static struct page *hwpoison_page; -static pfn_t hwpoison_pfn; - -static struct page *fault_page; -static pfn_t fault_pfn; - -inline int kvm_is_mmio_pfn(pfn_t pfn) +bool kvm_is_mmio_pfn(pfn_t pfn) { + if (is_error_pfn(pfn)) + return false; + if (pfn_valid(pfn)) { int reserved; struct page *tail = pfn_to_page(pfn); @@ -939,34 +933,55 @@ EXPORT_SYMBOL_GPL(kvm_disable_largepages); int is_error_page(struct page *page) { - return page == bad_page || page == hwpoison_page || page == fault_page; + return IS_ERR(page); } EXPORT_SYMBOL_GPL(is_error_page); int is_error_pfn(pfn_t pfn) { - return pfn == bad_pfn || pfn == hwpoison_pfn || pfn == fault_pfn; + return IS_ERR_VALUE(pfn); } EXPORT_SYMBOL_GPL(is_error_pfn); +static pfn_t get_bad_pfn(void) +{ + return -ENOENT; +} + +pfn_t get_fault_pfn(void) +{ + return -EFAULT; +} +EXPORT_SYMBOL_GPL(get_fault_pfn); + +static pfn_t get_hwpoison_pfn(void) +{ + return -EHWPOISON; +} + int is_hwpoison_pfn(pfn_t pfn) { - return pfn == hwpoison_pfn; + return pfn == -EHWPOISON; } EXPORT_SYMBOL_GPL(is_hwpoison_pfn); int is_noslot_pfn(pfn_t pfn) { - return pfn == bad_pfn; + return pfn == -ENOENT; } EXPORT_SYMBOL_GPL(is_noslot_pfn); int is_invalid_pfn(pfn_t pfn) { - return pfn == hwpoison_pfn || pfn == fault_pfn; + return !is_noslot_pfn(pfn) && is_error_pfn(pfn); } EXPORT_SYMBOL_GPL(is_invalid_pfn); +struct page *get_bad_page(void) +{ + return ERR_PTR(-ENOENT); +} + static inline unsigned long bad_hva(void) { return PAGE_OFFSET; @@ -1038,13 +1053,6 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) } EXPORT_SYMBOL_GPL(gfn_to_hva); -pfn_t get_fault_pfn(void) -{ - get_page(fault_page); - return fault_pfn; -} -EXPORT_SYMBOL_GPL(get_fault_pfn); - int get_user_page_nowait(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, int write, struct page **page) { @@ -1122,8 +1130,7 @@ static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, if (npages == -EHWPOISON || (!async && check_user_page_hwpoison(addr))) { up_read(¤t->mm->mmap_sem); - get_page(hwpoison_page); - return page_to_pfn(hwpoison_page); + return get_hwpoison_pfn(); } vma = find_vma_intersection(current->mm, addr, addr+1); @@ -1161,10 +1168,8 @@ static pfn_t __gfn_to_pfn(struct kvm *kvm, gfn_t gfn, bool atomic, bool *async, *async = false; addr = gfn_to_hva(kvm, gfn); - if (kvm_is_error_hva(addr)) { - get_page(bad_page); - return page_to_pfn(bad_page); - } + if (kvm_is_error_hva(addr)) + return get_bad_pfn(); return hva_to_pfn(addr, atomic, async, write_fault, writable); } @@ -1218,37 +1223,45 @@ int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages, } EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic); +static struct page *kvm_pfn_to_page(pfn_t pfn) +{ + WARN_ON(kvm_is_mmio_pfn(pfn)); + + if (is_error_pfn(pfn) || kvm_is_mmio_pfn(pfn)) + return get_bad_page(); + + return pfn_to_page(pfn); +} + struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) { pfn_t pfn; pfn = gfn_to_pfn(kvm, gfn); - if (!kvm_is_mmio_pfn(pfn)) - return pfn_to_page(pfn); - WARN_ON(kvm_is_mmio_pfn(pfn)); - - get_page(bad_page); - return bad_page; + return kvm_pfn_to_page(pfn); } EXPORT_SYMBOL_GPL(gfn_to_page); void kvm_release_page_clean(struct page *page) { - kvm_release_pfn_clean(page_to_pfn(page)); + if (!is_error_page(page)) + kvm_release_pfn_clean(page_to_pfn(page)); } EXPORT_SYMBOL_GPL(kvm_release_page_clean); void kvm_release_pfn_clean(pfn_t pfn) { - if (!kvm_is_mmio_pfn(pfn)) + if (!is_error_pfn(pfn) && !kvm_is_mmio_pfn(pfn)) put_page(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); void kvm_release_page_dirty(struct page *page) { + WARN_ON(is_error_page(page)); + kvm_release_pfn_dirty(page_to_pfn(page)); } EXPORT_SYMBOL_GPL(kvm_release_page_dirty); @@ -2771,33 +2784,6 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, if (r) goto out_fail; - bad_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - - if (bad_page == NULL) { - r = -ENOMEM; - goto out; - } - - bad_pfn = page_to_pfn(bad_page); - - hwpoison_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - - if (hwpoison_page == NULL) { - r = -ENOMEM; - goto out_free_0; - } - - hwpoison_pfn = page_to_pfn(hwpoison_page); - - fault_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - - if (fault_page == NULL) { - r = -ENOMEM; - goto out_free_0; - } - - fault_pfn = page_to_pfn(fault_page); - if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) { r = -ENOMEM; goto out_free_0; @@ -2872,12 +2858,6 @@ out_free_1: out_free_0a: free_cpumask_var(cpus_hardware_enabled); out_free_0: - if (fault_page) - __free_page(fault_page); - if (hwpoison_page) - __free_page(hwpoison_page); - __free_page(bad_page); -out: kvm_arch_exit(); out_fail: return r; @@ -2897,8 +2877,5 @@ void kvm_exit(void) kvm_arch_hardware_unsetup(); kvm_arch_exit(); free_cpumask_var(cpus_hardware_enabled); - __free_page(fault_page); - __free_page(hwpoison_page); - __free_page(bad_page); } EXPORT_SYMBOL_GPL(kvm_exit); From f23b070e662ca55a8fdaaa28537af06cab664499 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Thu, 26 Jul 2012 13:12:22 +0800 Subject: [PATCH 0123/5375] KVM: x86 emulator: simplify read_emulated No need split mmio read region into 8-bits pieces since we do it in emulator_read_write_onepage Changelog: Add a WARN_ON to check read-cache overflow Acked-by: Marcelo Tosatti Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- arch/x86/kvm/emulate.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 85b611e13e84..2c5d1e65d9d1 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1166,24 +1166,21 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt, int rc; struct read_cache *mc = &ctxt->mem_read; - while (size) { - int n = min(size, 8u); - size -= n; - if (mc->pos < mc->end) - goto read_cached; + if (mc->pos < mc->end) + goto read_cached; - rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, n, - &ctxt->exception); - if (rc != X86EMUL_CONTINUE) - return rc; - mc->end += n; + WARN_ON((mc->end + size) >= sizeof(mc->data)); - read_cached: - memcpy(dest, mc->data + mc->pos, n); - mc->pos += n; - dest += n; - addr += n; - } + rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, size, + &ctxt->exception); + if (rc != X86EMUL_CONTINUE) + return rc; + + mc->end += size; + +read_cached: + memcpy(dest, mc->data + mc->pos, size); + mc->pos += size; return X86EMUL_CONTINUE; } From 99245b507dc3b1b2815d6a6cb4e94a6b7018a24b Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Wed, 25 Jul 2012 15:49:42 +0300 Subject: [PATCH 0124/5375] KVM: x86 emulator: drop unneeded call to get_segment() setup_syscalls_segments() calls get_segment() and than overwrites all but one of the structure fields and this one should also be overwritten anyway, so we can drop call to get_segment() and avoid a couple of vmreads on vmx. Also drop zeroing ss/cs structures since most of the fields are set anyway. Just set those that were not set explicitly. Signed-off-by: Gleb Natapov Signed-off-by: Avi Kivity --- arch/x86/kvm/emulate.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 2c5d1e65d9d1..10f0136f50c1 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2035,12 +2035,6 @@ static void setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, struct desc_struct *cs, struct desc_struct *ss) { - u16 selector; - - memset(cs, 0, sizeof(struct desc_struct)); - ctxt->ops->get_segment(ctxt, &selector, cs, NULL, VCPU_SREG_CS); - memset(ss, 0, sizeof(struct desc_struct)); - cs->l = 0; /* will be adjusted later */ set_desc_base(cs, 0); /* flat segment */ cs->g = 1; /* 4kb granularity */ @@ -2050,6 +2044,7 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, cs->dpl = 0; /* will be adjusted later */ cs->p = 1; cs->d = 1; + cs->avl = 0; set_desc_base(ss, 0); /* flat segment */ set_desc_limit(ss, 0xfffff); /* 4GB limit */ @@ -2059,6 +2054,8 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, ss->d = 1; /* 32bit stack segment */ ss->dpl = 0; ss->p = 1; + ss->l = 0; + ss->avl = 0; } static bool vendor_intel(struct x86_emulate_ctxt *ctxt) From 23d43cf998275bc97437931c0cdee1df2c1aa3ca Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Tue, 24 Jul 2012 08:51:20 -0400 Subject: [PATCH 0125/5375] KVM: Move KVM_IRQ_LINE to arch-generic code Handle KVM_IRQ_LINE and KVM_IRQ_LINE_STATUS in the generic kvm_vm_ioctl() function and call into kvm_vm_ioctl_irq_line(). This is even more relevant when KVM/ARM also uses this ioctl. Signed-off-by: Christoffer Dall Signed-off-by: Avi Kivity --- arch/ia64/kvm/kvm-ia64.c | 33 ++++++++++----------------------- arch/x86/kvm/x86.c | 33 ++++++++++----------------------- include/linux/kvm_host.h | 1 + virt/kvm/kvm_main.c | 23 +++++++++++++++++++++++ 4 files changed, 44 insertions(+), 46 deletions(-) diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index bd77cb507c1c..eac65380bd20 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c @@ -924,6 +924,16 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) return 0; } +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event) +{ + if (!irqchip_in_kernel(kvm)) + return -ENXIO; + + irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, + irq_event->irq, irq_event->level); + return 0; +} + long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -963,29 +973,6 @@ long kvm_arch_vm_ioctl(struct file *filp, goto out; } break; - case KVM_IRQ_LINE_STATUS: - case KVM_IRQ_LINE: { - struct kvm_irq_level irq_event; - - r = -EFAULT; - if (copy_from_user(&irq_event, argp, sizeof irq_event)) - goto out; - r = -ENXIO; - if (irqchip_in_kernel(kvm)) { - __s32 status; - status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, - irq_event.irq, irq_event.level); - if (ioctl == KVM_IRQ_LINE_STATUS) { - r = -EFAULT; - irq_event.status = status; - if (copy_to_user(argp, &irq_event, - sizeof irq_event)) - goto out; - } - r = 0; - } - break; - } case KVM_GET_IRQCHIP: { /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ struct kvm_irqchip chip; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3d9d08edbf29..b6379e55ee27 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3165,6 +3165,16 @@ out: return r; } +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event) +{ + if (!irqchip_in_kernel(kvm)) + return -ENXIO; + + irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, + irq_event->irq, irq_event->level); + return 0; +} + long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -3271,29 +3281,6 @@ long kvm_arch_vm_ioctl(struct file *filp, create_pit_unlock: mutex_unlock(&kvm->slots_lock); break; - case KVM_IRQ_LINE_STATUS: - case KVM_IRQ_LINE: { - struct kvm_irq_level irq_event; - - r = -EFAULT; - if (copy_from_user(&irq_event, argp, sizeof irq_event)) - goto out; - r = -ENXIO; - if (irqchip_in_kernel(kvm)) { - __s32 status; - status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, - irq_event.irq, irq_event.level); - if (ioctl == KVM_IRQ_LINE_STATUS) { - r = -EFAULT; - irq_event.status = status; - if (copy_to_user(argp, &irq_event, - sizeof irq_event)) - goto out; - } - r = 0; - } - break; - } case KVM_GET_IRQCHIP: { /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ struct kvm_irqchip *chip; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 4e60d3695e4e..dbc65f9d6a2b 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -498,6 +498,7 @@ int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, int user_alloc); +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level); long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index de89497fe4c7..bcf973ec98ff 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2148,6 +2148,29 @@ static long kvm_vm_ioctl(struct file *filp, r = kvm_send_userspace_msi(kvm, &msi); break; } +#endif +#ifdef __KVM_HAVE_IRQ_LINE + case KVM_IRQ_LINE_STATUS: + case KVM_IRQ_LINE: { + struct kvm_irq_level irq_event; + + r = -EFAULT; + if (copy_from_user(&irq_event, argp, sizeof irq_event)) + goto out; + + r = kvm_vm_ioctl_irq_line(kvm, &irq_event); + if (r) + goto out; + + r = -EFAULT; + if (ioctl == KVM_IRQ_LINE_STATUS) { + if (copy_to_user(argp, &irq_event, sizeof irq_event)) + goto out; + } + + r = 0; + break; + } #endif default: r = kvm_arch_vm_ioctl(filp, ioctl, arg); From 42d6ab4839799b2f246748ce663d6b023f02bb73 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 26 Jul 2012 11:49:32 +0100 Subject: [PATCH 0126/5375] drm/i915: Segregate memory domains in the GTT using coloring Several functions of the GPU have the restriction that differing memory domains cannot be placed next to each other (as the GPU may prefetch beyond the end of one domain and hang as it crosses into the other domain). We use the facility of the drm_mm to mark ranges with a particular color that corresponds to the cache attributes of those pages in order to prevent allocating adjacent blocks of differing memory types. v2: Rebase ontop of drm_mm coloring v2. v3: Fix rebinding existing gtt_space and add a verification routine. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +- drivers/gpu/drm/i915/i915_gem.c | 111 +++++++++++++++++++++++--- drivers/gpu/drm/i915/i915_gem_evict.c | 7 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 19 +++++ 4 files changed, 128 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e6e63c1aee68..270b31cabc1a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -109,6 +109,7 @@ struct intel_pch_pll { #define WATCH_COHERENCY 0 #define WATCH_LISTS 0 +#define WATCH_GTT 0 #define I915_GEM_PHYS_CURSOR_0 1 #define I915_GEM_PHYS_CURSOR_1 2 @@ -1406,7 +1407,9 @@ void i915_gem_init_global_gtt(struct drm_device *dev, /* i915_gem_evict.c */ int __must_check i915_gem_evict_something(struct drm_device *dev, int min_size, - unsigned alignment, bool mappable); + unsigned alignment, + unsigned cache_level, + bool mappable); int i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only); /* i915_gem_stolen.c */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b274810eaeab..19bdc245a87a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2586,6 +2586,76 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) return 0; } +static bool i915_gem_valid_gtt_space(struct drm_device *dev, + struct drm_mm_node *gtt_space, + unsigned long cache_level) +{ + struct drm_mm_node *other; + + /* On non-LLC machines we have to be careful when putting differing + * types of snoopable memory together to avoid the prefetcher + * crossing memory domains and dieing. + */ + if (HAS_LLC(dev)) + return true; + + if (gtt_space == NULL) + return true; + + if (list_empty(>t_space->node_list)) + return true; + + other = list_entry(gtt_space->node_list.prev, struct drm_mm_node, node_list); + if (other->allocated && !other->hole_follows && other->color != cache_level) + return false; + + other = list_entry(gtt_space->node_list.next, struct drm_mm_node, node_list); + if (other->allocated && !gtt_space->hole_follows && other->color != cache_level) + return false; + + return true; +} + +static void i915_gem_verify_gtt(struct drm_device *dev) +{ +#if WATCH_GTT + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj; + int err = 0; + + list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { + if (obj->gtt_space == NULL) { + printk(KERN_ERR "object found on GTT list with no space reserved\n"); + err++; + continue; + } + + if (obj->cache_level != obj->gtt_space->color) { + printk(KERN_ERR "object reserved space [%08lx, %08lx] with wrong color, cache_level=%x, color=%lx\n", + obj->gtt_space->start, + obj->gtt_space->start + obj->gtt_space->size, + obj->cache_level, + obj->gtt_space->color); + err++; + continue; + } + + if (!i915_gem_valid_gtt_space(dev, + obj->gtt_space, + obj->cache_level)) { + printk(KERN_ERR "invalid GTT space found at [%08lx, %08lx] - color=%x\n", + obj->gtt_space->start, + obj->gtt_space->start + obj->gtt_space->size, + obj->cache_level); + err++; + continue; + } + } + + WARN_ON(err); +#endif +} + /** * Finds free space in the GTT aperture and binds the object there. */ @@ -2640,36 +2710,47 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, search_free: if (map_and_fenceable) free_space = - drm_mm_search_free_in_range(&dev_priv->mm.gtt_space, - size, alignment, - 0, dev_priv->mm.gtt_mappable_end, - 0); + drm_mm_search_free_in_range_color(&dev_priv->mm.gtt_space, + size, alignment, obj->cache_level, + 0, dev_priv->mm.gtt_mappable_end, + false); else - free_space = drm_mm_search_free(&dev_priv->mm.gtt_space, - size, alignment, 0); + free_space = drm_mm_search_free_color(&dev_priv->mm.gtt_space, + size, alignment, obj->cache_level, + false); if (free_space != NULL) { if (map_and_fenceable) obj->gtt_space = drm_mm_get_block_range_generic(free_space, - size, alignment, 0, + size, alignment, obj->cache_level, 0, dev_priv->mm.gtt_mappable_end, - 0); + false); else obj->gtt_space = - drm_mm_get_block(free_space, size, alignment); + drm_mm_get_block_generic(free_space, + size, alignment, obj->cache_level, + false); } if (obj->gtt_space == NULL) { /* If the gtt is empty and we're still having trouble * fitting our object in, we're out of memory. */ ret = i915_gem_evict_something(dev, size, alignment, + obj->cache_level, map_and_fenceable); if (ret) return ret; goto search_free; } + if (WARN_ON(!i915_gem_valid_gtt_space(dev, + obj->gtt_space, + obj->cache_level))) { + drm_mm_put_block(obj->gtt_space); + obj->gtt_space = NULL; + return -EINVAL; + } ret = i915_gem_object_get_pages_gtt(obj, gfpmask); if (ret) { @@ -2732,6 +2813,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, obj->map_and_fenceable = mappable && fenceable; trace_i915_gem_object_bind(obj, map_and_fenceable); + i915_gem_verify_gtt(dev); return 0; } @@ -2873,6 +2955,12 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, return -EBUSY; } + if (!i915_gem_valid_gtt_space(dev, obj->gtt_space, cache_level)) { + ret = i915_gem_object_unbind(obj); + if (ret) + return ret; + } + if (obj->gtt_space) { ret = i915_gem_object_finish_gpu(obj); if (ret) @@ -2884,7 +2972,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, * registers with snooped memory, so relinquish any fences * currently pointing to our region in the aperture. */ - if (INTEL_INFO(obj->base.dev)->gen < 6) { + if (INTEL_INFO(dev)->gen < 6) { ret = i915_gem_object_put_fence(obj); if (ret) return ret; @@ -2895,6 +2983,8 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, if (obj->has_aliasing_ppgtt_mapping) i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt, obj, cache_level); + + obj->gtt_space->color = cache_level; } if (cache_level == I915_CACHE_NONE) { @@ -2921,6 +3011,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, } obj->cache_level = cache_level; + i915_gem_verify_gtt(dev); return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 51e547c4ed89..7279c31d4a9a 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -44,7 +44,8 @@ mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind) int i915_gem_evict_something(struct drm_device *dev, int min_size, - unsigned alignment, bool mappable) + unsigned alignment, unsigned cache_level, + bool mappable) { drm_i915_private_t *dev_priv = dev->dev_private; struct list_head eviction_list, unwind_list; @@ -79,11 +80,11 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, INIT_LIST_HEAD(&unwind_list); if (mappable) drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space, - min_size, alignment, 0, + min_size, alignment, cache_level, 0, dev_priv->mm.gtt_mappable_end); else drm_mm_init_scan(&dev_priv->mm.gtt_space, - min_size, alignment, 0); + min_size, alignment, cache_level); /* First see if there is a large enough contiguous idle region... */ list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 9fd25a435536..4584f7f0063e 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -422,6 +422,23 @@ void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj) undo_idling(dev_priv, interruptible); } +static void i915_gtt_color_adjust(struct drm_mm_node *node, + unsigned long color, + unsigned long *start, + unsigned long *end) +{ + if (node->color != color) + *start += 4096; + + if (!list_empty(&node->node_list)) { + node = list_entry(node->node_list.next, + struct drm_mm_node, + node_list); + if (node->allocated && node->color != color) + *end -= 4096; + } +} + void i915_gem_init_global_gtt(struct drm_device *dev, unsigned long start, unsigned long mappable_end, @@ -431,6 +448,8 @@ void i915_gem_init_global_gtt(struct drm_device *dev, /* Substract the guard page ... */ drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE); + if (!HAS_LLC(dev)) + dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust; dev_priv->mm.gtt_start = start; dev_priv->mm.gtt_mappable_end = mappable_end; From e6994aeedcee4f71998d89d2c10c5baa419ebeac Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 10 Jul 2012 10:27:08 +0100 Subject: [PATCH 0127/5375] drm/i915: Export ability of changing cache levels to userspace By selecting the cache level (essentially whether or not the CPU snoops any updates to the bo, and on more recent machines whether it resides inside the CPU's last-level-cache) a userspace driver is able to then manage all of its memory within buffer objects, if it so desires. This enables the userspace driver to accelerate uploads and more importantly downloads from the GPU and to able to mix CPU and GPU rendering/activity efficiently. Signed-off-by: Chris Wilson [danvet: Added code comment about where we plan to stuff platform specific cacheing control bits in the ioctl struct.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 2 ++ drivers/gpu/drm/i915/i915_drv.h | 8 +++-- drivers/gpu/drm/i915/i915_gem.c | 62 +++++++++++++++++++++++++++++++++ include/drm/i915_drm.h | 10 ++++-- 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 733744f26dc6..71672cee00f7 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1835,6 +1835,8 @@ struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHEING, i915_gem_set_cacheing_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHEING, i915_gem_get_cacheing_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 270b31cabc1a..0dc89a42a80a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -848,9 +848,9 @@ enum hdmi_force_audio { }; enum i915_cache_level { - I915_CACHE_NONE, + I915_CACHE_NONE = 0, I915_CACHE_LLC, - I915_CACHE_LLC_MLC, /* gen6+ */ + I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */ }; struct drm_i915_gem_object { @@ -1238,6 +1238,10 @@ int i915_gem_unpin_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int i915_gem_get_cacheing_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); +int i915_gem_set_cacheing_ioctl(struct drm_device *dev, void *data, + struct drm_file *file); int i915_gem_throttle_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_madvise_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 19bdc245a87a..c540321b42ba 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3015,6 +3015,68 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, return 0; } +int i915_gem_get_cacheing_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_cacheing *args = data; + struct drm_i915_gem_object *obj; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + args->cacheing = obj->cache_level != I915_CACHE_NONE; + + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int i915_gem_set_cacheing_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_i915_gem_cacheing *args = data; + struct drm_i915_gem_object *obj; + enum i915_cache_level level; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + + switch (args->cacheing) { + case I915_CACHEING_NONE: + level = I915_CACHE_NONE; + break; + case I915_CACHEING_CACHED: + level = I915_CACHE_LLC; + break; + default: + return -EINVAL; + } + + obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); + if (&obj->base == NULL) { + ret = -ENOENT; + goto unlock; + } + + ret = i915_gem_object_set_cache_level(obj, level); + + drm_gem_object_unreference(&obj->base); +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + /* * Prepare buffer for display plane (scanout, cursors, etc). * Can be called from an uninterruptible phase (modesetting) and allows diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index 0f149fe32211..772b0d638912 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -716,10 +716,16 @@ struct drm_i915_gem_busy { #define I915_CACHEING_CACHED 1 struct drm_i915_gem_cacheing { - /** Handle of the buffer to set/get the cacheing level of */ + /** + * Handle of the buffer to set/get the cacheing level of. */ __u32 handle; - /** Cacheing level to apply or return value */ + /** + * Cacheing level to apply or return value + * + * bits0-15 are for generic cacheing control (i.e. the above defined + * values). bits16-31 are reserved for platform-specific variations + * (e.g. l3$ caching on gen7). */ __u32 cacheing; }; From 9b7fb990e080f3a7c5dff9a829d11247e629b98f Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 23 Jul 2012 17:20:28 +0200 Subject: [PATCH 0128/5375] s390/dis: Instruction decoding interface Provide a new function, insn_to_mnemonic, by which e.g. kvm can obtain a human-readable decoding of an instruction's opcode. Reviewed-by: Christian Borntraeger Reviewed-by: Heiko Carstens Signed-off-by: Cornelia Huck Signed-off-by: Avi Kivity --- arch/s390/include/asm/processor.h | 1 + arch/s390/kernel/dis.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index c40fa91e38a8..31feac630544 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -138,6 +138,7 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern unsigned long thread_saved_pc(struct task_struct *t); extern void show_code(struct pt_regs *regs); +extern int insn_to_mnemonic(unsigned char *instruction, char buf[8]); unsigned long get_wchan(struct task_struct *p); #define task_pt_regs(tsk) ((struct pt_regs *) \ diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index 1f6b428e2762..c02310b8db09 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -1468,6 +1468,33 @@ static struct insn *find_insn(unsigned char *code) return NULL; } +/** + * insn_to_mnemonic - decode an s390 instruction + * @instruction: instruction to decode + * @buf: buffer to fill with mnemonic + * + * Decode the instruction at @instruction and store the corresponding + * mnemonic into @buf. + * @buf is left unchanged if the instruction could not be decoded. + * Returns: + * %0 on success, %-ENOENT if the instruction was not found. + */ +int insn_to_mnemonic(unsigned char *instruction, char buf[8]) +{ + struct insn *insn; + + insn = find_insn(instruction); + if (!insn) + return -ENOENT; + if (insn->name[0] == '\0') + snprintf(buf, sizeof(buf), "%s", + long_insn_name[(int) insn->name[1]]); + else + snprintf(buf, sizeof(buf), "%.5s", insn->name); + return 0; +} +EXPORT_SYMBOL_GPL(insn_to_mnemonic); + static int print_insn(char *buffer, unsigned char *code, unsigned long addr) { struct insn *insn; From 5786fffa96ae7c3f8111e29fb62e073a45efc557 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 23 Jul 2012 17:20:29 +0200 Subject: [PATCH 0129/5375] KVM: s390: Add architectural trace events Add trace events for several s390 architecture specifics: - SIE entry/exit - common intercepts - common instructions (sigp/diagnose) Reviewed-by: Christian Borntraeger Signed-off-by: Cornelia Huck Signed-off-by: Avi Kivity --- arch/s390/kvm/diag.c | 2 + arch/s390/kvm/intercept.c | 8 + arch/s390/kvm/kvm-s390.c | 7 + arch/s390/kvm/priv.c | 9 +- arch/s390/kvm/sigp.c | 2 + arch/s390/kvm/trace.h | 341 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 368 insertions(+), 1 deletion(-) create mode 100644 arch/s390/kvm/trace.h diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index c88bb7793390..f5d4416ebfed 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c @@ -14,6 +14,7 @@ #include #include #include "kvm-s390.h" +#include "trace.h" static int diag_release_pages(struct kvm_vcpu *vcpu) { @@ -105,6 +106,7 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) { int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16; + trace_kvm_s390_handle_diag(vcpu, code); switch (code) { case 0x10: return diag_release_pages(vcpu); diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index adae539f12e2..db541d62c771 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -19,6 +19,7 @@ #include "kvm-s390.h" #include "gaccess.h" +#include "trace.h" static int handle_lctlg(struct kvm_vcpu *vcpu) { @@ -45,6 +46,7 @@ static int handle_lctlg(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, disp2); + trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr); do { rc = get_guest_u64(vcpu, useraddr, @@ -82,6 +84,7 @@ static int handle_lctl(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, disp2); + trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr); reg = reg1; do { @@ -171,6 +174,7 @@ static int handle_validity(struct kvm_vcpu *vcpu) int rc; vcpu->stat.exit_validity++; + trace_kvm_s390_intercept_validity(vcpu, viwhy); if (viwhy == 0x37) { vmaddr = gmap_fault(vcpu->arch.sie_block->prefix, vcpu->arch.gmap); @@ -213,6 +217,9 @@ static int handle_instruction(struct kvm_vcpu *vcpu) intercept_handler_t handler; vcpu->stat.exit_instruction++; + trace_kvm_s390_intercept_instruction(vcpu, + vcpu->arch.sie_block->ipa, + vcpu->arch.sie_block->ipb); handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8]; if (handler) return handler(vcpu); @@ -222,6 +229,7 @@ static int handle_instruction(struct kvm_vcpu *vcpu) static int handle_prog(struct kvm_vcpu *vcpu) { vcpu->stat.exit_program_interruption++; + trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc); return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc); } diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index d470ccbfabae..4613602e123e 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -32,6 +32,9 @@ #include "kvm-s390.h" #include "gaccess.h" +#define CREATE_TRACE_POINTS +#include "trace.h" + #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU struct kvm_stats_debugfs_item debugfs_entries[] = { @@ -607,18 +610,22 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) local_irq_enable(); VCPU_EVENT(vcpu, 6, "entering sie flags %x", atomic_read(&vcpu->arch.sie_block->cpuflags)); + trace_kvm_s390_sie_enter(vcpu, + atomic_read(&vcpu->arch.sie_block->cpuflags)); rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs); if (rc) { if (kvm_is_ucontrol(vcpu->kvm)) { rc = SIE_INTERCEPT_UCONTROL; } else { VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction"); + trace_kvm_s390_sie_fault(vcpu); kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); rc = 0; } } VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", vcpu->arch.sie_block->icptcode); + trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode); local_irq_disable(); kvm_guest_exit(); local_irq_enable(); diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 60da903d6f3e..ed256fdd7b58 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -20,6 +20,7 @@ #include #include "gaccess.h" #include "kvm-s390.h" +#include "trace.h" static int handle_set_prefix(struct kvm_vcpu *vcpu) { @@ -59,6 +60,7 @@ static int handle_set_prefix(struct kvm_vcpu *vcpu) kvm_s390_set_prefix(vcpu, address); VCPU_EVENT(vcpu, 5, "setting prefix to %x", address); + trace_kvm_s390_handle_prefix(vcpu, 1, address); out: return 0; } @@ -91,6 +93,7 @@ static int handle_store_prefix(struct kvm_vcpu *vcpu) } VCPU_EVENT(vcpu, 5, "storing prefix to %x", address); + trace_kvm_s390_handle_prefix(vcpu, 0, address); out: return 0; } @@ -119,6 +122,7 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu) } VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr); + trace_kvm_s390_handle_stap(vcpu, useraddr); out: return 0; } @@ -164,9 +168,11 @@ static int handle_stfl(struct kvm_vcpu *vcpu) &facility_list, sizeof(facility_list)); if (rc == -EFAULT) kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - else + else { VCPU_EVENT(vcpu, 5, "store facility list value %x", facility_list); + trace_kvm_s390_handle_stfl(vcpu, facility_list); + } return 0; } @@ -278,6 +284,7 @@ static int handle_stsi(struct kvm_vcpu *vcpu) kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out_mem; } + trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2); free_page(mem); vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); vcpu->run->s.regs.gprs[0] = 0; diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index 56f80e1f98f7..566ddf6e8dfb 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -18,6 +18,7 @@ #include #include "gaccess.h" #include "kvm-s390.h" +#include "trace.h" static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, u64 *reg) @@ -344,6 +345,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) else parameter = vcpu->run->s.regs.gprs[r1 + 1]; + trace_kvm_s390_handle_sigp(vcpu, order_code, cpu_addr, parameter); switch (order_code) { case SIGP_SENSE: vcpu->stat.instruction_sigp_sense++; diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/trace.h new file mode 100644 index 000000000000..2b29e62351d3 --- /dev/null +++ b/arch/s390/kvm/trace.h @@ -0,0 +1,341 @@ +#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_KVM_H + +#include +#include +#include + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM kvm +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +/* + * Helpers for vcpu-specific tracepoints containing the same information + * as s390dbf VCPU_EVENTs. + */ +#define VCPU_PROTO_COMMON struct kvm_vcpu *vcpu +#define VCPU_ARGS_COMMON vcpu +#define VCPU_FIELD_COMMON __field(int, id) \ + __field(unsigned long, pswmask) \ + __field(unsigned long, pswaddr) +#define VCPU_ASSIGN_COMMON do { \ + __entry->id = vcpu->vcpu_id; \ + __entry->pswmask = vcpu->arch.sie_block->gpsw.mask; \ + __entry->pswaddr = vcpu->arch.sie_block->gpsw.addr; \ + } while (0); +#define VCPU_TP_PRINTK(p_str, p_args...) \ + TP_printk("%02d[%016lx-%016lx]: " p_str, __entry->id, \ + __entry->pswmask, __entry->pswaddr, p_args) + +/* + * Tracepoints for SIE entry and exit. + */ +TRACE_EVENT(kvm_s390_sie_enter, + TP_PROTO(VCPU_PROTO_COMMON, int cpuflags), + TP_ARGS(VCPU_ARGS_COMMON, cpuflags), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(int, cpuflags) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->cpuflags = cpuflags; + ), + + VCPU_TP_PRINTK("entering sie flags %x", __entry->cpuflags) + ); + +TRACE_EVENT(kvm_s390_sie_fault, + TP_PROTO(VCPU_PROTO_COMMON), + TP_ARGS(VCPU_ARGS_COMMON), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + ), + + VCPU_TP_PRINTK("%s", "fault in sie instruction") + ); + +#define sie_intercept_code \ + {0x04, "Instruction"}, \ + {0x08, "Program interruption"}, \ + {0x0C, "Instruction and program interuption"}, \ + {0x10, "External request"}, \ + {0x14, "External interruption"}, \ + {0x18, "I/O request"}, \ + {0x1C, "Wait state"}, \ + {0x20, "Validity"}, \ + {0x28, "Stop request"} + +TRACE_EVENT(kvm_s390_sie_exit, + TP_PROTO(VCPU_PROTO_COMMON, u8 icptcode), + TP_ARGS(VCPU_ARGS_COMMON, icptcode), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(u8, icptcode) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->icptcode = icptcode; + ), + + VCPU_TP_PRINTK("exit sie icptcode %d (%s)", __entry->icptcode, + __print_symbolic(__entry->icptcode, + sie_intercept_code)) + ); + +/* + * Trace point for intercepted instructions. + */ +TRACE_EVENT(kvm_s390_intercept_instruction, + TP_PROTO(VCPU_PROTO_COMMON, __u16 ipa, __u32 ipb), + TP_ARGS(VCPU_ARGS_COMMON, ipa, ipb), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(__u64, instruction) + __field(char, insn[8]) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->instruction = ((__u64)ipa << 48) | + ((__u64)ipb << 16); + ), + + VCPU_TP_PRINTK("intercepted instruction %016llx (%s)", + __entry->instruction, + insn_to_mnemonic((unsigned char *) + &__entry->instruction, + __entry->insn) ? + "unknown" : __entry->insn) + ); + +/* + * Trace point for intercepted program interruptions. + */ +TRACE_EVENT(kvm_s390_intercept_prog, + TP_PROTO(VCPU_PROTO_COMMON, __u16 code), + TP_ARGS(VCPU_ARGS_COMMON, code), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(__u16, code) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->code = code; + ), + + VCPU_TP_PRINTK("intercepted program interruption %04x", + __entry->code) + ); + +/* + * Trace point for validity intercepts. + */ +TRACE_EVENT(kvm_s390_intercept_validity, + TP_PROTO(VCPU_PROTO_COMMON, __u16 viwhy), + TP_ARGS(VCPU_ARGS_COMMON, viwhy), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(__u16, viwhy) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->viwhy = viwhy; + ), + + VCPU_TP_PRINTK("got validity intercept %04x", __entry->viwhy) + ); + +/* + * Trace points for instructions that are of special interest. + */ + +#define sigp_order_codes \ + {SIGP_SENSE, "sense"}, \ + {SIGP_EXTERNAL_CALL, "external call"}, \ + {SIGP_EMERGENCY_SIGNAL, "emergency signal"}, \ + {SIGP_STOP, "stop"}, \ + {SIGP_STOP_AND_STORE_STATUS, "stop and store status"}, \ + {SIGP_SET_ARCHITECTURE, "set architecture"}, \ + {SIGP_SET_PREFIX, "set prefix"}, \ + {SIGP_SENSE_RUNNING, "sense running"}, \ + {SIGP_RESTART, "restart"} + +TRACE_EVENT(kvm_s390_handle_sigp, + TP_PROTO(VCPU_PROTO_COMMON, __u8 order_code, __u16 cpu_addr, \ + __u32 parameter), + TP_ARGS(VCPU_ARGS_COMMON, order_code, cpu_addr, parameter), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(__u8, order_code) + __field(__u16, cpu_addr) + __field(__u32, parameter) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->order_code = order_code; + __entry->cpu_addr = cpu_addr; + __entry->parameter = parameter; + ), + + VCPU_TP_PRINTK("handle sigp order %02x (%s), cpu address %04x, " \ + "parameter %08x", __entry->order_code, + __print_symbolic(__entry->order_code, + sigp_order_codes), + __entry->cpu_addr, __entry->parameter) + ); + +#define diagnose_codes \ + {0x10, "release pages"}, \ + {0x44, "time slice end"}, \ + {0x308, "ipl functions"}, \ + {0x500, "kvm hypercall"}, \ + {0x501, "kvm breakpoint"} + +TRACE_EVENT(kvm_s390_handle_diag, + TP_PROTO(VCPU_PROTO_COMMON, __u16 code), + TP_ARGS(VCPU_ARGS_COMMON, code), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(__u16, code) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->code = code; + ), + + VCPU_TP_PRINTK("handle diagnose call %04x (%s)", __entry->code, + __print_symbolic(__entry->code, diagnose_codes)) + ); + +TRACE_EVENT(kvm_s390_handle_lctl, + TP_PROTO(VCPU_PROTO_COMMON, int g, int reg1, int reg3, u64 addr), + TP_ARGS(VCPU_ARGS_COMMON, g, reg1, reg3, addr), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(int, g) + __field(int, reg1) + __field(int, reg3) + __field(u64, addr) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->g = g; + __entry->reg1 = reg1; + __entry->reg3 = reg3; + __entry->addr = addr; + ), + + VCPU_TP_PRINTK("%s: loading cr %x-%x from %016llx", + __entry->g ? "lctlg" : "lctl", + __entry->reg1, __entry->reg3, __entry->addr) + ); + +TRACE_EVENT(kvm_s390_handle_prefix, + TP_PROTO(VCPU_PROTO_COMMON, int set, u32 address), + TP_ARGS(VCPU_ARGS_COMMON, set, address), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(int, set) + __field(u32, address) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->set = set; + __entry->address = address; + ), + + VCPU_TP_PRINTK("%s prefix to %08x", + __entry->set ? "setting" : "storing", + __entry->address) + ); + +TRACE_EVENT(kvm_s390_handle_stap, + TP_PROTO(VCPU_PROTO_COMMON, u64 address), + TP_ARGS(VCPU_ARGS_COMMON, address), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(u64, address) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->address = address; + ), + + VCPU_TP_PRINTK("storing cpu address to %016llx", + __entry->address) + ); + +TRACE_EVENT(kvm_s390_handle_stfl, + TP_PROTO(VCPU_PROTO_COMMON, unsigned int facility_list), + TP_ARGS(VCPU_ARGS_COMMON, facility_list), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(unsigned int, facility_list) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->facility_list = facility_list; + ), + + VCPU_TP_PRINTK("store facility list value %08x", + __entry->facility_list) + ); + +TRACE_EVENT(kvm_s390_handle_stsi, + TP_PROTO(VCPU_PROTO_COMMON, int fc, int sel1, int sel2, u64 addr), + TP_ARGS(VCPU_ARGS_COMMON, fc, sel1, sel2, addr), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(int, fc) + __field(int, sel1) + __field(int, sel2) + __field(u64, addr) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->fc = fc; + __entry->sel1 = sel1; + __entry->sel2 = sel2; + __entry->addr = addr; + ), + + VCPU_TP_PRINTK("STSI %d.%d.%d information stored to %016llx", + __entry->fc, __entry->sel1, __entry->sel2, + __entry->addr) + ); + +#endif /* _TRACE_KVM_H */ + +/* This part must be outside protection */ +#include From ade38c311a0ad8c32e902fe1d0ae74d0d44bc71e Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 23 Jul 2012 17:20:30 +0200 Subject: [PATCH 0130/5375] KVM: s390: Add implementation-specific trace events Introduce a new trace system, kvm-s390, for some kvm/s390 specific trace points: - injection of interrupts - delivery of interrupts to the guest - creation/destruction of kvm machines and vcpus - stop actions for vcpus - reset requests for userspace Reviewed-by: Christian Borntraeger Signed-off-by: Cornelia Huck Signed-off-by: Avi Kivity --- arch/s390/kvm/diag.c | 2 + arch/s390/kvm/intercept.c | 3 + arch/s390/kvm/interrupt.c | 23 ++++ arch/s390/kvm/kvm-s390.c | 3 + arch/s390/kvm/trace-s390.h | 210 +++++++++++++++++++++++++++++++++++++ 5 files changed, 241 insertions(+) create mode 100644 arch/s390/kvm/trace-s390.h diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index f5d4416ebfed..a390687feb13 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c @@ -15,6 +15,7 @@ #include #include "kvm-s390.h" #include "trace.h" +#include "trace-s390.h" static int diag_release_pages(struct kvm_vcpu *vcpu) { @@ -99,6 +100,7 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu) vcpu->run->exit_reason = KVM_EXIT_S390_RESET; VCPU_EVENT(vcpu, 3, "requesting userspace resets %llx", vcpu->run->s390_reset_flags); + trace_kvm_s390_request_resets(vcpu->run->s390_reset_flags); return -EREMOTE; } diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index db541d62c771..22798ec33fd1 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -20,6 +20,7 @@ #include "kvm-s390.h" #include "gaccess.h" #include "trace.h" +#include "trace-s390.h" static int handle_lctlg(struct kvm_vcpu *vcpu) { @@ -138,6 +139,8 @@ static int handle_stop(struct kvm_vcpu *vcpu) vcpu->stat.exit_stop_request++; spin_lock_bh(&vcpu->arch.local_int.lock); + trace_kvm_s390_stop_request(vcpu->arch.local_int.action_bits); + if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) { vcpu->arch.local_int.action_bits &= ~ACTION_RELOADVCPU_ON_STOP; rc = SIE_INTERCEPT_RERUNVCPU; diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index b7bc1aac8ed2..7556231fb073 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -19,6 +19,7 @@ #include #include "kvm-s390.h" #include "gaccess.h" +#include "trace-s390.h" static int psw_extint_disabled(struct kvm_vcpu *vcpu) { @@ -130,6 +131,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, case KVM_S390_INT_EMERGENCY: VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg"); vcpu->stat.deliver_emergency_signal++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->emerg.code, 0); rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201); if (rc == -EFAULT) exception = 1; @@ -152,6 +155,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, case KVM_S390_INT_EXTERNAL_CALL: VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call"); vcpu->stat.deliver_external_call++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->extcall.code, 0); rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1202); if (rc == -EFAULT) exception = 1; @@ -175,6 +180,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", inti->ext.ext_params); vcpu->stat.deliver_service_signal++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->ext.ext_params, 0); rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401); if (rc == -EFAULT) exception = 1; @@ -198,6 +205,9 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx", inti->ext.ext_params, inti->ext.ext_params2); vcpu->stat.deliver_virtio_interrupt++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->ext.ext_params, + inti->ext.ext_params2); rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603); if (rc == -EFAULT) exception = 1; @@ -229,6 +239,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, case KVM_S390_SIGP_STOP: VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop"); vcpu->stat.deliver_stop_signal++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + 0, 0); __set_intercept_indicator(vcpu, inti); break; @@ -236,12 +248,16 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x", inti->prefix.address); vcpu->stat.deliver_prefix_signal++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->prefix.address, 0); kvm_s390_set_prefix(vcpu, inti->prefix.address); break; case KVM_S390_RESTART: VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart"); vcpu->stat.deliver_restart_signal++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + 0, 0); rc = copy_to_guest(vcpu, offsetof(struct _lowcore, restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) @@ -259,6 +275,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, inti->pgm.code, table[vcpu->arch.sie_block->ipa >> 14]); vcpu->stat.deliver_program_int++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->pgm.code, 0); rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code); if (rc == -EFAULT) exception = 1; @@ -515,6 +533,7 @@ int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) inti->pgm.code = code; VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code); + trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, inti->type, code, 0, 1); spin_lock_bh(&li->lock); list_add(&inti->list, &li->list); atomic_set(&li->active, 1); @@ -556,6 +575,8 @@ int kvm_s390_inject_vm(struct kvm *kvm, kfree(inti); return -EINVAL; } + trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64, + 2); mutex_lock(&kvm->lock); fi = &kvm->arch.float_int; @@ -621,6 +642,8 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, kfree(inti); return -EINVAL; } + trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type, s390int->parm, + s390int->parm64, 2); mutex_lock(&vcpu->kvm->lock); li = &vcpu->arch.local_int; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 4613602e123e..e83df7f0fedd 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -34,6 +34,7 @@ #define CREATE_TRACE_POINTS #include "trace.h" +#include "trace-s390.h" #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU @@ -245,6 +246,7 @@ out_err: void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) { VCPU_EVENT(vcpu, 3, "%s", "free cpu"); + trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id); if (!kvm_is_ucontrol(vcpu->kvm)) { clear_bit(63 - vcpu->vcpu_id, (unsigned long *) &vcpu->kvm->arch.sca->mcn); @@ -420,6 +422,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, goto out_free_sie_block; VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu, vcpu->arch.sie_block); + trace_kvm_s390_create_vcpu(id, vcpu, vcpu->arch.sie_block); return vcpu; out_free_sie_block: diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h new file mode 100644 index 000000000000..90fdf85b5ff7 --- /dev/null +++ b/arch/s390/kvm/trace-s390.h @@ -0,0 +1,210 @@ +#if !defined(_TRACE_KVMS390_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_KVMS390_H + +#include + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM kvm-s390 +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace-s390 + +/* + * Trace point for the creation of the kvm instance. + */ +TRACE_EVENT(kvm_s390_create_vm, + TP_PROTO(unsigned long type), + TP_ARGS(type), + + TP_STRUCT__entry( + __field(unsigned long, type) + ), + + TP_fast_assign( + __entry->type = type; + ), + + TP_printk("create vm%s", + __entry->type & KVM_VM_S390_UCONTROL ? " (UCONTROL)" : "") + ); + +/* + * Trace points for creation and destruction of vpcus. + */ +TRACE_EVENT(kvm_s390_create_vcpu, + TP_PROTO(unsigned int id, struct kvm_vcpu *vcpu, + struct kvm_s390_sie_block *sie_block), + TP_ARGS(id, vcpu, sie_block), + + TP_STRUCT__entry( + __field(unsigned int, id) + __field(struct kvm_vcpu *, vcpu) + __field(struct kvm_s390_sie_block *, sie_block) + ), + + TP_fast_assign( + __entry->id = id; + __entry->vcpu = vcpu; + __entry->sie_block = sie_block; + ), + + TP_printk("create cpu %d at %p, sie block at %p", __entry->id, + __entry->vcpu, __entry->sie_block) + ); + +TRACE_EVENT(kvm_s390_destroy_vcpu, + TP_PROTO(unsigned int id), + TP_ARGS(id), + + TP_STRUCT__entry( + __field(unsigned int, id) + ), + + TP_fast_assign( + __entry->id = id; + ), + + TP_printk("destroy cpu %d", __entry->id) + ); + +/* + * Trace points for injection of interrupts, either per machine or + * per vcpu. + */ + +#define kvm_s390_int_type \ + {KVM_S390_SIGP_STOP, "sigp stop"}, \ + {KVM_S390_PROGRAM_INT, "program interrupt"}, \ + {KVM_S390_SIGP_SET_PREFIX, "sigp set prefix"}, \ + {KVM_S390_RESTART, "sigp restart"}, \ + {KVM_S390_INT_VIRTIO, "virtio interrupt"}, \ + {KVM_S390_INT_SERVICE, "sclp interrupt"}, \ + {KVM_S390_INT_EMERGENCY, "sigp emergency"}, \ + {KVM_S390_INT_EXTERNAL_CALL, "sigp ext call"} + +TRACE_EVENT(kvm_s390_inject_vm, + TP_PROTO(__u64 type, __u32 parm, __u64 parm64, int who), + TP_ARGS(type, parm, parm64, who), + + TP_STRUCT__entry( + __field(__u32, inttype) + __field(__u32, parm) + __field(__u64, parm64) + __field(int, who) + ), + + TP_fast_assign( + __entry->inttype = type & 0x00000000ffffffff; + __entry->parm = parm; + __entry->parm64 = parm64; + __entry->who = who; + ), + + TP_printk("inject%s: type:%x (%s) parm:%x parm64:%llx", + (__entry->who == 1) ? " (from kernel)" : + (__entry->who == 2) ? " (from user)" : "", + __entry->inttype, + __print_symbolic(__entry->inttype, kvm_s390_int_type), + __entry->parm, __entry->parm64) + ); + +TRACE_EVENT(kvm_s390_inject_vcpu, + TP_PROTO(unsigned int id, __u64 type, __u32 parm, __u64 parm64, \ + int who), + TP_ARGS(id, type, parm, parm64, who), + + TP_STRUCT__entry( + __field(int, id) + __field(__u32, inttype) + __field(__u32, parm) + __field(__u64, parm64) + __field(int, who) + ), + + TP_fast_assign( + __entry->id = id; + __entry->inttype = type & 0x00000000ffffffff; + __entry->parm = parm; + __entry->parm64 = parm64; + __entry->who = who; + ), + + TP_printk("inject%s (vcpu %d): type:%x (%s) parm:%x parm64:%llx", + (__entry->who == 1) ? " (from kernel)" : + (__entry->who == 2) ? " (from user)" : "", + __entry->id, __entry->inttype, + __print_symbolic(__entry->inttype, kvm_s390_int_type), + __entry->parm, __entry->parm64) + ); + +/* + * Trace point for the actual delivery of interrupts. + */ +TRACE_EVENT(kvm_s390_deliver_interrupt, + TP_PROTO(unsigned int id, __u64 type, __u32 data0, __u64 data1), + TP_ARGS(id, type, data0, data1), + + TP_STRUCT__entry( + __field(int, id) + __field(__u32, inttype) + __field(__u32, data0) + __field(__u64, data1) + ), + + TP_fast_assign( + __entry->id = id; + __entry->inttype = type & 0x00000000ffffffff; + __entry->data0 = data0; + __entry->data1 = data1; + ), + + TP_printk("deliver interrupt (vcpu %d): type:%x (%s) " \ + "data:%08x %016llx", + __entry->id, __entry->inttype, + __print_symbolic(__entry->inttype, kvm_s390_int_type), + __entry->data0, __entry->data1) + ); + +/* + * Trace point for resets that may be requested from userspace. + */ +TRACE_EVENT(kvm_s390_request_resets, + TP_PROTO(__u64 resets), + TP_ARGS(resets), + + TP_STRUCT__entry( + __field(__u64, resets) + ), + + TP_fast_assign( + __entry->resets = resets; + ), + + TP_printk("requesting userspace resets %llx", + __entry->resets) + ); + +/* + * Trace point for a vcpu's stop requests. + */ +TRACE_EVENT(kvm_s390_stop_request, + TP_PROTO(unsigned int action_bits), + TP_ARGS(action_bits), + + TP_STRUCT__entry( + __field(unsigned int, action_bits) + ), + + TP_fast_assign( + __entry->action_bits = action_bits; + ), + + TP_printk("stop request, action_bits = %08x", + __entry->action_bits) + ); + + +#endif /* _TRACE_KVMS390_H */ + +/* This part must be outside protection */ +#include From 20b46e59dd102665ce7168baa215e5b1ee66b69b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 26 Jul 2012 11:16:14 +0200 Subject: [PATCH 0131/5375] drm/i915: Only set the down rps limit when at the loweset frequency The power docs say that when the gt leaves rc6, it is in the lowest frequency and only about 25 usec later will switch to the frequency selected in GEN6_RPNSWREQ. If the downclock limit expires in that window and the down limit is set to the lowest possible frequency, the hw will not send the down interrupt. Which leads to a too high gpu clock and wasted power. Chris Wilson already worked on this with commit 7b9e0ae6da0a7eaf2680a1a788f08df123724f3b Author: Chris Wilson Date: Sat Apr 28 08:56:39 2012 +0100 drm/i915: Always update RPS interrupts thresholds along with frequency but got the logic inverted: The current code set the down limit as long as we haven't reached it. Instead of only once with reached the lowest frequency. Note that we can't always set the downclock limit to 0, because otherwise the hw will keep on bugging us with downclock request irqs once the lowest level is reached. For similar reasons also always set the upclock limit, otherwise the hw might poke us again with interrupts. v2: Chris Wilson noticed that the limit reg is also computed in sanitize_pm. To avoid duplication, extract the code into a common function. Reviewed-by: Chris Wilson Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 39 +++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 85d1b1c57df2..e8727da06b0b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2267,21 +2267,33 @@ static void ironlake_disable_drps(struct drm_device *dev) } -void gen6_set_rps(struct drm_device *dev, u8 val) +static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 val) { - struct drm_i915_private *dev_priv = dev->dev_private; u32 limits; limits = 0; if (val >= dev_priv->max_delay) val = dev_priv->max_delay; - else - limits |= dev_priv->max_delay << 24; + limits |= dev_priv->max_delay << 24; - if (val <= dev_priv->min_delay) + /* Only set the down limit when we've reached the lowest level to avoid + * getting more interrupts, otherwise leave this clear. This prevents a + * race in the hw when coming out of rc6: There's a tiny window where + * the hw runs at the minimal clock before selecting the desired + * frequency, if the down threshold expires in that window we will not + * receive a down interrupt. */ + if (val <= dev_priv->min_delay) { val = dev_priv->min_delay; - else limits |= dev_priv->min_delay << 16; + } + + return limits; +} + +void gen6_set_rps(struct drm_device *dev, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 limits = gen6_rps_limits(dev_priv, val); if (val == dev_priv->cur_delay) return; @@ -3741,25 +3753,20 @@ void intel_init_clock_gating(struct drm_device *dev) static void gen6_sanitize_pm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 limits, delay, old; + u32 limits, current_limits; gen6_gt_force_wake_get(dev_priv); - old = limits = I915_READ(GEN6_RP_INTERRUPT_LIMITS); + current_limits = I915_READ(GEN6_RP_INTERRUPT_LIMITS); /* Make sure we continue to get interrupts * until we hit the minimum or maximum frequencies. */ - limits &= ~(0x3f << 16 | 0x3f << 24); - delay = dev_priv->cur_delay; - if (delay < dev_priv->max_delay) - limits |= (dev_priv->max_delay & 0x3f) << 24; - if (delay > dev_priv->min_delay) - limits |= (dev_priv->min_delay & 0x3f) << 16; + limits = gen6_rps_limits(dev_priv, dev_priv->cur_delay); - if (old != limits) { + if (current_limits != limits) { /* Note that the known failure case is to read back 0. */ DRM_DEBUG_DRIVER("Power management discrepancy: GEN6_RP_INTERRUPT_LIMITS " - "expected %08x, was %08x\n", limits, old); + "expected %08x, was %08x\n", limits, current_limits); I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); } From acbe9475505de68540fab8653131d41d424c4fa3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 26 Jul 2012 11:50:05 +0200 Subject: [PATCH 0132/5375] drm/i915: rip out sanitize_pm again We believe to have squashed all issues around the gen6+ rps interrupt generation and why the gpu sometimes got stuck. With that cleared up, there's no user left for the sanitize_pm infrastructure, so let's just rip it out. Note that 'intel_reg_write 0xa014 0x13070000' is the w/a if we find ourselves stuck again. Acked-by: Chris Wilson Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_display.c | 2 -- drivers/gpu/drm/i915/intel_drv.h | 2 -- drivers/gpu/drm/i915/intel_pm.c | 39 ++++------------------------ 4 files changed, 5 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0dc89a42a80a..0b2eb17fb381 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -249,7 +249,6 @@ struct drm_i915_display_funcs { void (*update_wm)(struct drm_device *dev); void (*update_sprite_wm)(struct drm_device *dev, int pipe, uint32_t sprite_width, int pixel_size); - void (*sanitize_pm)(struct drm_device *dev); void (*update_linetime_wm)(struct drm_device *dev, int pipe, struct drm_display_mode *mode); int (*crtc_mode_set)(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b463829b92eb..17020cdff338 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5929,13 +5929,11 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc) void intel_mark_busy(struct drm_device *dev) { - intel_sanitize_pm(dev); i915_update_gfx_val(dev->dev_private); } void intel_mark_idle(struct drm_device *dev) { - intel_sanitize_pm(dev); } void intel_mark_fb_busy(struct drm_i915_gem_object *obj) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8c7f48310842..13f0467c1f4d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -390,8 +390,6 @@ extern int intel_plane_init(struct drm_device *dev, enum pipe pipe); extern void intel_flush_display_plane(struct drm_i915_private *dev_priv, enum plane plane); -void intel_sanitize_pm(struct drm_device *dev); - /* intel_panel.c */ extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e8727da06b0b..d0ce894ba6e6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2267,6 +2267,11 @@ static void ironlake_disable_drps(struct drm_device *dev) } +/* There's a funny hw issue where the hw returns all 0 when reading from + * GEN6_RP_INTERRUPT_LIMITS. Hence we always need to compute the desired value + * ourselves, instead of doing a rmw cycle (which might result in us clearing + * all limits and the gpu stuck at whatever frequency it is at atm). + */ static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 val) { u32 limits; @@ -3750,37 +3755,6 @@ void intel_init_clock_gating(struct drm_device *dev) dev_priv->display.init_pch_clock_gating(dev); } -static void gen6_sanitize_pm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 limits, current_limits; - - gen6_gt_force_wake_get(dev_priv); - - current_limits = I915_READ(GEN6_RP_INTERRUPT_LIMITS); - /* Make sure we continue to get interrupts - * until we hit the minimum or maximum frequencies. - */ - limits = gen6_rps_limits(dev_priv, dev_priv->cur_delay); - - if (current_limits != limits) { - /* Note that the known failure case is to read back 0. */ - DRM_DEBUG_DRIVER("Power management discrepancy: GEN6_RP_INTERRUPT_LIMITS " - "expected %08x, was %08x\n", limits, current_limits); - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); - } - - gen6_gt_force_wake_put(dev_priv); -} - -void intel_sanitize_pm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->display.sanitize_pm) - dev_priv->display.sanitize_pm(dev); -} - /* Starting with Haswell, we have different power wells for * different parts of the GPU. This attempts to enable them all. */ @@ -3866,7 +3840,6 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.update_wm = NULL; } dev_priv->display.init_clock_gating = gen6_init_clock_gating; - dev_priv->display.sanitize_pm = gen6_sanitize_pm; } else if (IS_IVYBRIDGE(dev)) { /* FIXME: detect B0+ stepping and use auto training */ if (SNB_READ_WM0_LATENCY()) { @@ -3878,7 +3851,6 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.update_wm = NULL; } dev_priv->display.init_clock_gating = ivybridge_init_clock_gating; - dev_priv->display.sanitize_pm = gen6_sanitize_pm; } else if (IS_HASWELL(dev)) { if (SNB_READ_WM0_LATENCY()) { dev_priv->display.update_wm = sandybridge_update_wm; @@ -3890,7 +3862,6 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.update_wm = NULL; } dev_priv->display.init_clock_gating = haswell_init_clock_gating; - dev_priv->display.sanitize_pm = gen6_sanitize_pm; } else dev_priv->display.update_wm = NULL; } else if (IS_VALLEYVIEW(dev)) { From ab3951eb74e7c33a2f5b7b64d72e82f1eea61571 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Mon, 18 Jun 2012 19:03:38 -0300 Subject: [PATCH 0133/5375] drm/i915: prevent possible pin leak on error path We should not hit this under any sane conditions, but still, this does not looks right. CC: Chris Wilson CC: Daniel Vetter CC: stable@vger.kernel.org Reported-by: Herton Ronaldo Krzesinski Reviewed-by: Chris Wlison Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 17020cdff338..2e1f28f38ee9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6317,7 +6317,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, default: WARN_ONCE(1, "unknown plane in flip command\n"); ret = -ENODEV; - goto err; + goto err_unpin; } ret = intel_ring_begin(ring, 4); From 7d0642b93780a7309d2954de6f6126d6ceb526f0 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 11 Jul 2012 15:03:18 -0400 Subject: [PATCH 0134/5375] xen/perf: Define .glob for the different hypercalls. This allows us in perf to have this: 99.67% [kernel] [k] xen_hypercall_sched_op 0.11% [kernel] [k] xen_hypercall_xen_version instead of the borring ever-encompassing: 99.13% [kernel] [k] hypercall_page [v2: Use a macro to define the name and skip] [v3: Use balign per Jan's suggestion] Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/xen/xen-head.S | 56 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S index aaa7291c9259..7faed5869e5b 100644 --- a/arch/x86/xen/xen-head.S +++ b/arch/x86/xen/xen-head.S @@ -28,9 +28,61 @@ ENTRY(startup_xen) __FINIT .pushsection .text - .align PAGE_SIZE + .balign PAGE_SIZE ENTRY(hypercall_page) - .skip PAGE_SIZE +#define NEXT_HYPERCALL(x) \ + ENTRY(xen_hypercall_##x) \ + .skip 32 + +NEXT_HYPERCALL(set_trap_table) +NEXT_HYPERCALL(mmu_update) +NEXT_HYPERCALL(set_gdt) +NEXT_HYPERCALL(stack_switch) +NEXT_HYPERCALL(set_callbacks) +NEXT_HYPERCALL(fpu_taskswitch) +NEXT_HYPERCALL(sched_op_compat) +NEXT_HYPERCALL(platform_op) +NEXT_HYPERCALL(set_debugreg) +NEXT_HYPERCALL(get_debugreg) +NEXT_HYPERCALL(update_descriptor) +NEXT_HYPERCALL(ni) +NEXT_HYPERCALL(memory_op) +NEXT_HYPERCALL(multicall) +NEXT_HYPERCALL(update_va_mapping) +NEXT_HYPERCALL(set_timer_op) +NEXT_HYPERCALL(event_channel_op_compat) +NEXT_HYPERCALL(xen_version) +NEXT_HYPERCALL(console_io) +NEXT_HYPERCALL(physdev_op_compat) +NEXT_HYPERCALL(grant_table_op) +NEXT_HYPERCALL(vm_assist) +NEXT_HYPERCALL(update_va_mapping_otherdomain) +NEXT_HYPERCALL(iret) +NEXT_HYPERCALL(vcpu_op) +NEXT_HYPERCALL(set_segment_base) +NEXT_HYPERCALL(mmuext_op) +NEXT_HYPERCALL(xsm_op) +NEXT_HYPERCALL(nmi_op) +NEXT_HYPERCALL(sched_op) +NEXT_HYPERCALL(callback_op) +NEXT_HYPERCALL(xenoprof_op) +NEXT_HYPERCALL(event_channel_op) +NEXT_HYPERCALL(physdev_op) +NEXT_HYPERCALL(hvm_op) +NEXT_HYPERCALL(sysctl) +NEXT_HYPERCALL(domctl) +NEXT_HYPERCALL(kexec_op) +NEXT_HYPERCALL(tmem_op) /* 38 */ +ENTRY(xen_hypercall_rsvr) + .skip 320 +NEXT_HYPERCALL(mca) /* 48 */ +NEXT_HYPERCALL(arch_1) +NEXT_HYPERCALL(arch_2) +NEXT_HYPERCALL(arch_3) +NEXT_HYPERCALL(arch_4) +NEXT_HYPERCALL(arch_5) +NEXT_HYPERCALL(arch_6) + .balign PAGE_SIZE .popsection ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") From 4a4541a40e1fe145c72c4b959fac524a5600d9fb Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 22 Jul 2012 17:41:00 +0300 Subject: [PATCH 0135/5375] KVM: Don't update PPR on any APIC read The current code will update the PPR on almost any APIC read; however that's only required if we read the PPR. kvm_update_ppr() shows up in some profiles, albeit with a low usage (~1%). This should reduce it further (it will still be called during interrupt processing). Signed-off-by: Avi Kivity Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/lapic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index fff7173f6a71..ad7fff7ad13c 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -696,12 +696,14 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset) val = apic_get_tmcct(apic); break; - + case APIC_PROCPRI: + apic_update_ppr(apic); + val = apic_get_reg(apic, offset); + break; case APIC_TASKPRI: report_tpr_access(apic, false); /* fall thru */ default: - apic_update_ppr(apic); val = apic_get_reg(apic, offset); break; } From b42353011e9001e88f5a57097dcf7d9424a0e9c4 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 26 Jul 2012 02:23:33 -0300 Subject: [PATCH 0136/5375] [media] s5k6aa: Add missing static storage class specifier Fixes the following sparse warning: drivers/media/video/s5k6aa.c:1439:5: warning: symbol 's5k6aa_check_fw_revision' was not declared. Should it be static? Signed-off-by: Sachin Kamat Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5k6aa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/s5k6aa.c b/drivers/media/video/s5k6aa.c index 6625e46a4638..decb64808346 100644 --- a/drivers/media/video/s5k6aa.c +++ b/drivers/media/video/s5k6aa.c @@ -1436,7 +1436,7 @@ static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return 0; } -int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa) +static int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa) { struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); u16 api_ver = 0, fw_rev = 0; From bc7892c2142ce1eb1b0792337391414728cddf9e Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Thu, 26 Jul 2012 11:31:51 -0300 Subject: [PATCH 0137/5375] [media] omap3isp: #include videodev2.h in omap3isp.h include/linux/omap3isp.h uses BASE_VIDIOC_PRIVATE from include/linux/videodev2.h but didn't include this file. Signed-off-by: Michael Jones Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- include/linux/omap3isp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/omap3isp.h b/include/linux/omap3isp.h index c73a34c3434d..e7a79db3c1f7 100644 --- a/include/linux/omap3isp.h +++ b/include/linux/omap3isp.h @@ -28,6 +28,7 @@ #define OMAP3_ISP_USER_H #include +#include /* * Private IOCTLs From 47c75f773c3dc4a4c3520f40c154792585935980 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Thu, 26 Jul 2012 12:44:19 -0300 Subject: [PATCH 0138/5375] [media] cx25840: Declare MODULE_FIRMWARE usage Signed-off-by: Tim Gardner Acked-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-firmware.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index 8150200511da..b3169f94ece8 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c @@ -61,6 +61,10 @@ static void end_fw_load(struct i2c_client *client) cx25840_write(client, 0x803, 0x03); } +#define CX2388x_FIRMWARE "v4l-cx23885-avcore-01.fw" +#define CX231xx_FIRMWARE "v4l-cx231xx-avcore-01.fw" +#define CX25840_FIRMWARE "v4l-cx25840.fw" + static const char *get_fw_name(struct i2c_client *client) { struct cx25840_state *state = to_state(i2c_get_clientdata(client)); @@ -68,10 +72,10 @@ static const char *get_fw_name(struct i2c_client *client) if (firmware[0]) return firmware; if (is_cx2388x(state)) - return "v4l-cx23885-avcore-01.fw"; + return CX2388x_FIRMWARE; if (is_cx231xx(state)) - return "v4l-cx231xx-avcore-01.fw"; - return "v4l-cx25840.fw"; + return CX231xx_FIRMWARE; + return CX25840_FIRMWARE; } static int check_fw_load(struct i2c_client *client, int size) @@ -164,3 +168,8 @@ int cx25840_loadfw(struct i2c_client *client) return check_fw_load(client, size); } + +MODULE_FIRMWARE(CX2388x_FIRMWARE); +MODULE_FIRMWARE(CX231xx_FIRMWARE); +MODULE_FIRMWARE(CX25840_FIRMWARE); + From eb3058e78c45f203616b1a4cd4132b6d32d0281a Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Thu, 26 Jul 2012 14:26:20 -0300 Subject: [PATCH 0139/5375] [media] ivtv: Declare MODULE_FIRMWARE usage Signed-off-by: Tim Gardner Acked-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-firmware.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c index 02c5adebf517..6ec7705af555 100644 --- a/drivers/media/video/ivtv/ivtv-firmware.c +++ b/drivers/media/video/ivtv/ivtv-firmware.c @@ -396,3 +396,7 @@ int ivtv_firmware_check(struct ivtv *itv, char *where) return res; } + +MODULE_FIRMWARE(CX2341X_FIRM_ENC_FILENAME); +MODULE_FIRMWARE(CX2341X_FIRM_DEC_FILENAME); +MODULE_FIRMWARE(IVTV_DECODE_INIT_MPEG_FILENAME); From b8320e95f77023858a56992bfef70edc20cc6abd Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Thu, 26 Jul 2012 14:34:22 -0300 Subject: [PATCH 0140/5375] [media] cx231xx: Declare MODULE_FIRMWARE usage Cc: Hans Verkuil Signed-off-by: Tim Gardner Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx231xx/cx231xx-417.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c index ce2f62238a19..b024e5197a75 100644 --- a/drivers/media/video/cx231xx/cx231xx-417.c +++ b/drivers/media/video/cx231xx/cx231xx-417.c @@ -2193,3 +2193,5 @@ int cx231xx_417_register(struct cx231xx *dev) return 0; } + +MODULE_FIRMWARE(CX231xx_FIRM_IMAGE_NAME); From 583087f567ca370c63b7e6b078fb550914b0049e Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Thu, 26 Jul 2012 14:39:24 -0300 Subject: [PATCH 0141/5375] [media] cx23885: Declare MODULE_FIRMWARE usage Cc: Steven Toth Cc: Hans Verkuil Signed-off-by: Tim Gardner Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-417.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index f5c79e53e5a1..5d5052d0253f 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1786,3 +1786,5 @@ int cx23885_417_register(struct cx23885_dev *dev) return 0; } + +MODULE_FIRMWARE(CX23885_FIRM_IMAGE_NAME); From 740a3ea20d4070d3f2e4fadb8771f1fdac7d4abe Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Thu, 26 Jul 2012 14:57:07 -0300 Subject: [PATCH 0142/5375] [media] pvrusb2: Declare MODULE_FIRMWARE usage Signed-off-by: Tim Gardner Acked-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-devattr.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index d8c898278e8c..adc501d3c287 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -54,8 +54,9 @@ static const struct pvr2_device_client_desc pvr2_cli_29xxx[] = { { .module_id = PVR2_CLIENT_ID_DEMOD }, }; +#define PVR2_FIRMWARE_29xxx "v4l-pvrusb2-29xxx-01.fw" static const char *pvr2_fw1_names_29xxx[] = { - "v4l-pvrusb2-29xxx-01.fw", + PVR2_FIRMWARE_29xxx, }; static const struct pvr2_device_desc pvr2_device_29xxx = { @@ -87,8 +88,9 @@ static const struct pvr2_device_client_desc pvr2_cli_24xxx[] = { { .module_id = PVR2_CLIENT_ID_DEMOD }, }; +#define PVR2_FIRMWARE_24xxx "v4l-pvrusb2-24xxx-01.fw" static const char *pvr2_fw1_names_24xxx[] = { - "v4l-pvrusb2-24xxx-01.fw", + PVR2_FIRMWARE_24xxx, }; static const struct pvr2_device_desc pvr2_device_24xxx = { @@ -369,8 +371,9 @@ static const struct pvr2_device_client_desc pvr2_cli_73xxx[] = { .i2c_address_list = "\x42"}, }; +#define PVR2_FIRMWARE_73xxx "v4l-pvrusb2-73xxx-01.fw" static const char *pvr2_fw1_names_73xxx[] = { - "v4l-pvrusb2-73xxx-01.fw", + PVR2_FIRMWARE_73xxx, }; static const struct pvr2_device_desc pvr2_device_73xxx = { @@ -475,8 +478,9 @@ static const struct pvr2_dvb_props pvr2_751xx_dvb_props = { }; #endif +#define PVR2_FIRMWARE_75xxx "v4l-pvrusb2-73xxx-01.fw" static const char *pvr2_fw1_names_75xxx[] = { - "v4l-pvrusb2-73xxx-01.fw", + PVR2_FIRMWARE_75xxx, }; static const struct pvr2_device_desc pvr2_device_750xx = { @@ -556,7 +560,10 @@ struct usb_device_id pvr2_device_table[] = { }; MODULE_DEVICE_TABLE(usb, pvr2_device_table); - +MODULE_FIRMWARE(PVR2_FIRMWARE_29xxx); +MODULE_FIRMWARE(PVR2_FIRMWARE_24xxx); +MODULE_FIRMWARE(PVR2_FIRMWARE_73xxx); +MODULE_FIRMWARE(PVR2_FIRMWARE_75xxx); /* Stuff for Emacs to see, in order to encourage consistent editing style: From 8a7bf1d446bcaeed3b1f2a4dcb2f033dcdfc0827 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Fri, 27 Jul 2012 12:45:21 -0300 Subject: [PATCH 0143/5375] [media] cx18: Declare MODULE_FIRMWARE usage Signed-off-by: Tim Gardner Acked-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-av-firmware.c | 2 ++ drivers/media/video/cx18/cx18-driver.c | 1 + drivers/media/video/cx18/cx18-dvb.c | 6 +++++- drivers/media/video/cx18/cx18-firmware.c | 10 ++++++++-- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c index 280aa4d22488..a34fd082b76e 100644 --- a/drivers/media/video/cx18/cx18-av-firmware.c +++ b/drivers/media/video/cx18/cx18-av-firmware.c @@ -221,3 +221,5 @@ int cx18_av_loadfw(struct cx18 *cx) release_firmware(fw); return 0; } + +MODULE_FIRMWARE(FWFILE); diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 7e5ffd6f5178..c67733d32c8a 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -1357,3 +1357,4 @@ static void __exit module_cleanup(void) module_init(module_start); module_exit(module_cleanup); +MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE); diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index f41922bd4020..3eac59c51231 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c @@ -40,6 +40,8 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +#define FWFILE "dvb-cx18-mpc718-mt352.fw" + #define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000 #define CX18_CLOCK_ENABLE2 0xc71024 #define CX18_DMUX_CLK_MASK 0x0080 @@ -135,7 +137,7 @@ static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream, const struct firmware **fw) { struct cx18 *cx = stream->cx; - const char *fn = "dvb-cx18-mpc718-mt352.fw"; + const char *fn = FWFILE; int ret; ret = request_firmware(fw, fn, &cx->pci_dev->dev); @@ -603,3 +605,5 @@ static int dvb_register(struct cx18_stream *stream) return ret; } + +MODULE_FIRMWARE(FWFILE); diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c index b85c292a849a..a1c1cec05f98 100644 --- a/drivers/media/video/cx18/cx18-firmware.c +++ b/drivers/media/video/cx18/cx18-firmware.c @@ -376,6 +376,9 @@ void cx18_init_memory(struct cx18 *cx) cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14); /* AVO */ } +#define CX18_CPU_FIRMWARE "v4l-cx23418-cpu.fw" +#define CX18_APU_FIRMWARE "v4l-cx23418-apu.fw" + int cx18_firmware_init(struct cx18 *cx) { u32 fw_entry_addr; @@ -400,7 +403,7 @@ int cx18_firmware_init(struct cx18 *cx) cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); - sz = load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx); + sz = load_cpu_fw_direct(CX18_CPU_FIRMWARE, cx->enc_mem, cx); if (sz <= 0) return sz; @@ -408,7 +411,7 @@ int cx18_firmware_init(struct cx18 *cx) cx18_init_scb(cx); fw_entry_addr = 0; - sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx, + sz = load_apu_fw_direct(CX18_APU_FIRMWARE, cx->enc_mem, cx, &fw_entry_addr); if (sz <= 0) return sz; @@ -451,3 +454,6 @@ int cx18_firmware_init(struct cx18 *cx) cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400); return 0; } + +MODULE_FIRMWARE(CX18_CPU_FIRMWARE); +MODULE_FIRMWARE(CX18_APU_FIRMWARE); From 076f0e359e308dae67821196f56d36d6648f9086 Mon Sep 17 00:00:00 2001 From: Djuri Baars Date: Sat, 28 Jul 2012 09:01:38 -0300 Subject: [PATCH 0144/5375] [media] Add support for the Terratec Cinergy T Dual PCIe IR remote The following patch adds support for the infrared remote included in the Terratec Cinergy T Dual PCIe card. Signed-off-by: Djuri Baars Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 4 ++++ drivers/media/video/cx23885/cx23885-input.c | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 080e11157e5f..d365e9a8efc4 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -46,6 +46,7 @@ MODULE_PARM_DESC(enable_885_ir, "Enable integrated IR controller for supported\n" "\t\t CX2388[57] boards that are wired for it:\n" "\t\t\tHVR-1250 (reported safe)\n" + "\t\t\tTerraTec Cinergy T PCIe Dual (not well tested, appears to be safe)\n" "\t\t\tTeVii S470 (reported unsafe)\n" "\t\t This can cause an interrupt storm with some cards.\n" "\t\t Default: 0 [Disabled]"); @@ -1363,6 +1364,7 @@ int cx23885_ir_init(struct cx23885_dev *dev) params.shutdown = true; v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, ¶ms); break; + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: case CX23885_BOARD_TEVII_S470: if (!enable_885_ir) break; @@ -1403,6 +1405,7 @@ void cx23885_ir_fini(struct cx23885_dev *dev) cx23888_ir_remove(dev); dev->sd_ir = NULL; break; + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: case CX23885_BOARD_TEVII_S470: case CX23885_BOARD_HAUPPAUGE_HVR1250: cx23885_irq_remove(dev, PCI_MSK_AV_CORE); @@ -1446,6 +1449,7 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev) if (dev->sd_ir) cx23885_irq_add_enable(dev, PCI_MSK_IR); break; + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: case CX23885_BOARD_TEVII_S470: case CX23885_BOARD_HAUPPAUGE_HVR1250: if (dev->sd_ir) diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c index ce765e3f77bd..56066721edc1 100644 --- a/drivers/media/video/cx23885/cx23885-input.c +++ b/drivers/media/video/cx23885/cx23885-input.c @@ -85,6 +85,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) case CX23885_BOARD_HAUPPAUGE_HVR1270: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1290: + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: case CX23885_BOARD_TEVII_S470: case CX23885_BOARD_HAUPPAUGE_HVR1250: /* @@ -162,6 +163,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev) */ params.invert_level = true; break; + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: case CX23885_BOARD_TEVII_S470: /* * The IR controller on this board only returns pulse widths. @@ -272,6 +274,13 @@ int cx23885_input_init(struct cx23885_dev *dev) /* The grey Hauppauge RC-5 remote */ rc_map = RC_MAP_HAUPPAUGE; break; + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: + /* Integrated CX23885 IR controller */ + driver_type = RC_DRIVER_IR_RAW; + allowed_protos = RC_TYPE_NEC; + /* The grey Terratec remote with orange buttons */ + rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS; + break; case CX23885_BOARD_TEVII_S470: /* Integrated CX23885 IR controller */ driver_type = RC_DRIVER_IR_RAW; From 660e22c7b008f1b21283cc2d786b2dd7c7790440 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 30 Jul 2012 05:08:47 -0300 Subject: [PATCH 0145/5375] [media] v4l: Add missing compatibility definitions for bounds rectangles Compatibility defines for ACTUAL subdev selection rectangles were added and also the name of the BOUNDS rectangles was changed in the process, which, alas, went unnoticed until now. Add compatibility definitions for these rectangles. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- include/linux/v4l2-common.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/v4l2-common.h b/include/linux/v4l2-common.h index 0fa8b64c3cdb..4f0667e010dd 100644 --- a/include/linux/v4l2-common.h +++ b/include/linux/v4l2-common.h @@ -53,10 +53,10 @@ /* Backward compatibility target definitions --- to be removed. */ #define V4L2_SEL_TGT_CROP_ACTIVE V4L2_SEL_TGT_CROP #define V4L2_SEL_TGT_COMPOSE_ACTIVE V4L2_SEL_TGT_COMPOSE -#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL \ - V4L2_SEL_TGT_CROP -#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL \ - V4L2_SEL_TGT_COMPOSE +#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL V4L2_SEL_TGT_CROP +#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL V4L2_SEL_TGT_COMPOSE +#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS V4L2_SEL_TGT_CROP_BOUNDS +#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS V4L2_SEL_TGT_COMPOSE_BOUNDS /* Selection flags */ #define V4L2_SEL_FLAG_GE (1 << 0) From 24ed693da0cefede7382d498dd5e9a83f0a21c38 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 30 Jul 2012 14:03:16 -0300 Subject: [PATCH 0146/5375] [media] DVB: dib0700, remove double \n's from log err() already adds \n to the end of the format string. So remove one more \n from formatting strings in the dib0700 driver. Signed-off-by: Jiri Slaby Cc: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 7e9e00fae04e..ef87229de6af 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -768,13 +768,13 @@ int dib0700_rc_setup(struct dvb_usb_device *d) /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ purb = usb_alloc_urb(0, GFP_KERNEL); if (purb == NULL) { - err("rc usb alloc urb failed\n"); + err("rc usb alloc urb failed"); return -ENOMEM; } purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL); if (purb->transfer_buffer == NULL) { - err("rc kzalloc failed\n"); + err("rc kzalloc failed"); usb_free_urb(purb); return -ENOMEM; } @@ -786,7 +786,7 @@ int dib0700_rc_setup(struct dvb_usb_device *d) ret = usb_submit_urb(purb, GFP_ATOMIC); if (ret) { - err("rc submit urb failed\n"); + err("rc submit urb failed"); kfree(purb->transfer_buffer); usb_free_urb(purb); } From fed57cd375ece6d271e45d9ad630c7de632e74b6 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 20 Jul 2012 13:31:08 +0530 Subject: [PATCH 0147/5375] dma: tegra: enable/disable dma clock Enable the DMA clock when allocating channel and disable clock when freeing channels. Signed-off-by: Laxman Dewangan Signed-off-by: Vinod Koul --- drivers/dma/tegra20-apb-dma.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index d52dbc6c54ab..24acd711e032 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -1119,15 +1119,21 @@ struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic( static int tegra_dma_alloc_chan_resources(struct dma_chan *dc) { struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); + struct tegra_dma *tdma = tdc->tdma; + int ret; dma_cookie_init(&tdc->dma_chan); tdc->config_init = false; - return 0; + ret = clk_prepare_enable(tdma->dma_clk); + if (ret < 0) + dev_err(tdc2dev(tdc), "clk_prepare_enable failed: %d\n", ret); + return ret; } static void tegra_dma_free_chan_resources(struct dma_chan *dc) { struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); + struct tegra_dma *tdma = tdc->tdma; struct tegra_dma_desc *dma_desc; struct tegra_dma_sg_req *sg_req; @@ -1163,6 +1169,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc) list_del(&sg_req->node); kfree(sg_req); } + clk_disable_unprepare(tdma->dma_clk); } /* Tegra20 specific DMA controller information */ @@ -1255,6 +1262,13 @@ static int __devinit tegra_dma_probe(struct platform_device *pdev) } } + /* Enable clock before accessing registers */ + ret = clk_prepare_enable(tdma->dma_clk); + if (ret < 0) { + dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret); + goto err_pm_disable; + } + /* Reset DMA controller */ tegra_periph_reset_assert(tdma->dma_clk); udelay(2); @@ -1265,6 +1279,8 @@ static int __devinit tegra_dma_probe(struct platform_device *pdev) tdma_write(tdma, TEGRA_APBDMA_CONTROL, 0); tdma_write(tdma, TEGRA_APBDMA_IRQ_MASK_SET, 0xFFFFFFFFul); + clk_disable_unprepare(tdma->dma_clk); + INIT_LIST_HEAD(&tdma->dma_dev.channels); for (i = 0; i < cdata->nr_channels; i++) { struct tegra_dma_channel *tdc = &tdma->channels[i]; From 2f2da1e2995c9362babd7da3cc9d340be184ea73 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 31 Jul 2012 16:38:41 -0300 Subject: [PATCH 0148/5375] [media] radio-tea5777: use library for 64bits div drivers/built-in.o: In function `radio_tea5777_set_freq': radio-tea5777.c:(.text+0x4d8704): undefined reference to `__udivdi3' Reported-by: Randy Dunlap Cc: Hans de Goede Acked-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-tea5777.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c index 3e12179364f8..5bc9fa62720b 100644 --- a/drivers/media/radio/radio-tea5777.c +++ b/drivers/media/radio/radio-tea5777.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "radio-tea5777.h" MODULE_AUTHOR("Hans de Goede "); @@ -158,10 +159,11 @@ static int radio_tea5777_set_freq(struct radio_tea5777 *tea) int res; freq = clamp_t(u32, tea->freq, - TEA5777_FM_RANGELOW, TEA5777_FM_RANGEHIGH); - freq = (freq + 8) / 16; /* to kHz */ + TEA5777_FM_RANGELOW, TEA5777_FM_RANGEHIGH) + 8; + do_div(freq, 16); /* to kHz */ - freq = (freq - TEA5777_FM_IF) / TEA5777_FM_FREQ_STEP; + freq -= TEA5777_FM_IF; + do_div(freq, TEA5777_FM_FREQ_STEP); tea->write_reg &= ~(TEA5777_W_FM_PLL_MASK | TEA5777_W_FM_FREF_MASK); tea->write_reg |= freq << TEA5777_W_FM_PLL_SHIFT; From e9d90d472da97e1b1560bffb89578ba082c88a69 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 26 Jul 2012 18:01:50 +0300 Subject: [PATCH 0149/5375] KVM: Remove internal timer abstraction kvm_timer_fn(), the sole inhabitant of timer.c, is only used by lapic.c. Move it there to make it easier to hack on it. struct kvm_timer is a thin wrapper around hrtimer, and only adds obfuscation. Move near its two users (with different names) to prepare for simplification. Signed-off-by: Avi Kivity Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/Makefile | 2 +- arch/x86/kvm/i8254.c | 8 +++---- arch/x86/kvm/i8254.h | 18 ++++++++++++++- arch/x86/kvm/kvm_timer.h | 18 --------------- arch/x86/kvm/lapic.c | 30 ++++++++++++++++++++++++- arch/x86/kvm/lapic.h | 17 ++++++++++++++- arch/x86/kvm/timer.c | 47 ---------------------------------------- 7 files changed, 67 insertions(+), 73 deletions(-) delete mode 100644 arch/x86/kvm/kvm_timer.h delete mode 100644 arch/x86/kvm/timer.c diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index 4f579e8dcacf..04d30401c5cb 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -12,7 +12,7 @@ kvm-$(CONFIG_IOMMU_API) += $(addprefix ../../../virt/kvm/, iommu.o) kvm-$(CONFIG_KVM_ASYNC_PF) += $(addprefix ../../../virt/kvm/, async_pf.o) kvm-y += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \ - i8254.o timer.o cpuid.o pmu.o + i8254.o cpuid.o pmu.o kvm-intel-y += vmx.o kvm-amd-y += svm.o diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index adba28f88d1a..1d8e75702d95 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -272,14 +272,14 @@ static void destroy_pit_timer(struct kvm_pit *pit) flush_kthread_work(&pit->expired); } -static bool kpit_is_periodic(struct kvm_timer *ktimer) +static bool kpit_is_periodic(struct kvm_pit_timer *ktimer) { struct kvm_kpit_state *ps = container_of(ktimer, struct kvm_kpit_state, pit_timer); return ps->is_periodic; } -static struct kvm_timer_ops kpit_ops = { +static struct kvm_pit_timer_ops kpit_ops = { .is_periodic = kpit_is_periodic, }; @@ -322,7 +322,7 @@ static void pit_do_work(struct kthread_work *work) static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) { - struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer); + struct kvm_pit_timer *ktimer = container_of(data, struct kvm_pit_timer, timer); struct kvm_pit *pt = ktimer->kvm->arch.vpit; if (ktimer->reinject || !atomic_read(&ktimer->pending)) { @@ -340,7 +340,7 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) static void create_pit_timer(struct kvm *kvm, u32 val, int is_period) { struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; - struct kvm_timer *pt = &ps->pit_timer; + struct kvm_pit_timer *pt = &ps->pit_timer; s64 interval; if (!irqchip_in_kernel(kvm) || ps->flags & KVM_PIT_FLAGS_HPET_LEGACY) diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h index fdf40425ea1d..3351816e8b32 100644 --- a/arch/x86/kvm/i8254.h +++ b/arch/x86/kvm/i8254.h @@ -21,10 +21,26 @@ struct kvm_kpit_channel_state { ktime_t count_load_time; }; +struct kvm_pit_timer { + struct hrtimer timer; + s64 period; /* unit: ns */ + u32 timer_mode_mask; + u64 tscdeadline; + atomic_t pending; /* accumulated triggered timers */ + bool reinject; + struct kvm_pit_timer_ops *t_ops; + struct kvm *kvm; + struct kvm_vcpu *vcpu; +}; + +struct kvm_pit_timer_ops { + bool (*is_periodic)(struct kvm_pit_timer *); +}; + struct kvm_kpit_state { struct kvm_kpit_channel_state channels[3]; u32 flags; - struct kvm_timer pit_timer; + struct kvm_pit_timer pit_timer; bool is_periodic; u32 speaker_data_on; struct mutex lock; diff --git a/arch/x86/kvm/kvm_timer.h b/arch/x86/kvm/kvm_timer.h deleted file mode 100644 index 497dbaa366d4..000000000000 --- a/arch/x86/kvm/kvm_timer.h +++ /dev/null @@ -1,18 +0,0 @@ - -struct kvm_timer { - struct hrtimer timer; - s64 period; /* unit: ns */ - u32 timer_mode_mask; - u64 tscdeadline; - atomic_t pending; /* accumulated triggered timers */ - bool reinject; - struct kvm_timer_ops *t_ops; - struct kvm *kvm; - struct kvm_vcpu *vcpu; -}; - -struct kvm_timer_ops { - bool (*is_periodic)(struct kvm_timer *); -}; - -enum hrtimer_restart kvm_timer_fn(struct hrtimer *data); diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index ad7fff7ad13c..61ed32cd17c1 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1262,6 +1262,34 @@ static const struct kvm_io_device_ops apic_mmio_ops = { .write = apic_mmio_write, }; +static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) +{ + struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer); + struct kvm_vcpu *vcpu = ktimer->vcpu; + wait_queue_head_t *q = &vcpu->wq; + + /* + * There is a race window between reading and incrementing, but we do + * not care about potentially losing timer events in the !reinject + * case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked + * in vcpu_enter_guest. + */ + if (ktimer->reinject || !atomic_read(&ktimer->pending)) { + atomic_inc(&ktimer->pending); + /* FIXME: this code should not know anything about vcpus */ + kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu); + } + + if (waitqueue_active(q)) + wake_up_interruptible(q); + + if (ktimer->t_ops->is_periodic(ktimer)) { + hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); + return HRTIMER_RESTART; + } else + return HRTIMER_NORESTART; +} + int kvm_create_lapic(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic; @@ -1285,7 +1313,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - apic->lapic_timer.timer.function = kvm_timer_fn; + apic->lapic_timer.timer.function = apic_timer_fn; apic->lapic_timer.t_ops = &lapic_timer_ops; apic->lapic_timer.kvm = vcpu->kvm; apic->lapic_timer.vcpu = vcpu; diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 4af5405ae1e2..d7251c92ed42 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -2,10 +2,25 @@ #define __KVM_X86_LAPIC_H #include "iodev.h" -#include "kvm_timer.h" #include +struct kvm_timer { + struct hrtimer timer; + s64 period; /* unit: ns */ + u32 timer_mode_mask; + u64 tscdeadline; + atomic_t pending; /* accumulated triggered timers */ + bool reinject; + struct kvm_timer_ops *t_ops; + struct kvm *kvm; + struct kvm_vcpu *vcpu; +}; + +struct kvm_timer_ops { + bool (*is_periodic)(struct kvm_timer *); +}; + struct kvm_lapic { unsigned long base_address; struct kvm_io_device dev; diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c deleted file mode 100644 index 6b85cc647f34..000000000000 --- a/arch/x86/kvm/timer.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Kernel-based Virtual Machine driver for Linux - * - * This module enables machines with Intel VT-x extensions to run virtual - * machines without emulation or binary translation. - * - * timer support - * - * Copyright 2010 Red Hat, Inc. and/or its affiliates. - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - */ - -#include -#include -#include -#include -#include "kvm_timer.h" - -enum hrtimer_restart kvm_timer_fn(struct hrtimer *data) -{ - struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer); - struct kvm_vcpu *vcpu = ktimer->vcpu; - wait_queue_head_t *q = &vcpu->wq; - - /* - * There is a race window between reading and incrementing, but we do - * not care about potentially losing timer events in the !reinject - * case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked - * in vcpu_enter_guest. - */ - if (ktimer->reinject || !atomic_read(&ktimer->pending)) { - atomic_inc(&ktimer->pending); - /* FIXME: this code should not know anything about vcpus */ - kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu); - } - - if (waitqueue_active(q)) - wake_up_interruptible(q); - - if (ktimer->t_ops->is_periodic(ktimer)) { - hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); - return HRTIMER_RESTART; - } else - return HRTIMER_NORESTART; -} From 2a6eac9638a92b61de04bac4233d8ca665ae96af Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 26 Jul 2012 18:01:51 +0300 Subject: [PATCH 0150/5375] KVM: Simplify kvm_timer 'reinject' is never initialized 't_ops' only serves as indirection to lapic_is_periodic; call that directly instead 'kvm' is never used 'vcpu' can be derived via container_of Remove these fields. Signed-off-by: Avi Kivity Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/lapic.c | 18 +++++------------- arch/x86/kvm/lapic.h | 8 -------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 61ed32cd17c1..0cd431c85d38 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1214,10 +1214,8 @@ int kvm_lapic_enabled(struct kvm_vcpu *vcpu) *---------------------------------------------------------------------- */ -static bool lapic_is_periodic(struct kvm_timer *ktimer) +static bool lapic_is_periodic(struct kvm_lapic *apic) { - struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic, - lapic_timer); return apic_lvtt_period(apic); } @@ -1253,10 +1251,6 @@ void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu) kvm_apic_local_deliver(apic, APIC_LVT0); } -static struct kvm_timer_ops lapic_timer_ops = { - .is_periodic = lapic_is_periodic, -}; - static const struct kvm_io_device_ops apic_mmio_ops = { .read = apic_mmio_read, .write = apic_mmio_write, @@ -1265,7 +1259,8 @@ static const struct kvm_io_device_ops apic_mmio_ops = { static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) { struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer); - struct kvm_vcpu *vcpu = ktimer->vcpu; + struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic, lapic_timer); + struct kvm_vcpu *vcpu = apic->vcpu; wait_queue_head_t *q = &vcpu->wq; /* @@ -1274,7 +1269,7 @@ static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) * case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked * in vcpu_enter_guest. */ - if (ktimer->reinject || !atomic_read(&ktimer->pending)) { + if (!atomic_read(&ktimer->pending)) { atomic_inc(&ktimer->pending); /* FIXME: this code should not know anything about vcpus */ kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu); @@ -1283,7 +1278,7 @@ static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) if (waitqueue_active(q)) wake_up_interruptible(q); - if (ktimer->t_ops->is_periodic(ktimer)) { + if (lapic_is_periodic(apic)) { hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); return HRTIMER_RESTART; } else @@ -1314,9 +1309,6 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); apic->lapic_timer.timer.function = apic_timer_fn; - apic->lapic_timer.t_ops = &lapic_timer_ops; - apic->lapic_timer.kvm = vcpu->kvm; - apic->lapic_timer.vcpu = vcpu; apic->base_address = APIC_DEFAULT_PHYS_BASE; vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE; diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index d7251c92ed42..166766fffd9f 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -11,14 +11,6 @@ struct kvm_timer { u32 timer_mode_mask; u64 tscdeadline; atomic_t pending; /* accumulated triggered timers */ - bool reinject; - struct kvm_timer_ops *t_ops; - struct kvm *kvm; - struct kvm_vcpu *vcpu; -}; - -struct kvm_timer_ops { - bool (*is_periodic)(struct kvm_timer *); }; struct kvm_lapic { From 9d9d2239bdecd525ce3eb6cbfe4abb925c98208c Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 26 Jul 2012 18:01:52 +0300 Subject: [PATCH 0151/5375] KVM: Simplify kvm_pit_timer 'timer_mode_mask' is unused 'tscdeadline' is unused 't_ops' only adds needless indirection 'vcpu' is unused Remove. Signed-off-by: Avi Kivity Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/i8254.c | 14 +------------- arch/x86/kvm/i8254.h | 8 -------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 1d8e75702d95..a9e187a5b199 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -272,17 +272,6 @@ static void destroy_pit_timer(struct kvm_pit *pit) flush_kthread_work(&pit->expired); } -static bool kpit_is_periodic(struct kvm_pit_timer *ktimer) -{ - struct kvm_kpit_state *ps = container_of(ktimer, struct kvm_kpit_state, - pit_timer); - return ps->is_periodic; -} - -static struct kvm_pit_timer_ops kpit_ops = { - .is_periodic = kpit_is_periodic, -}; - static void pit_do_work(struct kthread_work *work) { struct kvm_pit *pit = container_of(work, struct kvm_pit, expired); @@ -330,7 +319,7 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) queue_kthread_work(&pt->worker, &pt->expired); } - if (ktimer->t_ops->is_periodic(ktimer)) { + if (pt->pit_state.is_periodic) { hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); return HRTIMER_RESTART; } else @@ -357,7 +346,6 @@ static void create_pit_timer(struct kvm *kvm, u32 val, int is_period) ps->is_periodic = is_period; pt->timer.function = pit_timer_fn; - pt->t_ops = &kpit_ops; pt->kvm = ps->pit->kvm; atomic_set(&pt->pending, 0); diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h index 3351816e8b32..c9bbcb889c40 100644 --- a/arch/x86/kvm/i8254.h +++ b/arch/x86/kvm/i8254.h @@ -24,17 +24,9 @@ struct kvm_kpit_channel_state { struct kvm_pit_timer { struct hrtimer timer; s64 period; /* unit: ns */ - u32 timer_mode_mask; - u64 tscdeadline; atomic_t pending; /* accumulated triggered timers */ bool reinject; - struct kvm_pit_timer_ops *t_ops; struct kvm *kvm; - struct kvm_vcpu *vcpu; -}; - -struct kvm_pit_timer_ops { - bool (*is_periodic)(struct kvm_pit_timer *); }; struct kvm_kpit_state { From 26ef19242f6e4d747a61b5fd8da72343838864e4 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 26 Jul 2012 18:01:53 +0300 Subject: [PATCH 0152/5375] KVM: fold kvm_pit_timer into kvm_kpit_state One structure nests inside the other, providing no value at all. Signed-off-by: Avi Kivity Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/i8254.c | 52 +++++++++++++++++++++----------------------- arch/x86/kvm/i8254.h | 14 +++++------- arch/x86/kvm/x86.c | 2 +- 3 files changed, 31 insertions(+), 37 deletions(-) diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index a9e187a5b199..11300d2fa714 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -108,7 +108,7 @@ static s64 __kpit_elapsed(struct kvm *kvm) ktime_t remaining; struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; - if (!ps->pit_timer.period) + if (!ps->period) return 0; /* @@ -120,9 +120,9 @@ static s64 __kpit_elapsed(struct kvm *kvm) * itself with the initial count and continues counting * from there. */ - remaining = hrtimer_get_remaining(&ps->pit_timer.timer); - elapsed = ps->pit_timer.period - ktime_to_ns(remaining); - elapsed = mod_64(elapsed, ps->pit_timer.period); + remaining = hrtimer_get_remaining(&ps->timer); + elapsed = ps->period - ktime_to_ns(remaining); + elapsed = mod_64(elapsed, ps->period); return elapsed; } @@ -238,12 +238,12 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian) int value; spin_lock(&ps->inject_lock); - value = atomic_dec_return(&ps->pit_timer.pending); + value = atomic_dec_return(&ps->pending); if (value < 0) /* spurious acks can be generated if, for example, the * PIC is being reset. Handle it gracefully here */ - atomic_inc(&ps->pit_timer.pending); + atomic_inc(&ps->pending); else if (value > 0) /* in this case, we had multiple outstanding pit interrupts * that we needed to inject. Reinject @@ -261,14 +261,14 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) if (!kvm_vcpu_is_bsp(vcpu) || !pit) return; - timer = &pit->pit_state.pit_timer.timer; + timer = &pit->pit_state.timer; if (hrtimer_cancel(timer)) hrtimer_start_expires(timer, HRTIMER_MODE_ABS); } static void destroy_pit_timer(struct kvm_pit *pit) { - hrtimer_cancel(&pit->pit_state.pit_timer.timer); + hrtimer_cancel(&pit->pit_state.timer); flush_kthread_work(&pit->expired); } @@ -311,16 +311,16 @@ static void pit_do_work(struct kthread_work *work) static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) { - struct kvm_pit_timer *ktimer = container_of(data, struct kvm_pit_timer, timer); - struct kvm_pit *pt = ktimer->kvm->arch.vpit; + struct kvm_kpit_state *ps = container_of(data, struct kvm_kpit_state, timer); + struct kvm_pit *pt = ps->kvm->arch.vpit; - if (ktimer->reinject || !atomic_read(&ktimer->pending)) { - atomic_inc(&ktimer->pending); + if (ps->reinject || !atomic_read(&ps->pending)) { + atomic_inc(&ps->pending); queue_kthread_work(&pt->worker, &pt->expired); } - if (pt->pit_state.is_periodic) { - hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); + if (ps->is_periodic) { + hrtimer_add_expires_ns(&ps->timer, ps->period); return HRTIMER_RESTART; } else return HRTIMER_NORESTART; @@ -329,7 +329,6 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) static void create_pit_timer(struct kvm *kvm, u32 val, int is_period) { struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; - struct kvm_pit_timer *pt = &ps->pit_timer; s64 interval; if (!irqchip_in_kernel(kvm) || ps->flags & KVM_PIT_FLAGS_HPET_LEGACY) @@ -340,18 +339,18 @@ static void create_pit_timer(struct kvm *kvm, u32 val, int is_period) pr_debug("create pit timer, interval is %llu nsec\n", interval); /* TODO The new value only affected after the retriggered */ - hrtimer_cancel(&pt->timer); + hrtimer_cancel(&ps->timer); flush_kthread_work(&ps->pit->expired); - pt->period = interval; + ps->period = interval; ps->is_periodic = is_period; - pt->timer.function = pit_timer_fn; - pt->kvm = ps->pit->kvm; + ps->timer.function = pit_timer_fn; + ps->kvm = ps->pit->kvm; - atomic_set(&pt->pending, 0); + atomic_set(&ps->pending, 0); ps->irq_ack = 1; - hrtimer_start(&pt->timer, ktime_add_ns(ktime_get(), interval), + hrtimer_start(&ps->timer, ktime_add_ns(ktime_get(), interval), HRTIMER_MODE_ABS); } @@ -627,7 +626,7 @@ void kvm_pit_reset(struct kvm_pit *pit) } mutex_unlock(&pit->pit_state.lock); - atomic_set(&pit->pit_state.pit_timer.pending, 0); + atomic_set(&pit->pit_state.pending, 0); pit->pit_state.irq_ack = 1; } @@ -636,7 +635,7 @@ static void pit_mask_notifer(struct kvm_irq_mask_notifier *kimn, bool mask) struct kvm_pit *pit = container_of(kimn, struct kvm_pit, mask_notifier); if (!mask) { - atomic_set(&pit->pit_state.pit_timer.pending, 0); + atomic_set(&pit->pit_state.pending, 0); pit->pit_state.irq_ack = 1; } } @@ -694,12 +693,11 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags) pit_state = &pit->pit_state; pit_state->pit = pit; - hrtimer_init(&pit_state->pit_timer.timer, - CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + hrtimer_init(&pit_state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); pit_state->irq_ack_notifier.gsi = 0; pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq; kvm_register_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier); - pit_state->pit_timer.reinject = true; + pit_state->reinject = true; mutex_unlock(&pit->pit_state.lock); kvm_pit_reset(pit); @@ -749,7 +747,7 @@ void kvm_free_pit(struct kvm *kvm) kvm_unregister_irq_ack_notifier(kvm, &kvm->arch.vpit->pit_state.irq_ack_notifier); mutex_lock(&kvm->arch.vpit->pit_state.lock); - timer = &kvm->arch.vpit->pit_state.pit_timer.timer; + timer = &kvm->arch.vpit->pit_state.timer; hrtimer_cancel(timer); flush_kthread_work(&kvm->arch.vpit->expired); kthread_stop(kvm->arch.vpit->worker_task); diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h index c9bbcb889c40..dd1b16b611b0 100644 --- a/arch/x86/kvm/i8254.h +++ b/arch/x86/kvm/i8254.h @@ -21,19 +21,15 @@ struct kvm_kpit_channel_state { ktime_t count_load_time; }; -struct kvm_pit_timer { - struct hrtimer timer; - s64 period; /* unit: ns */ - atomic_t pending; /* accumulated triggered timers */ - bool reinject; - struct kvm *kvm; -}; - struct kvm_kpit_state { struct kvm_kpit_channel_state channels[3]; u32 flags; - struct kvm_pit_timer pit_timer; bool is_periodic; + s64 period; /* unit: ns */ + struct hrtimer timer; + atomic_t pending; /* accumulated triggered timers */ + bool reinject; + struct kvm *kvm; u32 speaker_data_on; struct mutex lock; struct kvm_pit *pit; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b6379e55ee27..3a53bcc24f20 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3082,7 +3082,7 @@ static int kvm_vm_ioctl_reinject(struct kvm *kvm, if (!kvm->arch.vpit) return -ENXIO; mutex_lock(&kvm->arch.vpit->pit_state.lock); - kvm->arch.vpit->pit_state.pit_timer.reinject = control->pit_reinject; + kvm->arch.vpit->pit_state.reinject = control->pit_reinject; mutex_unlock(&kvm->arch.vpit->pit_state.lock); return 0; } From 738206d325a936d048bb66b5e0c70e3b1a8692be Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:19:55 +0300 Subject: [PATCH 0153/5375] crypto: tea - use crypto_[un]register_algs Combine all crypto_alg to be registered and use new crypto_[un]register_algs functions. This simplifies init/exit code. Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- crypto/tea.c | 41 ++++++----------------------------------- 1 file changed, 6 insertions(+), 35 deletions(-) diff --git a/crypto/tea.c b/crypto/tea.c index 412bc74f8179..0a572323ee4a 100644 --- a/crypto/tea.c +++ b/crypto/tea.c @@ -219,84 +219,55 @@ static void xeta_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) out[1] = cpu_to_le32(z); } -static struct crypto_alg tea_alg = { +static struct crypto_alg tea_algs[3] = { { .cra_name = "tea", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = TEA_BLOCK_SIZE, .cra_ctxsize = sizeof (struct tea_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tea_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = TEA_KEY_SIZE, .cia_max_keysize = TEA_KEY_SIZE, .cia_setkey = tea_setkey, .cia_encrypt = tea_encrypt, .cia_decrypt = tea_decrypt } } -}; - -static struct crypto_alg xtea_alg = { +}, { .cra_name = "xtea", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = XTEA_BLOCK_SIZE, .cra_ctxsize = sizeof (struct xtea_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(xtea_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = XTEA_KEY_SIZE, .cia_max_keysize = XTEA_KEY_SIZE, .cia_setkey = xtea_setkey, .cia_encrypt = xtea_encrypt, .cia_decrypt = xtea_decrypt } } -}; - -static struct crypto_alg xeta_alg = { +}, { .cra_name = "xeta", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = XTEA_BLOCK_SIZE, .cra_ctxsize = sizeof (struct xtea_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(xtea_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = XTEA_KEY_SIZE, .cia_max_keysize = XTEA_KEY_SIZE, .cia_setkey = xtea_setkey, .cia_encrypt = xeta_encrypt, .cia_decrypt = xeta_decrypt } } -}; +} }; static int __init tea_mod_init(void) { - int ret = 0; - - ret = crypto_register_alg(&tea_alg); - if (ret < 0) - goto out; - - ret = crypto_register_alg(&xtea_alg); - if (ret < 0) { - crypto_unregister_alg(&tea_alg); - goto out; - } - - ret = crypto_register_alg(&xeta_alg); - if (ret < 0) { - crypto_unregister_alg(&tea_alg); - crypto_unregister_alg(&xtea_alg); - goto out; - } - -out: - return ret; + return crypto_register_algs(tea_algs, ARRAY_SIZE(tea_algs)); } static void __exit tea_mod_fini(void) { - crypto_unregister_alg(&tea_alg); - crypto_unregister_alg(&xtea_alg); - crypto_unregister_alg(&xeta_alg); + crypto_unregister_algs(tea_algs, ARRAY_SIZE(tea_algs)); } MODULE_ALIAS("xtea"); From 70a03bff6c3f9d2983f90b74e40b0769ceb4cbd7 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:00 +0300 Subject: [PATCH 0154/5375] crypto: crypto_null - use crypto_[un]register_algs Combine all crypto_alg to be registered and use new crypto_[un]register_algs functions. This simplifies init/exit code. Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- crypto/crypto_null.c | 57 ++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 39 deletions(-) diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c index 07a8a96d46fc..fee7265cd35d 100644 --- a/crypto/crypto_null.c +++ b/crypto/crypto_null.c @@ -94,18 +94,6 @@ static int skcipher_null_crypt(struct blkcipher_desc *desc, return err; } -static struct crypto_alg compress_null = { - .cra_name = "compress_null", - .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, - .cra_blocksize = NULL_BLOCK_SIZE, - .cra_ctxsize = 0, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(compress_null.cra_list), - .cra_u = { .compress = { - .coa_compress = null_compress, - .coa_decompress = null_compress } } -}; - static struct shash_alg digest_null = { .digestsize = NULL_DIGEST_SIZE, .setkey = null_hash_setkey, @@ -122,22 +110,19 @@ static struct shash_alg digest_null = { } }; -static struct crypto_alg cipher_null = { +static struct crypto_alg null_algs[3] = { { .cra_name = "cipher_null", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = NULL_BLOCK_SIZE, .cra_ctxsize = 0, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(cipher_null.cra_list), .cra_u = { .cipher = { .cia_min_keysize = NULL_KEY_SIZE, .cia_max_keysize = NULL_KEY_SIZE, .cia_setkey = null_setkey, .cia_encrypt = null_crypt, .cia_decrypt = null_crypt } } -}; - -static struct crypto_alg skcipher_null = { +}, { .cra_name = "ecb(cipher_null)", .cra_driver_name = "ecb-cipher_null", .cra_priority = 100, @@ -146,7 +131,6 @@ static struct crypto_alg skcipher_null = { .cra_type = &crypto_blkcipher_type, .cra_ctxsize = 0, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(skcipher_null.cra_list), .cra_u = { .blkcipher = { .min_keysize = NULL_KEY_SIZE, .max_keysize = NULL_KEY_SIZE, @@ -154,7 +138,16 @@ static struct crypto_alg skcipher_null = { .setkey = null_setkey, .encrypt = skcipher_null_crypt, .decrypt = skcipher_null_crypt } } -}; +}, { + .cra_name = "compress_null", + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_blocksize = NULL_BLOCK_SIZE, + .cra_ctxsize = 0, + .cra_module = THIS_MODULE, + .cra_u = { .compress = { + .coa_compress = null_compress, + .coa_decompress = null_compress } } +} }; MODULE_ALIAS("compress_null"); MODULE_ALIAS("digest_null"); @@ -164,40 +157,26 @@ static int __init crypto_null_mod_init(void) { int ret = 0; - ret = crypto_register_alg(&cipher_null); + ret = crypto_register_algs(null_algs, ARRAY_SIZE(null_algs)); if (ret < 0) goto out; - ret = crypto_register_alg(&skcipher_null); - if (ret < 0) - goto out_unregister_cipher; - ret = crypto_register_shash(&digest_null); if (ret < 0) - goto out_unregister_skcipher; + goto out_unregister_algs; - ret = crypto_register_alg(&compress_null); - if (ret < 0) - goto out_unregister_digest; + return 0; +out_unregister_algs: + crypto_unregister_algs(null_algs, ARRAY_SIZE(null_algs)); out: return ret; - -out_unregister_digest: - crypto_unregister_shash(&digest_null); -out_unregister_skcipher: - crypto_unregister_alg(&skcipher_null); -out_unregister_cipher: - crypto_unregister_alg(&cipher_null); - goto out; } static void __exit crypto_null_mod_fini(void) { - crypto_unregister_alg(&compress_null); crypto_unregister_shash(&digest_null); - crypto_unregister_alg(&skcipher_null); - crypto_unregister_alg(&cipher_null); + crypto_unregister_algs(null_algs, ARRAY_SIZE(null_algs)); } module_init(crypto_null_mod_init); From 9935e6d2f3b5670550e48a55172cab546ae5d096 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:05 +0300 Subject: [PATCH 0155/5375] crypto: des - use crypto_[un]register_algs Combine all crypto_alg to be registered and use new crypto_[un]register_algs functions. This simplifies init/exit code. Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- crypto/des_generic.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/crypto/des_generic.c b/crypto/des_generic.c index 873818d48e86..f6cf63f88468 100644 --- a/crypto/des_generic.c +++ b/crypto/des_generic.c @@ -943,59 +943,44 @@ static void des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) d[1] = cpu_to_le32(L); } -static struct crypto_alg des_alg = { +static struct crypto_alg des_algs[2] = { { .cra_name = "des", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct des_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(des_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = DES_KEY_SIZE, .cia_max_keysize = DES_KEY_SIZE, .cia_setkey = des_setkey, .cia_encrypt = des_encrypt, .cia_decrypt = des_decrypt } } -}; - -static struct crypto_alg des3_ede_alg = { +}, { .cra_name = "des3_ede", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct des3_ede_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(des3_ede_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = DES3_EDE_KEY_SIZE, .cia_max_keysize = DES3_EDE_KEY_SIZE, .cia_setkey = des3_ede_setkey, .cia_encrypt = des3_ede_encrypt, .cia_decrypt = des3_ede_decrypt } } -}; +} }; MODULE_ALIAS("des3_ede"); static int __init des_generic_mod_init(void) { - int ret = 0; - - ret = crypto_register_alg(&des_alg); - if (ret < 0) - goto out; - - ret = crypto_register_alg(&des3_ede_alg); - if (ret < 0) - crypto_unregister_alg(&des_alg); -out: - return ret; + return crypto_register_algs(des_algs, ARRAY_SIZE(des_algs)); } static void __exit des_generic_mod_fini(void) { - crypto_unregister_alg(&des3_ede_alg); - crypto_unregister_alg(&des_alg); + crypto_unregister_algs(des_algs, ARRAY_SIZE(des_algs)); } module_init(des_generic_mod_init); From bbc406b9d2de4182a4b2990efcd1754ae9e2c483 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:10 +0300 Subject: [PATCH 0156/5375] crypto: serpent - use crypto_[un]register_algs Combine all crypto_alg to be registered and use new crypto_[un]register_algs functions. This simplifies init/exit code. Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- crypto/serpent_generic.c | 53 ++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/crypto/serpent_generic.c b/crypto/serpent_generic.c index 8f32cf35e5ce..7ddbd7e88859 100644 --- a/crypto/serpent_generic.c +++ b/crypto/serpent_generic.c @@ -567,24 +567,6 @@ static void serpent_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) __serpent_decrypt(ctx, dst, src); } -static struct crypto_alg serpent_alg = { - .cra_name = "serpent", - .cra_driver_name = "serpent-generic", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_ctx), - .cra_alignmask = 3, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_alg.cra_list), - .cra_u = { .cipher = { - .cia_min_keysize = SERPENT_MIN_KEY_SIZE, - .cia_max_keysize = SERPENT_MAX_KEY_SIZE, - .cia_setkey = serpent_setkey, - .cia_encrypt = serpent_encrypt, - .cia_decrypt = serpent_decrypt } } -}; - static int tnepres_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { @@ -637,41 +619,44 @@ static void tnepres_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) d[3] = swab32(rd[0]); } -static struct crypto_alg tnepres_alg = { +static struct crypto_alg srp_algs[2] = { { + .cra_name = "serpent", + .cra_driver_name = "serpent-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_u = { .cipher = { + .cia_min_keysize = SERPENT_MIN_KEY_SIZE, + .cia_max_keysize = SERPENT_MAX_KEY_SIZE, + .cia_setkey = serpent_setkey, + .cia_encrypt = serpent_encrypt, + .cia_decrypt = serpent_decrypt } } +}, { .cra_name = "tnepres", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = SERPENT_BLOCK_SIZE, .cra_ctxsize = sizeof(struct serpent_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = SERPENT_MIN_KEY_SIZE, .cia_max_keysize = SERPENT_MAX_KEY_SIZE, .cia_setkey = tnepres_setkey, .cia_encrypt = tnepres_encrypt, .cia_decrypt = tnepres_decrypt } } -}; +} }; static int __init serpent_mod_init(void) { - int ret = crypto_register_alg(&serpent_alg); - - if (ret) - return ret; - - ret = crypto_register_alg(&tnepres_alg); - - if (ret) - crypto_unregister_alg(&serpent_alg); - - return ret; + return crypto_register_algs(srp_algs, ARRAY_SIZE(srp_algs)); } static void __exit serpent_mod_fini(void) { - crypto_unregister_alg(&tnepres_alg); - crypto_unregister_alg(&serpent_alg); + crypto_unregister_algs(srp_algs, ARRAY_SIZE(srp_algs)); } module_init(serpent_mod_init); From 8fc229a51b0e10f4ceb794e8b99fa0a427a7ba41 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:15 +0300 Subject: [PATCH 0157/5375] crypto: ansi_cprng - use crypto_[un]register_algs Combine all crypto_alg to be registered and use new crypto_[un]register_algs functions. This simplifies init/exit code. Cc: Neil Horman Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- crypto/ansi_cprng.c | 63 +++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index 6ddd99e6114b..c0bb3778f1ae 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -382,26 +382,6 @@ static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen) return 0; } -static struct crypto_alg rng_alg = { - .cra_name = "stdrng", - .cra_driver_name = "ansi_cprng", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_RNG, - .cra_ctxsize = sizeof(struct prng_context), - .cra_type = &crypto_rng_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(rng_alg.cra_list), - .cra_init = cprng_init, - .cra_exit = cprng_exit, - .cra_u = { - .rng = { - .rng_make_random = cprng_get_random, - .rng_reset = cprng_reset, - .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ, - } - } -}; - #ifdef CONFIG_CRYPTO_FIPS static int fips_cprng_get_random(struct crypto_rng *tfm, u8 *rdata, unsigned int dlen) @@ -438,8 +418,27 @@ static int fips_cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen) out: return rc; } +#endif -static struct crypto_alg fips_rng_alg = { +static struct crypto_alg rng_algs[] = { { + .cra_name = "stdrng", + .cra_driver_name = "ansi_cprng", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_RNG, + .cra_ctxsize = sizeof(struct prng_context), + .cra_type = &crypto_rng_type, + .cra_module = THIS_MODULE, + .cra_init = cprng_init, + .cra_exit = cprng_exit, + .cra_u = { + .rng = { + .rng_make_random = cprng_get_random, + .rng_reset = cprng_reset, + .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ, + } + } +#ifdef CONFIG_CRYPTO_FIPS +}, { .cra_name = "fips(ansi_cprng)", .cra_driver_name = "fips_ansi_cprng", .cra_priority = 300, @@ -447,7 +446,6 @@ static struct crypto_alg fips_rng_alg = { .cra_ctxsize = sizeof(struct prng_context), .cra_type = &crypto_rng_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(rng_alg.cra_list), .cra_init = cprng_init, .cra_exit = cprng_exit, .cra_u = { @@ -457,33 +455,18 @@ static struct crypto_alg fips_rng_alg = { .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ, } } -}; #endif +} }; /* Module initalization */ static int __init prng_mod_init(void) { - int rc = 0; - - rc = crypto_register_alg(&rng_alg); -#ifdef CONFIG_CRYPTO_FIPS - if (rc) - goto out; - - rc = crypto_register_alg(&fips_rng_alg); - -out: -#endif - return rc; + return crypto_register_algs(rng_algs, ARRAY_SIZE(rng_algs)); } static void __exit prng_mod_fini(void) { - crypto_unregister_alg(&rng_alg); -#ifdef CONFIG_CRYPTO_FIPS - crypto_unregister_alg(&fips_rng_alg); -#endif - return; + crypto_unregister_algs(rng_algs, ARRAY_SIZE(rng_algs)); } MODULE_LICENSE("GPL"); From 50fc3e8d2c9d1ee72c67b751e5ac5d76ebc5a12e Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:20 +0300 Subject: [PATCH 0158/5375] crypto: add crypto_[un]register_shashes for [un]registering multiple shash entries at once Add crypto_[un]register_shashes() to allow simplifying init/exit code of shash crypto modules that register multiple algorithms. Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- crypto/shash.c | 36 ++++++++++++++++++++++++++++++++++ include/crypto/internal/hash.h | 2 ++ 2 files changed, 38 insertions(+) diff --git a/crypto/shash.c b/crypto/shash.c index 32067f47e6c7..f426330f1017 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -629,6 +629,42 @@ int crypto_unregister_shash(struct shash_alg *alg) } EXPORT_SYMBOL_GPL(crypto_unregister_shash); +int crypto_register_shashes(struct shash_alg *algs, int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = crypto_register_shash(&algs[i]); + if (ret) + goto err; + } + + return 0; + +err: + for (--i; i >= 0; --i) + crypto_unregister_shash(&algs[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(crypto_register_shashes); + +int crypto_unregister_shashes(struct shash_alg *algs, int count) +{ + int i, ret; + + for (i = count - 1; i >= 0; --i) { + ret = crypto_unregister_shash(&algs[i]); + if (ret) + pr_err("Failed to unregister %s %s: %d\n", + algs[i].base.cra_driver_name, + algs[i].base.cra_name, ret); + } + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_unregister_shashes); + int shash_register_instance(struct crypto_template *tmpl, struct shash_instance *inst) { diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 5bfad8c80595..821eae8cbd8c 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -83,6 +83,8 @@ struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask); int crypto_register_shash(struct shash_alg *alg); int crypto_unregister_shash(struct shash_alg *alg); +int crypto_register_shashes(struct shash_alg *algs, int count); +int crypto_unregister_shashes(struct shash_alg *algs, int count); int shash_register_instance(struct crypto_template *tmpl, struct shash_instance *inst); void shash_free_instance(struct crypto_instance *inst); From a5e7a2dcfcf360f285db9edd479491b1e2207b4f Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:25 +0300 Subject: [PATCH 0159/5375] crypto: tiger - use crypto_[un]register_shashes Combine all shash algs to be registered and use new crypto_[un]register_shashes functions. This simplifies init/exit code. Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- crypto/tgr192.c | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/crypto/tgr192.c b/crypto/tgr192.c index cbca4f208c9f..87403556fd0b 100644 --- a/crypto/tgr192.c +++ b/crypto/tgr192.c @@ -628,7 +628,7 @@ static int tgr128_final(struct shash_desc *desc, u8 * out) return 0; } -static struct shash_alg tgr192 = { +static struct shash_alg tgr_algs[3] = { { .digestsize = TGR192_DIGEST_SIZE, .init = tgr192_init, .update = tgr192_update, @@ -640,9 +640,7 @@ static struct shash_alg tgr192 = { .cra_blocksize = TGR192_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg tgr160 = { +}, { .digestsize = TGR160_DIGEST_SIZE, .init = tgr192_init, .update = tgr192_update, @@ -654,9 +652,7 @@ static struct shash_alg tgr160 = { .cra_blocksize = TGR192_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg tgr128 = { +}, { .digestsize = TGR128_DIGEST_SIZE, .init = tgr192_init, .update = tgr192_update, @@ -668,38 +664,16 @@ static struct shash_alg tgr128 = { .cra_blocksize = TGR192_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; +} }; static int __init tgr192_mod_init(void) { - int ret = 0; - - ret = crypto_register_shash(&tgr192); - - if (ret < 0) { - goto out; - } - - ret = crypto_register_shash(&tgr160); - if (ret < 0) { - crypto_unregister_shash(&tgr192); - goto out; - } - - ret = crypto_register_shash(&tgr128); - if (ret < 0) { - crypto_unregister_shash(&tgr192); - crypto_unregister_shash(&tgr160); - } - out: - return ret; + return crypto_register_shashes(tgr_algs, ARRAY_SIZE(tgr_algs)); } static void __exit tgr192_mod_fini(void) { - crypto_unregister_shash(&tgr192); - crypto_unregister_shash(&tgr160); - crypto_unregister_shash(&tgr128); + crypto_unregister_shashes(tgr_algs, ARRAY_SIZE(tgr_algs)); } MODULE_ALIAS("tgr160"); From 6aeb49bc5a6fffe2f8ba0668cf7459b6a4b672dc Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:30 +0300 Subject: [PATCH 0160/5375] crypto: sha256 - use crypto_[un]register_shashes Combine all shash algs to be registered and use new crypto_[un]register_shashes functions. This simplifies init/exit code. Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- crypto/sha256_generic.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index c48459ebf05b..c3ed4ec924e1 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -336,7 +336,7 @@ static int sha256_import(struct shash_desc *desc, const void *in) return 0; } -static struct shash_alg sha256 = { +static struct shash_alg sha256_algs[2] = { { .digestsize = SHA256_DIGEST_SIZE, .init = sha256_init, .update = sha256_update, @@ -352,9 +352,7 @@ static struct shash_alg sha256 = { .cra_blocksize = SHA256_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg sha224 = { +}, { .digestsize = SHA224_DIGEST_SIZE, .init = sha224_init, .update = sha256_update, @@ -367,29 +365,16 @@ static struct shash_alg sha224 = { .cra_blocksize = SHA224_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; +} }; static int __init sha256_generic_mod_init(void) { - int ret = 0; - - ret = crypto_register_shash(&sha224); - - if (ret < 0) - return ret; - - ret = crypto_register_shash(&sha256); - - if (ret < 0) - crypto_unregister_shash(&sha224); - - return ret; + return crypto_register_shashes(sha256_algs, ARRAY_SIZE(sha256_algs)); } static void __exit sha256_generic_mod_fini(void) { - crypto_unregister_shash(&sha224); - crypto_unregister_shash(&sha256); + crypto_unregister_shashes(sha256_algs, ARRAY_SIZE(sha256_algs)); } module_init(sha256_generic_mod_init); From 648b2a102d268d41d8116abde9081327c1be82e8 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:36 +0300 Subject: [PATCH 0161/5375] crypto: sha512 - use crypto_[un]register_shashes Combine all shash algs to be registered and use new crypto_[un]register_shashes functions. This simplifies init/exit code. Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- crypto/sha512_generic.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index dd30f40af9f5..71fcf361102d 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -242,7 +242,7 @@ static int sha384_final(struct shash_desc *desc, u8 *hash) return 0; } -static struct shash_alg sha512 = { +static struct shash_alg sha512_algs[2] = { { .digestsize = SHA512_DIGEST_SIZE, .init = sha512_init, .update = sha512_update, @@ -254,9 +254,7 @@ static struct shash_alg sha512 = { .cra_blocksize = SHA512_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg sha384 = { +}, { .digestsize = SHA384_DIGEST_SIZE, .init = sha384_init, .update = sha512_update, @@ -268,24 +266,16 @@ static struct shash_alg sha384 = { .cra_blocksize = SHA384_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; +} }; static int __init sha512_generic_mod_init(void) { - int ret = 0; - - if ((ret = crypto_register_shash(&sha384)) < 0) - goto out; - if ((ret = crypto_register_shash(&sha512)) < 0) - crypto_unregister_shash(&sha384); -out: - return ret; + return crypto_register_shashes(sha512_algs, ARRAY_SIZE(sha512_algs)); } static void __exit sha512_generic_mod_fini(void) { - crypto_unregister_shash(&sha384); - crypto_unregister_shash(&sha512); + crypto_unregister_shashes(sha512_algs, ARRAY_SIZE(sha512_algs)); } module_init(sha512_generic_mod_init); From f4b0277e7ef435733b888a62cf9c4c12b219e7c5 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:41 +0300 Subject: [PATCH 0162/5375] crypto: whirlpool - use crypto_[un]register_shashes Combine all shash algs to be registered and use new crypto_[un]register_shashes functions. This simplifies init/exit code. Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- crypto/wp512.c | 39 ++++++--------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/crypto/wp512.c b/crypto/wp512.c index 71719a2be25a..180f1d6e03f4 100644 --- a/crypto/wp512.c +++ b/crypto/wp512.c @@ -1119,7 +1119,7 @@ static int wp256_final(struct shash_desc *desc, u8 *out) return 0; } -static struct shash_alg wp512 = { +static struct shash_alg wp_algs[3] = { { .digestsize = WP512_DIGEST_SIZE, .init = wp512_init, .update = wp512_update, @@ -1131,9 +1131,7 @@ static struct shash_alg wp512 = { .cra_blocksize = WP512_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg wp384 = { +}, { .digestsize = WP384_DIGEST_SIZE, .init = wp512_init, .update = wp512_update, @@ -1145,9 +1143,7 @@ static struct shash_alg wp384 = { .cra_blocksize = WP512_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg wp256 = { +}, { .digestsize = WP256_DIGEST_SIZE, .init = wp512_init, .update = wp512_update, @@ -1159,39 +1155,16 @@ static struct shash_alg wp256 = { .cra_blocksize = WP512_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; +} }; static int __init wp512_mod_init(void) { - int ret = 0; - - ret = crypto_register_shash(&wp512); - - if (ret < 0) - goto out; - - ret = crypto_register_shash(&wp384); - if (ret < 0) - { - crypto_unregister_shash(&wp512); - goto out; - } - - ret = crypto_register_shash(&wp256); - if (ret < 0) - { - crypto_unregister_shash(&wp512); - crypto_unregister_shash(&wp384); - } -out: - return ret; + return crypto_register_shashes(wp_algs, ARRAY_SIZE(wp_algs)); } static void __exit wp512_mod_fini(void) { - crypto_unregister_shash(&wp512); - crypto_unregister_shash(&wp384); - crypto_unregister_shash(&wp256); + crypto_unregister_shashes(wp_algs, ARRAY_SIZE(wp_algs)); } MODULE_ALIAS("wp384"); From 77ec2e734d4820c51cbabe1257e9311df5868160 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:46 +0300 Subject: [PATCH 0163/5375] crypto: cleanup - remove unneeded crypto_alg.cra_list initializations Initialization of cra_list is currently mixed, most ciphers initialize this field and most shashes do not. Initialization however is not needed at all since cra_list is initialized/overwritten in __crypto_register_alg() with list_add(). Therefore perform cleanup to remove all unneeded initializations of this field in 'crypto/'. Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- crypto/aes_generic.c | 1 - crypto/anubis.c | 1 - crypto/blowfish_generic.c | 1 - crypto/camellia_generic.c | 1 - crypto/cast5.c | 1 - crypto/cast6.c | 1 - crypto/deflate.c | 1 - crypto/fcrypt.c | 1 - crypto/ghash-generic.c | 1 - crypto/khazad.c | 1 - crypto/krng.c | 1 - crypto/lzo.c | 1 - crypto/salsa20_generic.c | 1 - crypto/seed.c | 1 - crypto/twofish_generic.c | 1 - 15 files changed, 15 deletions(-) diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c index a68c73dae15a..47f2e5c71759 100644 --- a/crypto/aes_generic.c +++ b/crypto/aes_generic.c @@ -1448,7 +1448,6 @@ static struct crypto_alg aes_alg = { .cra_ctxsize = sizeof(struct crypto_aes_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE, diff --git a/crypto/anubis.c b/crypto/anubis.c index 77530d571c96..008c8a4fb67c 100644 --- a/crypto/anubis.c +++ b/crypto/anubis.c @@ -678,7 +678,6 @@ static struct crypto_alg anubis_alg = { .cra_ctxsize = sizeof (struct anubis_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(anubis_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = ANUBIS_MIN_KEY_SIZE, .cia_max_keysize = ANUBIS_MAX_KEY_SIZE, diff --git a/crypto/blowfish_generic.c b/crypto/blowfish_generic.c index 6f269b5cfa3b..8baf5447d35b 100644 --- a/crypto/blowfish_generic.c +++ b/crypto/blowfish_generic.c @@ -115,7 +115,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct bf_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = BF_MIN_KEY_SIZE, .cia_max_keysize = BF_MAX_KEY_SIZE, diff --git a/crypto/camellia_generic.c b/crypto/camellia_generic.c index f7aaaaf86982..75efa2052305 100644 --- a/crypto/camellia_generic.c +++ b/crypto/camellia_generic.c @@ -1072,7 +1072,6 @@ static struct crypto_alg camellia_alg = { .cra_ctxsize = sizeof(struct camellia_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE, diff --git a/crypto/cast5.c b/crypto/cast5.c index 4a230ddec877..fffcb37dec11 100644 --- a/crypto/cast5.c +++ b/crypto/cast5.c @@ -779,7 +779,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct cast5_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = CAST5_MIN_KEY_SIZE, diff --git a/crypto/cast6.c b/crypto/cast6.c index e0c15a6c7c34..04264f574601 100644 --- a/crypto/cast6.c +++ b/crypto/cast6.c @@ -519,7 +519,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct cast6_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = CAST6_MIN_KEY_SIZE, diff --git a/crypto/deflate.c b/crypto/deflate.c index b0165ecad0c5..b57d70eb156b 100644 --- a/crypto/deflate.c +++ b/crypto/deflate.c @@ -199,7 +199,6 @@ static struct crypto_alg alg = { .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, .cra_ctxsize = sizeof(struct deflate_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_init = deflate_init, .cra_exit = deflate_exit, .cra_u = { .compress = { diff --git a/crypto/fcrypt.c b/crypto/fcrypt.c index c33107e340b6..3b2cf569c684 100644 --- a/crypto/fcrypt.c +++ b/crypto/fcrypt.c @@ -396,7 +396,6 @@ static struct crypto_alg fcrypt_alg = { .cra_ctxsize = sizeof(struct fcrypt_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(fcrypt_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = 8, .cia_max_keysize = 8, diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c index 7835b8fc94db..9d3f0c69a86f 100644 --- a/crypto/ghash-generic.c +++ b/crypto/ghash-generic.c @@ -153,7 +153,6 @@ static struct shash_alg ghash_alg = { .cra_blocksize = GHASH_BLOCK_SIZE, .cra_ctxsize = sizeof(struct ghash_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list), .cra_exit = ghash_exit_tfm, }, }; diff --git a/crypto/khazad.c b/crypto/khazad.c index 527e4e395fc3..60e7cd66facc 100644 --- a/crypto/khazad.c +++ b/crypto/khazad.c @@ -853,7 +853,6 @@ static struct crypto_alg khazad_alg = { .cra_ctxsize = sizeof (struct khazad_ctx), .cra_alignmask = 7, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(khazad_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = KHAZAD_KEY_SIZE, .cia_max_keysize = KHAZAD_KEY_SIZE, diff --git a/crypto/krng.c b/crypto/krng.c index 4328bb3430ed..a2d2b72fc135 100644 --- a/crypto/krng.c +++ b/crypto/krng.c @@ -35,7 +35,6 @@ static struct crypto_alg krng_alg = { .cra_ctxsize = 0, .cra_type = &crypto_rng_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(krng_alg.cra_list), .cra_u = { .rng = { .rng_make_random = krng_get_random, diff --git a/crypto/lzo.c b/crypto/lzo.c index b5e77077d751..1c2aa69c54b8 100644 --- a/crypto/lzo.c +++ b/crypto/lzo.c @@ -81,7 +81,6 @@ static struct crypto_alg alg = { .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, .cra_ctxsize = sizeof(struct lzo_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_init = lzo_init, .cra_exit = lzo_exit, .cra_u = { .compress = { diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c index eac10c11685c..9a4770c02284 100644 --- a/crypto/salsa20_generic.c +++ b/crypto/salsa20_generic.c @@ -221,7 +221,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct salsa20_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .blkcipher = { .setkey = setkey, diff --git a/crypto/seed.c b/crypto/seed.c index d3e422f60556..9c904d6d2151 100644 --- a/crypto/seed.c +++ b/crypto/seed.c @@ -449,7 +449,6 @@ static struct crypto_alg seed_alg = { .cra_ctxsize = sizeof(struct seed_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(seed_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = SEED_KEY_SIZE, diff --git a/crypto/twofish_generic.c b/crypto/twofish_generic.c index 1f07b843e07c..2d5000552d0f 100644 --- a/crypto/twofish_generic.c +++ b/crypto/twofish_generic.c @@ -188,7 +188,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct twofish_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = TF_MIN_KEY_SIZE, .cia_max_keysize = TF_MAX_KEY_SIZE, From 7af6c2456851eb08d51d95de38ae8302994031e9 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:51 +0300 Subject: [PATCH 0164/5375] crypto: arch/x86 - cleanup - remove unneeded crypto_alg.cra_list initializations Initialization of cra_list is currently mixed, most ciphers initialize this field and most shashes do not. Initialization however is not needed at all since cra_list is initialized/overwritten in __crypto_register_alg() with list_add(). Therefore perform cleanup to remove all unneeded initializations of this field in 'arch/x86/crypto/'. Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- arch/x86/crypto/aes_glue.c | 1 - arch/x86/crypto/aesni-intel_glue.c | 5 +---- arch/x86/crypto/blowfish_glue.c | 4 ---- arch/x86/crypto/camellia_glue.c | 6 ------ arch/x86/crypto/ghash-clmulni-intel_glue.c | 2 -- arch/x86/crypto/salsa20_glue.c | 1 - arch/x86/crypto/serpent_avx_glue.c | 10 ---------- arch/x86/crypto/serpent_sse2_glue.c | 10 ---------- arch/x86/crypto/twofish_avx_glue.c | 10 ---------- arch/x86/crypto/twofish_glue.c | 1 - arch/x86/crypto/twofish_glue_3way.c | 5 ----- 11 files changed, 1 insertion(+), 54 deletions(-) diff --git a/arch/x86/crypto/aes_glue.c b/arch/x86/crypto/aes_glue.c index 59b37deb8c8d..aafe8ce0d65d 100644 --- a/arch/x86/crypto/aes_glue.c +++ b/arch/x86/crypto/aes_glue.c @@ -40,7 +40,6 @@ static struct crypto_alg aes_alg = { .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypto_aes_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE, diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index 34fdcff4d2c8..648347a05773 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -1118,7 +1118,7 @@ MODULE_DEVICE_TABLE(x86cpu, aesni_cpu_id); static int __init aesni_init(void) { - int err, i; + int err; if (!x86_match_cpu(aesni_cpu_id)) return -ENODEV; @@ -1127,9 +1127,6 @@ static int __init aesni_init(void) if (err) return err; - for (i = 0; i < ARRAY_SIZE(aesni_algs); i++) - INIT_LIST_HEAD(&aesni_algs[i].cra_list); - return crypto_register_algs(aesni_algs, ARRAY_SIZE(aesni_algs)); } diff --git a/arch/x86/crypto/blowfish_glue.c b/arch/x86/crypto/blowfish_glue.c index 7967474de8f7..50ec333b70e6 100644 --- a/arch/x86/crypto/blowfish_glue.c +++ b/arch/x86/crypto/blowfish_glue.c @@ -367,7 +367,6 @@ static struct crypto_alg bf_algs[4] = { { .cra_ctxsize = sizeof(struct bf_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(bf_algs[0].cra_list), .cra_u = { .cipher = { .cia_min_keysize = BF_MIN_KEY_SIZE, @@ -387,7 +386,6 @@ static struct crypto_alg bf_algs[4] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(bf_algs[1].cra_list), .cra_u = { .blkcipher = { .min_keysize = BF_MIN_KEY_SIZE, @@ -407,7 +405,6 @@ static struct crypto_alg bf_algs[4] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(bf_algs[2].cra_list), .cra_u = { .blkcipher = { .min_keysize = BF_MIN_KEY_SIZE, @@ -428,7 +425,6 @@ static struct crypto_alg bf_algs[4] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(bf_algs[3].cra_list), .cra_u = { .blkcipher = { .min_keysize = BF_MIN_KEY_SIZE, diff --git a/arch/x86/crypto/camellia_glue.c b/arch/x86/crypto/camellia_glue.c index eeb2b3b743e9..7a74d7bb326d 100644 --- a/arch/x86/crypto/camellia_glue.c +++ b/arch/x86/crypto/camellia_glue.c @@ -1601,7 +1601,6 @@ static struct crypto_alg camellia_algs[6] = { { .cra_ctxsize = sizeof(struct camellia_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[0].cra_list), .cra_u = { .cipher = { .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE, @@ -1621,7 +1620,6 @@ static struct crypto_alg camellia_algs[6] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[1].cra_list), .cra_u = { .blkcipher = { .min_keysize = CAMELLIA_MIN_KEY_SIZE, @@ -1641,7 +1639,6 @@ static struct crypto_alg camellia_algs[6] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[2].cra_list), .cra_u = { .blkcipher = { .min_keysize = CAMELLIA_MIN_KEY_SIZE, @@ -1662,7 +1659,6 @@ static struct crypto_alg camellia_algs[6] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[3].cra_list), .cra_u = { .blkcipher = { .min_keysize = CAMELLIA_MIN_KEY_SIZE, @@ -1683,7 +1679,6 @@ static struct crypto_alg camellia_algs[6] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[4].cra_list), .cra_exit = lrw_exit_tfm, .cra_u = { .blkcipher = { @@ -1707,7 +1702,6 @@ static struct crypto_alg camellia_algs[6] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[5].cra_list), .cra_u = { .blkcipher = { .min_keysize = CAMELLIA_MIN_KEY_SIZE * 2, diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c index b4bf0a63b520..6759dd1135be 100644 --- a/arch/x86/crypto/ghash-clmulni-intel_glue.c +++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c @@ -150,7 +150,6 @@ static struct shash_alg ghash_alg = { .cra_blocksize = GHASH_BLOCK_SIZE, .cra_ctxsize = sizeof(struct ghash_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list), }, }; @@ -288,7 +287,6 @@ static struct ahash_alg ghash_async_alg = { .cra_blocksize = GHASH_BLOCK_SIZE, .cra_type = &crypto_ahash_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ghash_async_alg.halg.base.cra_list), .cra_init = ghash_async_init_tfm, .cra_exit = ghash_async_exit_tfm, }, diff --git a/arch/x86/crypto/salsa20_glue.c b/arch/x86/crypto/salsa20_glue.c index bccb76d80987..a3a3c0205c16 100644 --- a/arch/x86/crypto/salsa20_glue.c +++ b/arch/x86/crypto/salsa20_glue.c @@ -97,7 +97,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct salsa20_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .blkcipher = { .setkey = setkey, diff --git a/arch/x86/crypto/serpent_avx_glue.c b/arch/x86/crypto/serpent_avx_glue.c index b36bdac237eb..3f543a04cf1e 100644 --- a/arch/x86/crypto/serpent_avx_glue.c +++ b/arch/x86/crypto/serpent_avx_glue.c @@ -390,7 +390,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[0].cra_list), .cra_u = { .blkcipher = { .min_keysize = SERPENT_MIN_KEY_SIZE, @@ -410,7 +409,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[1].cra_list), .cra_u = { .blkcipher = { .min_keysize = SERPENT_MIN_KEY_SIZE, @@ -430,7 +428,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[2].cra_list), .cra_u = { .blkcipher = { .min_keysize = SERPENT_MIN_KEY_SIZE, @@ -451,7 +448,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[3].cra_list), .cra_exit = lrw_exit_tfm, .cra_u = { .blkcipher = { @@ -475,7 +471,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[4].cra_list), .cra_u = { .blkcipher = { .min_keysize = SERPENT_MIN_KEY_SIZE * 2, @@ -496,7 +491,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -518,7 +512,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -541,7 +534,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -565,7 +557,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -590,7 +581,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { diff --git a/arch/x86/crypto/serpent_sse2_glue.c b/arch/x86/crypto/serpent_sse2_glue.c index d679c8675f4a..9107a9908c41 100644 --- a/arch/x86/crypto/serpent_sse2_glue.c +++ b/arch/x86/crypto/serpent_sse2_glue.c @@ -393,7 +393,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[0].cra_list), .cra_u = { .blkcipher = { .min_keysize = SERPENT_MIN_KEY_SIZE, @@ -413,7 +412,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[1].cra_list), .cra_u = { .blkcipher = { .min_keysize = SERPENT_MIN_KEY_SIZE, @@ -433,7 +431,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[2].cra_list), .cra_u = { .blkcipher = { .min_keysize = SERPENT_MIN_KEY_SIZE, @@ -454,7 +451,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[3].cra_list), .cra_exit = lrw_exit_tfm, .cra_u = { .blkcipher = { @@ -478,7 +474,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[4].cra_list), .cra_u = { .blkcipher = { .min_keysize = SERPENT_MIN_KEY_SIZE * 2, @@ -499,7 +494,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -521,7 +515,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -544,7 +537,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -568,7 +560,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -593,7 +584,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { diff --git a/arch/x86/crypto/twofish_avx_glue.c b/arch/x86/crypto/twofish_avx_glue.c index 782b67ddaf6a..e7708b5442e0 100644 --- a/arch/x86/crypto/twofish_avx_glue.c +++ b/arch/x86/crypto/twofish_avx_glue.c @@ -378,7 +378,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[0].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE, @@ -398,7 +397,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[1].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE, @@ -418,7 +416,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[2].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE, @@ -439,7 +436,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[3].cra_list), .cra_exit = lrw_twofish_exit_tfm, .cra_u = { .blkcipher = { @@ -463,7 +459,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[4].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE * 2, @@ -484,7 +479,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[5].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -506,7 +500,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[6].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -529,7 +522,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[7].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -553,7 +545,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[8].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -578,7 +569,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[9].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { diff --git a/arch/x86/crypto/twofish_glue.c b/arch/x86/crypto/twofish_glue.c index 359ae084275c..0a5202303501 100644 --- a/arch/x86/crypto/twofish_glue.c +++ b/arch/x86/crypto/twofish_glue.c @@ -70,7 +70,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct twofish_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = TF_MIN_KEY_SIZE, diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c index 15f9347316c8..aa3eb358b7e8 100644 --- a/arch/x86/crypto/twofish_glue_3way.c +++ b/arch/x86/crypto/twofish_glue_3way.c @@ -342,7 +342,6 @@ static struct crypto_alg tf_algs[5] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tf_algs[0].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE, @@ -362,7 +361,6 @@ static struct crypto_alg tf_algs[5] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tf_algs[1].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE, @@ -383,7 +381,6 @@ static struct crypto_alg tf_algs[5] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tf_algs[2].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE, @@ -404,7 +401,6 @@ static struct crypto_alg tf_algs[5] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tf_algs[3].cra_list), .cra_exit = lrw_twofish_exit_tfm, .cra_u = { .blkcipher = { @@ -426,7 +422,6 @@ static struct crypto_alg tf_algs[5] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tf_algs[4].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE * 2, From e15aa3692da1dcee3172966a878b04a1e0f514b3 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:20:56 +0300 Subject: [PATCH 0165/5375] crypto: drivers - remove cra_list initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialization of cra_list is currently mixed, most ciphers initialize this field and most shashes do not. Initialization however is not needed at all since cra_list is initialized/overwritten in __crypto_register_alg() with list_add(). Therefore perform cleanup to remove all unneeded initializations of this field in 'crypto/drivers/'. Cc: Benjamin Herrenschmidt Cc: linux-geode@lists.infradead.org Cc: Michal Ludvig Cc: Dmitry Kasatkin Cc: Varun Wadekar Cc: Eric Bénard Signed-off-by: Jussi Kivilinna Acked-by: Kent Yoder Acked-by: Vladimir Zapolskiy Signed-off-by: Herbert Xu --- drivers/crypto/atmel-aes.c | 2 -- drivers/crypto/atmel-tdes.c | 1 - drivers/crypto/geode-aes.c | 3 --- drivers/crypto/nx/nx-aes-cbc.c | 1 - drivers/crypto/nx/nx-aes-ccm.c | 2 -- drivers/crypto/nx/nx-aes-ctr.c | 2 -- drivers/crypto/nx/nx-aes-ecb.c | 1 - drivers/crypto/nx/nx-aes-gcm.c | 2 -- drivers/crypto/omap-aes.c | 1 - drivers/crypto/padlock-aes.c | 3 --- drivers/crypto/s5p-sss.c | 1 - drivers/crypto/tegra-aes.c | 2 -- 12 files changed, 21 deletions(-) diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 6bb20fffbf49..872ca8c8d83b 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -1017,7 +1017,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) int err, i, j; for (i = 0; i < ARRAY_SIZE(aes_algs); i++) { - INIT_LIST_HEAD(&aes_algs[i].cra_list); err = crypto_register_alg(&aes_algs[i]); if (err) goto err_aes_algs; @@ -1026,7 +1025,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) atmel_aes_hw_version_init(dd); if (dd->hw_version >= 0x130) { - INIT_LIST_HEAD(&aes_cfb64_alg[0].cra_list); err = crypto_register_alg(&aes_cfb64_alg[0]); if (err) goto err_aes_cfb64_alg; diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index eb2b61e57e2d..53c1680b5513 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -1044,7 +1044,6 @@ static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd) int err, i, j; for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) { - INIT_LIST_HEAD(&tdes_algs[i].cra_list); err = crypto_register_alg(&tdes_algs[i]); if (err) goto err_tdes_algs; diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index f3e36c86b6c3..933fb4b4a4c7 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -289,7 +289,6 @@ static struct crypto_alg geode_alg = { .cra_blocksize = AES_MIN_BLOCK_SIZE, .cra_ctxsize = sizeof(struct geode_aes_op), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE, @@ -402,7 +401,6 @@ static struct crypto_alg geode_cbc_alg = { .cra_alignmask = 15, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_cbc_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, @@ -489,7 +487,6 @@ static struct crypto_alg geode_ecb_alg = { .cra_alignmask = 15, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_ecb_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, diff --git a/drivers/crypto/nx/nx-aes-cbc.c b/drivers/crypto/nx/nx-aes-cbc.c index 69ed796ee327..a76d4c4f29f5 100644 --- a/drivers/crypto/nx/nx-aes-cbc.c +++ b/drivers/crypto/nx/nx-aes-cbc.c @@ -127,7 +127,6 @@ struct crypto_alg nx_cbc_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_cbc_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_cbc_init, .cra_exit = nx_crypto_ctx_exit, .cra_blkcipher = { diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c index 7aeac678b9c0..ef5eae6d1400 100644 --- a/drivers/crypto/nx/nx-aes-ccm.c +++ b/drivers/crypto/nx/nx-aes-ccm.c @@ -430,7 +430,6 @@ struct crypto_alg nx_ccm_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_aead_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_ccm_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_ccm_init, .cra_exit = nx_crypto_ctx_exit, .cra_aead = { @@ -453,7 +452,6 @@ struct crypto_alg nx_ccm4309_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_nivaead_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_ccm4309_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_ccm_init, .cra_exit = nx_crypto_ctx_exit, .cra_aead = { diff --git a/drivers/crypto/nx/nx-aes-ctr.c b/drivers/crypto/nx/nx-aes-ctr.c index 52d4eb05e8f7..b6286f14680b 100644 --- a/drivers/crypto/nx/nx-aes-ctr.c +++ b/drivers/crypto/nx/nx-aes-ctr.c @@ -141,7 +141,6 @@ struct crypto_alg nx_ctr_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_ctr_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_ctr_init, .cra_exit = nx_crypto_ctx_exit, .cra_blkcipher = { @@ -163,7 +162,6 @@ struct crypto_alg nx_ctr3686_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_ctr3686_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_ctr_init, .cra_exit = nx_crypto_ctx_exit, .cra_blkcipher = { diff --git a/drivers/crypto/nx/nx-aes-ecb.c b/drivers/crypto/nx/nx-aes-ecb.c index 7b77bc2d1df4..ba5f1611336f 100644 --- a/drivers/crypto/nx/nx-aes-ecb.c +++ b/drivers/crypto/nx/nx-aes-ecb.c @@ -126,7 +126,6 @@ struct crypto_alg nx_ecb_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_ecb_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_ecb_init, .cra_exit = nx_crypto_ctx_exit, .cra_blkcipher = { diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c index 9ab1c7341dac..c8109edc5cfb 100644 --- a/drivers/crypto/nx/nx-aes-gcm.c +++ b/drivers/crypto/nx/nx-aes-gcm.c @@ -316,7 +316,6 @@ struct crypto_alg nx_gcm_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_aead_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_gcm_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_gcm_init, .cra_exit = nx_crypto_ctx_exit, .cra_aead = { @@ -338,7 +337,6 @@ struct crypto_alg nx_gcm4106_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_nivaead_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_gcm4106_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_gcm_init, .cra_exit = nx_crypto_ctx_exit, .cra_aead = { diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 63e57b57a12c..093a8af59cbe 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -876,7 +876,6 @@ static int omap_aes_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(algs); i++) { pr_debug("i: %d\n", i); - INIT_LIST_HEAD(&algs[i].cra_list); err = crypto_register_alg(&algs[i]); if (err) goto err_algs; diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 37b2e9406af6..633ba945e153 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -328,7 +328,6 @@ static struct crypto_alg aes_alg = { .cra_ctxsize = sizeof(struct aes_ctx), .cra_alignmask = PADLOCK_ALIGNMENT - 1, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE, @@ -408,7 +407,6 @@ static struct crypto_alg ecb_aes_alg = { .cra_alignmask = PADLOCK_ALIGNMENT - 1, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, @@ -491,7 +489,6 @@ static struct crypto_alg cbc_aes_alg = { .cra_alignmask = PADLOCK_ALIGNMENT - 1, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index bc986f806086..a22714412cda 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -626,7 +626,6 @@ static int s5p_aes_probe(struct platform_device *pdev) crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN); for (i = 0; i < ARRAY_SIZE(algs); i++) { - INIT_LIST_HEAD(&algs[i].cra_list); err = crypto_register_alg(&algs[i]); if (err) goto err_algs; diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c index ac236f6724f4..631149e50ef1 100644 --- a/drivers/crypto/tegra-aes.c +++ b/drivers/crypto/tegra-aes.c @@ -1004,8 +1004,6 @@ static int tegra_aes_probe(struct platform_device *pdev) aes_dev = dd; for (i = 0; i < ARRAY_SIZE(algs); i++) { - INIT_LIST_HEAD(&algs[i].cra_list); - algs[i].cra_priority = 300; algs[i].cra_ctxsize = sizeof(struct tegra_aes_ctx); algs[i].cra_module = THIS_MODULE; From 37743cc0d34c4c5cb8520bc27eb2a45141e938fe Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 11 Jul 2012 14:21:01 +0300 Subject: [PATCH 0166/5375] crypto: arch/s390 - cleanup - remove unneeded cra_list initialization Initialization of cra_list is currently mixed, most ciphers initialize this field and most shashes do not. Initialization however is not needed at all since cra_list is initialized/overwritten in __crypto_register_alg() with list_add(). Therefore perform cleanup to remove all unneeded initializations of this field in 'arch/s390/crypto/' Cc: Gerald Schaefer Cc: linux-s390@vger.kernel.org Signed-off-by: Jussi Kivilinna Signed-off-by: Jan Glauber Signed-off-by: Herbert Xu --- arch/s390/crypto/aes_s390.c | 5 ----- arch/s390/crypto/des_s390.c | 10 ---------- arch/s390/crypto/ghash_s390.c | 1 - 3 files changed, 16 deletions(-) diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index e402a9dd4eda..da3c1a7dcd8e 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -216,7 +216,6 @@ static struct crypto_alg aes_alg = { .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), .cra_init = fallback_init_cip, .cra_exit = fallback_exit_cip, .cra_u = { @@ -398,7 +397,6 @@ static struct crypto_alg ecb_aes_alg = { .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list), .cra_init = fallback_init_blk, .cra_exit = fallback_exit_blk, .cra_u = { @@ -508,7 +506,6 @@ static struct crypto_alg cbc_aes_alg = { .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list), .cra_init = fallback_init_blk, .cra_exit = fallback_exit_blk, .cra_u = { @@ -710,7 +707,6 @@ static struct crypto_alg xts_aes_alg = { .cra_ctxsize = sizeof(struct s390_xts_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(xts_aes_alg.cra_list), .cra_init = xts_fallback_init, .cra_exit = xts_fallback_exit, .cra_u = { @@ -832,7 +828,6 @@ static struct crypto_alg ctr_aes_alg = { .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ctr_aes_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index 1eaa371ca3ee..b49fb96f4207 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -70,7 +70,6 @@ static struct crypto_alg des_alg = { .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(des_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = DES_KEY_SIZE, @@ -163,7 +162,6 @@ static struct crypto_alg ecb_des_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES_KEY_SIZE, @@ -206,7 +204,6 @@ static struct crypto_alg cbc_des_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES_KEY_SIZE, @@ -271,7 +268,6 @@ static struct crypto_alg des3_alg = { .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(des3_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = DES3_KEY_SIZE, @@ -314,8 +310,6 @@ static struct crypto_alg ecb_des3_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT( - ecb_des3_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES3_KEY_SIZE, @@ -358,8 +352,6 @@ static struct crypto_alg cbc_des3_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT( - cbc_des3_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES3_KEY_SIZE, @@ -452,7 +444,6 @@ static struct crypto_alg ctr_des_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ctr_des_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES_KEY_SIZE, @@ -496,7 +487,6 @@ static struct crypto_alg ctr_des3_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ctr_des3_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES3_KEY_SIZE, diff --git a/arch/s390/crypto/ghash_s390.c b/arch/s390/crypto/ghash_s390.c index b1bd170f24b1..1ebd3a15cca4 100644 --- a/arch/s390/crypto/ghash_s390.c +++ b/arch/s390/crypto/ghash_s390.c @@ -135,7 +135,6 @@ static struct shash_alg ghash_alg = { .cra_blocksize = GHASH_BLOCK_SIZE, .cra_ctxsize = sizeof(struct ghash_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list), }, }; From 270b0c6b406a0ae7673ee880d1d7cc6bd6c904de Mon Sep 17 00:00:00 2001 From: Johannes Goetzfried Date: Wed, 11 Jul 2012 19:37:04 +0200 Subject: [PATCH 0167/5375] crypto: cast5 - prepare generic module for optimized implementations Rename cast5 module to cast5_generic to allow autoloading of optimized implementations. Generic functions and s-boxes are exported to be able to use them within optimized implementations. Signed-off-by: Johannes Goetzfried Signed-off-by: Herbert Xu --- crypto/Makefile | 2 +- crypto/{cast5.c => cast5_generic.c} | 79 +++++++++++++++++------------ include/crypto/cast5.h | 22 ++++++++ 3 files changed, 69 insertions(+), 34 deletions(-) rename crypto/{cast5.c => cast5_generic.c} (95%) create mode 100644 include/crypto/cast5.h diff --git a/crypto/Makefile b/crypto/Makefile index 30f33d675330..a56821e5d573 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -68,7 +68,7 @@ obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o obj-$(CONFIG_CRYPTO_AES) += aes_generic.o obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o -obj-$(CONFIG_CRYPTO_CAST5) += cast5.o +obj-$(CONFIG_CRYPTO_CAST5) += cast5_generic.o obj-$(CONFIG_CRYPTO_CAST6) += cast6.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o obj-$(CONFIG_CRYPTO_TEA) += tea.o diff --git a/crypto/cast5.c b/crypto/cast5_generic.c similarity index 95% rename from crypto/cast5.c rename to crypto/cast5_generic.c index fffcb37dec11..bc525dbd8a4b 100644 --- a/crypto/cast5.c +++ b/crypto/cast5_generic.c @@ -4,8 +4,8 @@ * Derived from GnuPG implementation of cast5. * * Major Changes. -* Complete conformance to rfc2144. -* Supports key size from 40 to 128 bits. +* Complete conformance to rfc2144. +* Supports key size from 40 to 128 bits. * * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * Copyright (C) 2003 Kartikey Mahendra Bhatt . @@ -28,19 +28,10 @@ #include #include #include - -#define CAST5_BLOCK_SIZE 8 -#define CAST5_MIN_KEY_SIZE 5 -#define CAST5_MAX_KEY_SIZE 16 - -struct cast5_ctx { - u32 Km[16]; - u8 Kr[16]; - int rr; /* rr?number of rounds = 16:number of rounds = 12; (rfc 2144) */ -}; +#include -static const u32 s1[256] = { +const u32 cast5_s1[256] = { 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, @@ -106,7 +97,8 @@ static const u32 s1[256] = { 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf }; -static const u32 s2[256] = { +EXPORT_SYMBOL_GPL(cast5_s1); +const u32 cast5_s2[256] = { 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, @@ -172,7 +164,8 @@ static const u32 s2[256] = { 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 }; -static const u32 s3[256] = { +EXPORT_SYMBOL_GPL(cast5_s2); +const u32 cast5_s3[256] = { 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, @@ -238,7 +231,8 @@ static const u32 s3[256] = { 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 }; -static const u32 s4[256] = { +EXPORT_SYMBOL_GPL(cast5_s3); +const u32 cast5_s4[256] = { 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, @@ -304,6 +298,7 @@ static const u32 s4[256] = { 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 }; +EXPORT_SYMBOL_GPL(cast5_s4); static const u32 s5[256] = { 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, @@ -569,17 +564,21 @@ static const u32 sb8[256] = { 0xeaee6801, 0x8db2a283, 0xea8bf59e }; +#define s1 cast5_s1 +#define s2 cast5_s2 +#define s3 cast5_s3 +#define s4 cast5_s4 + #define F1(D, m, r) ((I = ((m) + (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff])) + (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff])) #define F2(D, m, r) ((I = ((m) ^ (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff])) + (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff])) #define F3(D, m, r) ((I = ((m) - (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff])) + (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff])) -static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +void __cast5_encrypt(struct cast5_ctx *c, u8 *outbuf, const u8 *inbuf) { - struct cast5_ctx *c = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)inbuf; __be32 *dst = (__be32 *)outbuf; u32 l, r, t; @@ -628,10 +627,15 @@ static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) dst[0] = cpu_to_be32(r); dst[1] = cpu_to_be32(l); } +EXPORT_SYMBOL_GPL(__cast5_encrypt); -static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +{ + __cast5_encrypt(crypto_tfm_ctx(tfm), outbuf, inbuf); +} + +void __cast5_decrypt(struct cast5_ctx *c, u8 *outbuf, const u8 *inbuf) { - struct cast5_ctx *c = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)inbuf; __be32 *dst = (__be32 *)outbuf; u32 l, r, t; @@ -667,6 +671,12 @@ static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) dst[0] = cpu_to_be32(r); dst[1] = cpu_to_be32(l); } +EXPORT_SYMBOL_GPL(__cast5_decrypt); + +static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +{ + __cast5_decrypt(crypto_tfm_ctx(tfm), outbuf, inbuf); +} static void key_schedule(u32 *x, u32 *z, u32 *k) { @@ -743,7 +753,7 @@ static void key_schedule(u32 *x, u32 *z, u32 *k) } -static int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned key_len) +int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len) { struct cast5_ctx *c = crypto_tfm_ctx(tfm); int i; @@ -771,19 +781,22 @@ static int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned key_len) c->Kr[i] = k[i] & 0x1f; return 0; } +EXPORT_SYMBOL_GPL(cast5_setkey); static struct crypto_alg alg = { - .cra_name = "cast5", - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = CAST5_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct cast5_ctx), - .cra_alignmask = 3, - .cra_module = THIS_MODULE, - .cra_u = { + .cra_name = "cast5", + .cra_driver_name = "cast5-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = CAST5_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast5_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_u = { .cipher = { .cia_min_keysize = CAST5_MIN_KEY_SIZE, .cia_max_keysize = CAST5_MAX_KEY_SIZE, - .cia_setkey = cast5_setkey, + .cia_setkey = cast5_setkey, .cia_encrypt = cast5_encrypt, .cia_decrypt = cast5_decrypt } @@ -805,4 +818,4 @@ module_exit(cast5_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cast5 Cipher Algorithm"); - +MODULE_ALIAS("cast5"); diff --git a/include/crypto/cast5.h b/include/crypto/cast5.h new file mode 100644 index 000000000000..dcb90c13dd39 --- /dev/null +++ b/include/crypto/cast5.h @@ -0,0 +1,22 @@ +#ifndef _CRYPTO_CAST5_H +#define _CRYPTO_CAST5_H + +#include +#include + +#define CAST5_BLOCK_SIZE 8 +#define CAST5_MIN_KEY_SIZE 5 +#define CAST5_MAX_KEY_SIZE 16 + +struct cast5_ctx { + u32 Km[16]; + u8 Kr[16]; + int rr; /* rr ? rounds = 12 : rounds = 16; (rfc 2144) */ +}; + +int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen); + +void __cast5_encrypt(struct cast5_ctx *ctx, u8 *dst, const u8 *src); +void __cast5_decrypt(struct cast5_ctx *ctx, u8 *dst, const u8 *src); + +#endif From a2c5826095562983bf316e3a7eb137ef04a71a24 Mon Sep 17 00:00:00 2001 From: Johannes Goetzfried Date: Wed, 11 Jul 2012 19:37:21 +0200 Subject: [PATCH 0168/5375] crypto: testmgr - add larger cast5 testvectors New ECB, CBC and CTR testvectors for cast5. We need larger testvectors to check parallel code paths in the optimized implementation. Tests have also been added to the tcrypt module. Signed-off-by: Johannes Goetzfried Signed-off-by: Herbert Xu --- crypto/tcrypt.c | 32 ++ crypto/tcrypt.h | 1 + crypto/testmgr.c | 30 ++ crypto/testmgr.h | 810 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 871 insertions(+), 2 deletions(-) diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 5cf2ccb1540c..a94bbd77dc60 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1037,6 +1037,8 @@ static int do_test(int m) case 14: ret += tcrypt_test("ecb(cast5)"); + ret += tcrypt_test("cbc(cast5)"); + ret += tcrypt_test("ctr(cast5)"); break; case 15: @@ -1359,6 +1361,21 @@ static int do_test(int m) speed_template_8); break; + case 209: + test_cipher_speed("ecb(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_cipher_speed("ecb(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + test_cipher_speed("cbc(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_cipher_speed("cbc(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + test_cipher_speed("ctr(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_cipher_speed("ctr(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + break; + case 300: /* fall through */ @@ -1639,6 +1656,21 @@ static int do_test(int m) speed_template_8); break; + case 506: + test_acipher_speed("ecb(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_acipher_speed("ecb(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + test_acipher_speed("cbc(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_acipher_speed("cbc(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + test_acipher_speed("ctr(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_acipher_speed("ctr(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + break; + case 1000: test_available(); break; diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index 5be1fc8c1ab3..cd2068524f3f 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h @@ -47,6 +47,7 @@ static struct cipher_speed_template des3_speed_template[] = { */ static u8 speed_template_8[] = {8, 0}; static u8 speed_template_24[] = {24, 0}; +static u8 speed_template_8_16[] = {8, 16, 0}; static u8 speed_template_8_32[] = {8, 32, 0}; static u8 speed_template_16_32[] = {16, 32, 0}; static u8 speed_template_16_24_32[] = {16, 24, 32, 0}; diff --git a/crypto/testmgr.c b/crypto/testmgr.c index a2ca7431760a..7a91e540563f 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1817,6 +1817,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "cbc(cast5)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast5_cbc_enc_tv_template, + .count = CAST5_CBC_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast5_cbc_dec_tv_template, + .count = CAST5_CBC_DEC_TEST_VECTORS + } + } + } }, { .alg = "cbc(des)", .test = alg_test_skcipher, @@ -2053,6 +2068,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "ctr(cast5)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast5_ctr_enc_tv_template, + .count = CAST5_CTR_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast5_ctr_dec_tv_template, + .count = CAST5_CTR_DEC_TEST_VECTORS + } + } + } }, { .alg = "ctr(serpent)", .test = alg_test_skcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index f8179e0344ed..9309948a7028 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -12125,8 +12125,12 @@ static struct cprng_testvec ansi_cprng_aes_tv_template[] = { }; /* Cast5 test vectors from RFC 2144 */ -#define CAST5_ENC_TEST_VECTORS 3 -#define CAST5_DEC_TEST_VECTORS 3 +#define CAST5_ENC_TEST_VECTORS 4 +#define CAST5_DEC_TEST_VECTORS 4 +#define CAST5_CBC_ENC_TEST_VECTORS 1 +#define CAST5_CBC_DEC_TEST_VECTORS 1 +#define CAST5_CTR_ENC_TEST_VECTORS 1 +#define CAST5_CTR_DEC_TEST_VECTORS 1 static struct cipher_testvec cast5_enc_tv_template[] = { { @@ -12152,6 +12156,137 @@ static struct cipher_testvec cast5_enc_tv_template[] = { .ilen = 8, .result = "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e", .rlen = 8, + }, { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\x8D\xFC\x81\x9C\xCB\xAA\x5A\x1C" + "\x7E\x95\xCF\x40\xAB\x4D\x6F\xEA" + "\xD3\xD9\xB0\x9A\xB7\xC7\xE0\x2E" + "\xD1\x39\x34\x92\x8F\xFA\x14\xF1" + "\xD5\xD2\x7B\x59\x1F\x35\x28\xC2" + "\x20\xD9\x42\x06\xC9\x0B\x10\x04" + "\xF8\x79\xCD\x32\x86\x75\x4C\xB6" + "\x7B\x1C\x52\xB1\x91\x64\x22\x4B" + "\x13\xC7\xAE\x98\x0E\xB5\xCF\x6F" + "\x3F\xF4\x43\x96\x73\x0D\xA2\x05" + "\xDB\xFD\x28\x90\x2C\x56\xB9\x37" + "\x5B\x69\x0C\xAD\x84\x67\xFF\x15" + "\x4A\xD4\xA7\xD3\xDD\x99\x47\x3A" + "\xED\x34\x35\x78\x6B\x91\xC9\x32" + "\xE1\xBF\xBC\xB4\x04\x85\x6A\x39" + "\xC0\xBA\x51\xD0\x0F\x4E\xD1\xE2" + "\x1C\xFD\x0E\x05\x07\xF4\x10\xED" + "\xA2\x17\xFF\xF5\x64\xC6\x1A\x22" + "\xAD\x78\xE7\xD7\x11\xE9\x99\xB9" + "\xAA\xEC\x6F\xF8\x3B\xBF\xCE\x77" + "\x93\xE8\xAD\x1D\x50\x6C\xAE\xBC" + "\xBA\x5C\x80\xD1\x91\x65\x51\x1B" + "\xE8\x0A\xCD\x99\x96\x71\x3D\xB6" + "\x78\x75\x37\x55\xC1\xF5\x90\x40" + "\x34\xF4\x7E\xC8\xCC\x3A\x5F\x6E" + "\x36\xA1\xA1\xC2\x3A\x72\x42\x8E" + "\x0E\x37\x88\xE8\xCE\x83\xCB\xAD" + "\xE0\x69\x77\x50\xC7\x0C\x99\xCA" + "\x19\x5B\x30\x25\x9A\xEF\x9B\x0C" + "\xEF\x8F\x74\x4C\xCF\x49\x4E\xB9" + "\xC5\xAE\x9E\x2E\x78\x9A\xB9\x48" + "\xD5\x81\xE4\x37\x1D\xBF\x27\xD9" + "\xC5\xD6\x65\x43\x45\x8C\xBB\xB6" + "\x55\xF4\x06\xBB\x49\x53\x8B\x1B" + "\x07\xA9\x96\x69\x5B\xCB\x0F\xBC" + "\x93\x85\x90\x0F\x0A\x68\x40\x2A" + "\x95\xED\x2D\x88\xBF\x71\xD0\xBB" + "\xEC\xB0\x77\x6C\x79\xFC\x3C\x05" + "\x49\x3F\xB8\x24\xEF\x8E\x09\xA2" + "\x1D\xEF\x92\x02\x96\xD4\x7F\xC8" + "\x03\xB2\xCA\xDB\x17\x5C\x52\xCF" + "\xDD\x70\x37\x63\xAA\xA5\x83\x20" + "\x52\x02\xF6\xB9\xE7\x6E\x0A\xB6" + "\x79\x03\xA0\xDA\xA3\x79\x21\xBD" + "\xE3\x37\x3A\xC0\xF7\x2C\x32\xBE" + "\x8B\xE8\xA6\x00\xC7\x32\xD5\x06" + "\xBB\xE3\xAB\x06\x21\x82\xB8\x32" + "\x31\x34\x2A\xA7\x1F\x64\x99\xBF" + "\xFA\xDA\x3D\x75\xF7\x48\xD5\x48" + "\x4B\x52\x7E\xF6\x7C\xAB\x67\x59" + "\xC5\xDC\xA8\xC6\x63\x85\x4A\xDF" + "\xF0\x40\x5F\xCF\xE3\x58\x52\x67" + "\x7A\x24\x32\xC5\xEC\x9E\xA9\x6F" + "\x58\x56\xDD\x94\x1F\x71\x8D\xF4" + "\x6E\xFF\x2C\xA7\xA5\xD8\xBA\xAF" + "\x1D\x8B\xA2\x46\xB5\xC4\x9F\x57" + "\x8D\xD8\xB3\x3C\x02\x0D\xBB\x84" + "\xC7\xBD\xB4\x9A\x6E\xBB\xB1\x37" + "\x95\x79\xC4\xA7\xEA\x1D\xDC\x33" + "\x5D\x0B\x3F\x03\x8F\x30\xF9\xAE" + "\x4F\xFE\x24\x9C\x9A\x02\xE5\x57" + "\xF5\xBC\x25\xD6\x02\x56\x57\x1C", + .rlen = 496, }, }; @@ -12179,6 +12314,677 @@ static struct cipher_testvec cast5_dec_tv_template[] = { .ilen = 8, .result = "\x01\x23\x45\x67\x89\xab\xcd\xef", .rlen = 8, + }, { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .input = "\x8D\xFC\x81\x9C\xCB\xAA\x5A\x1C" + "\x7E\x95\xCF\x40\xAB\x4D\x6F\xEA" + "\xD3\xD9\xB0\x9A\xB7\xC7\xE0\x2E" + "\xD1\x39\x34\x92\x8F\xFA\x14\xF1" + "\xD5\xD2\x7B\x59\x1F\x35\x28\xC2" + "\x20\xD9\x42\x06\xC9\x0B\x10\x04" + "\xF8\x79\xCD\x32\x86\x75\x4C\xB6" + "\x7B\x1C\x52\xB1\x91\x64\x22\x4B" + "\x13\xC7\xAE\x98\x0E\xB5\xCF\x6F" + "\x3F\xF4\x43\x96\x73\x0D\xA2\x05" + "\xDB\xFD\x28\x90\x2C\x56\xB9\x37" + "\x5B\x69\x0C\xAD\x84\x67\xFF\x15" + "\x4A\xD4\xA7\xD3\xDD\x99\x47\x3A" + "\xED\x34\x35\x78\x6B\x91\xC9\x32" + "\xE1\xBF\xBC\xB4\x04\x85\x6A\x39" + "\xC0\xBA\x51\xD0\x0F\x4E\xD1\xE2" + "\x1C\xFD\x0E\x05\x07\xF4\x10\xED" + "\xA2\x17\xFF\xF5\x64\xC6\x1A\x22" + "\xAD\x78\xE7\xD7\x11\xE9\x99\xB9" + "\xAA\xEC\x6F\xF8\x3B\xBF\xCE\x77" + "\x93\xE8\xAD\x1D\x50\x6C\xAE\xBC" + "\xBA\x5C\x80\xD1\x91\x65\x51\x1B" + "\xE8\x0A\xCD\x99\x96\x71\x3D\xB6" + "\x78\x75\x37\x55\xC1\xF5\x90\x40" + "\x34\xF4\x7E\xC8\xCC\x3A\x5F\x6E" + "\x36\xA1\xA1\xC2\x3A\x72\x42\x8E" + "\x0E\x37\x88\xE8\xCE\x83\xCB\xAD" + "\xE0\x69\x77\x50\xC7\x0C\x99\xCA" + "\x19\x5B\x30\x25\x9A\xEF\x9B\x0C" + "\xEF\x8F\x74\x4C\xCF\x49\x4E\xB9" + "\xC5\xAE\x9E\x2E\x78\x9A\xB9\x48" + "\xD5\x81\xE4\x37\x1D\xBF\x27\xD9" + "\xC5\xD6\x65\x43\x45\x8C\xBB\xB6" + "\x55\xF4\x06\xBB\x49\x53\x8B\x1B" + "\x07\xA9\x96\x69\x5B\xCB\x0F\xBC" + "\x93\x85\x90\x0F\x0A\x68\x40\x2A" + "\x95\xED\x2D\x88\xBF\x71\xD0\xBB" + "\xEC\xB0\x77\x6C\x79\xFC\x3C\x05" + "\x49\x3F\xB8\x24\xEF\x8E\x09\xA2" + "\x1D\xEF\x92\x02\x96\xD4\x7F\xC8" + "\x03\xB2\xCA\xDB\x17\x5C\x52\xCF" + "\xDD\x70\x37\x63\xAA\xA5\x83\x20" + "\x52\x02\xF6\xB9\xE7\x6E\x0A\xB6" + "\x79\x03\xA0\xDA\xA3\x79\x21\xBD" + "\xE3\x37\x3A\xC0\xF7\x2C\x32\xBE" + "\x8B\xE8\xA6\x00\xC7\x32\xD5\x06" + "\xBB\xE3\xAB\x06\x21\x82\xB8\x32" + "\x31\x34\x2A\xA7\x1F\x64\x99\xBF" + "\xFA\xDA\x3D\x75\xF7\x48\xD5\x48" + "\x4B\x52\x7E\xF6\x7C\xAB\x67\x59" + "\xC5\xDC\xA8\xC6\x63\x85\x4A\xDF" + "\xF0\x40\x5F\xCF\xE3\x58\x52\x67" + "\x7A\x24\x32\xC5\xEC\x9E\xA9\x6F" + "\x58\x56\xDD\x94\x1F\x71\x8D\xF4" + "\x6E\xFF\x2C\xA7\xA5\xD8\xBA\xAF" + "\x1D\x8B\xA2\x46\xB5\xC4\x9F\x57" + "\x8D\xD8\xB3\x3C\x02\x0D\xBB\x84" + "\xC7\xBD\xB4\x9A\x6E\xBB\xB1\x37" + "\x95\x79\xC4\xA7\xEA\x1D\xDC\x33" + "\x5D\x0B\x3F\x03\x8F\x30\xF9\xAE" + "\x4F\xFE\x24\x9C\x9A\x02\xE5\x57" + "\xF5\xBC\x25\xD6\x02\x56\x57\x1C", + .ilen = 496, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + }, +}; + +static struct cipher_testvec cast5_cbc_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\x05\x28\xCE\x61\x90\x80\xE1\x78" + "\xB9\x2A\x97\x7C\xB0\x83\xD8\x1A" + "\xDE\x58\x7F\xD7\xFD\x72\xB8\xFB" + "\xDA\xF0\x6E\x77\x14\x47\x82\xBA" + "\x29\x0E\x25\x6E\xB4\x39\xD9\x7F" + "\x05\xA7\xA7\x3A\xC1\x5D\x9E\x39" + "\xA7\xFB\x0D\x05\x00\xF3\x58\x67" + "\x60\xEC\x73\x77\x46\x85\x9B\x6A" + "\x08\x3E\xBE\x59\xFB\xE4\x96\x34" + "\xB4\x05\x49\x1A\x97\x43\xAD\xA0" + "\xA9\x1E\x6E\x74\xF1\x94\xEC\xA8" + "\xB5\x8A\x20\xEA\x89\x6B\x19\xAA" + "\xA7\xF1\x33\x67\x90\x23\x0D\xEE" + "\x81\xD5\x78\x4F\xD3\x63\xEA\x46" + "\xB5\xB2\x6E\xBB\xCA\x76\x06\x10" + "\x96\x2A\x0A\xBA\xF9\x41\x5A\x1D" + "\x36\x7C\x56\x14\x54\x83\xFA\xA1" + "\x27\xDD\xBA\x8A\x90\x29\xD6\xA6" + "\xFA\x48\x3E\x1E\x23\x6E\x98\xA8" + "\xA7\xD9\x67\x92\x5C\x13\xB4\x71" + "\xA8\xAA\x89\x4A\xA4\xB3\x49\x7C" + "\x7D\x7F\xCE\x6F\x29\x2E\x7E\x37" + "\xC8\x52\x60\xD9\xE7\xCA\x60\x98" + "\xED\xCD\xE8\x60\x83\xAD\x34\x4D" + "\x96\x4A\x99\x2B\xB7\x14\x75\x66" + "\x6C\x2C\x1A\xBA\x4B\xBB\x49\x56" + "\xE1\x86\xA2\x0E\xD0\xF0\x07\xD3" + "\x18\x38\x09\x9C\x0E\x8B\x86\x07" + "\x90\x12\x37\x49\x27\x98\x69\x18" + "\xB0\xCC\xFB\xD3\xBD\x04\xA0\x85" + "\x4B\x22\x97\x07\xB6\x97\xE9\x95" + "\x0F\x88\x36\xA9\x44\x00\xC6\xE9" + "\x27\x53\x5C\x5B\x1F\xD3\xE2\xEE" + "\xD0\xCD\x63\x30\xA9\xC0\xDD\x49" + "\xFE\x16\xA4\x07\x0D\xE2\x5D\x97" + "\xDE\x89\xBA\x2E\xF3\xA9\x5E\xBE" + "\x03\x55\x0E\x02\x41\x4A\x45\x06" + "\xBE\xEA\x32\xF2\xDC\x91\x5C\x20" + "\x94\x02\x30\xD2\xFC\x29\xFA\x8E" + "\x34\xA0\x31\xB8\x34\xBA\xAE\x54" + "\xB5\x88\x1F\xDC\x43\xDC\x22\x9F" + "\xDC\xCE\xD3\xFA\xA4\xA8\xBC\x8A" + "\xC7\x5A\x43\x21\xA5\xB1\xDB\xC3" + "\x84\x3B\xB4\x9B\xB5\xA7\xF1\x0A" + "\xB6\x37\x21\x19\x55\xC2\xBD\x99" + "\x49\x24\xBB\x7C\xB3\x8E\xEF\xD2" + "\x3A\xCF\xA0\x31\x28\x0E\x25\xA2" + "\x11\xB4\x18\x17\x1A\x65\x92\x56" + "\xE8\xE0\x52\x9C\x61\x18\x2A\xB1" + "\x1A\x01\x22\x45\x17\x62\x52\x6C" + "\x91\x44\xCF\x98\xC7\xC0\x79\x26" + "\x32\x66\x6F\x23\x7F\x94\x36\x88" + "\x3C\xC9\xD0\xB7\x45\x30\x31\x86" + "\x3D\xC6\xA3\x98\x62\x84\x1A\x8B" + "\x16\x88\xC7\xA3\xE9\x4F\xE0\x86" + "\xA4\x93\xA8\x34\x5A\xCA\xDF\xCA" + "\x46\x38\xD2\xF4\xE0\x2D\x1E\xC9" + "\x7C\xEF\x53\xB7\x60\x72\x41\xBF" + "\x29\x00\x87\x02\xAF\x44\x4C\xB7" + "\x8C\xF5\x3F\x19\xF4\x80\x45\xA7" + "\x15\x5F\xDB\xE9\xB1\x83\xD2\xE6" + "\x1D\x18\x66\x44\x5B\x8F\x14\xEB", + .rlen = 496, + }, +}; + +static struct cipher_testvec cast5_cbc_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .input = "\x05\x28\xCE\x61\x90\x80\xE1\x78" + "\xB9\x2A\x97\x7C\xB0\x83\xD8\x1A" + "\xDE\x58\x7F\xD7\xFD\x72\xB8\xFB" + "\xDA\xF0\x6E\x77\x14\x47\x82\xBA" + "\x29\x0E\x25\x6E\xB4\x39\xD9\x7F" + "\x05\xA7\xA7\x3A\xC1\x5D\x9E\x39" + "\xA7\xFB\x0D\x05\x00\xF3\x58\x67" + "\x60\xEC\x73\x77\x46\x85\x9B\x6A" + "\x08\x3E\xBE\x59\xFB\xE4\x96\x34" + "\xB4\x05\x49\x1A\x97\x43\xAD\xA0" + "\xA9\x1E\x6E\x74\xF1\x94\xEC\xA8" + "\xB5\x8A\x20\xEA\x89\x6B\x19\xAA" + "\xA7\xF1\x33\x67\x90\x23\x0D\xEE" + "\x81\xD5\x78\x4F\xD3\x63\xEA\x46" + "\xB5\xB2\x6E\xBB\xCA\x76\x06\x10" + "\x96\x2A\x0A\xBA\xF9\x41\x5A\x1D" + "\x36\x7C\x56\x14\x54\x83\xFA\xA1" + "\x27\xDD\xBA\x8A\x90\x29\xD6\xA6" + "\xFA\x48\x3E\x1E\x23\x6E\x98\xA8" + "\xA7\xD9\x67\x92\x5C\x13\xB4\x71" + "\xA8\xAA\x89\x4A\xA4\xB3\x49\x7C" + "\x7D\x7F\xCE\x6F\x29\x2E\x7E\x37" + "\xC8\x52\x60\xD9\xE7\xCA\x60\x98" + "\xED\xCD\xE8\x60\x83\xAD\x34\x4D" + "\x96\x4A\x99\x2B\xB7\x14\x75\x66" + "\x6C\x2C\x1A\xBA\x4B\xBB\x49\x56" + "\xE1\x86\xA2\x0E\xD0\xF0\x07\xD3" + "\x18\x38\x09\x9C\x0E\x8B\x86\x07" + "\x90\x12\x37\x49\x27\x98\x69\x18" + "\xB0\xCC\xFB\xD3\xBD\x04\xA0\x85" + "\x4B\x22\x97\x07\xB6\x97\xE9\x95" + "\x0F\x88\x36\xA9\x44\x00\xC6\xE9" + "\x27\x53\x5C\x5B\x1F\xD3\xE2\xEE" + "\xD0\xCD\x63\x30\xA9\xC0\xDD\x49" + "\xFE\x16\xA4\x07\x0D\xE2\x5D\x97" + "\xDE\x89\xBA\x2E\xF3\xA9\x5E\xBE" + "\x03\x55\x0E\x02\x41\x4A\x45\x06" + "\xBE\xEA\x32\xF2\xDC\x91\x5C\x20" + "\x94\x02\x30\xD2\xFC\x29\xFA\x8E" + "\x34\xA0\x31\xB8\x34\xBA\xAE\x54" + "\xB5\x88\x1F\xDC\x43\xDC\x22\x9F" + "\xDC\xCE\xD3\xFA\xA4\xA8\xBC\x8A" + "\xC7\x5A\x43\x21\xA5\xB1\xDB\xC3" + "\x84\x3B\xB4\x9B\xB5\xA7\xF1\x0A" + "\xB6\x37\x21\x19\x55\xC2\xBD\x99" + "\x49\x24\xBB\x7C\xB3\x8E\xEF\xD2" + "\x3A\xCF\xA0\x31\x28\x0E\x25\xA2" + "\x11\xB4\x18\x17\x1A\x65\x92\x56" + "\xE8\xE0\x52\x9C\x61\x18\x2A\xB1" + "\x1A\x01\x22\x45\x17\x62\x52\x6C" + "\x91\x44\xCF\x98\xC7\xC0\x79\x26" + "\x32\x66\x6F\x23\x7F\x94\x36\x88" + "\x3C\xC9\xD0\xB7\x45\x30\x31\x86" + "\x3D\xC6\xA3\x98\x62\x84\x1A\x8B" + "\x16\x88\xC7\xA3\xE9\x4F\xE0\x86" + "\xA4\x93\xA8\x34\x5A\xCA\xDF\xCA" + "\x46\x38\xD2\xF4\xE0\x2D\x1E\xC9" + "\x7C\xEF\x53\xB7\x60\x72\x41\xBF" + "\x29\x00\x87\x02\xAF\x44\x4C\xB7" + "\x8C\xF5\x3F\x19\xF4\x80\x45\xA7" + "\x15\x5F\xDB\xE9\xB1\x83\xD2\xE6" + "\x1D\x18\x66\x44\x5B\x8F\x14\xEB", + .ilen = 496, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + }, +}; + +static struct cipher_testvec cast5_ctr_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\xFF\xC4\x2E\x82\x3D\xF8\xA8\x39" + "\x7C\x52\xC4\xD3\xBB\x62\xC6\xA8" + "\x0C\x63\xA5\x55\xE3\xF8\x1C\x7F" + "\xDC\x59\xF9\xA0\x52\xAD\x83\xDF" + "\xD5\x3B\x53\x4A\xAA\x1F\x49\x44" + "\xE8\x20\xCC\xF8\x97\xE6\xE0\x3C" + "\x5A\xD2\x83\xEC\xEE\x25\x3F\xCF" + "\x0D\xC2\x79\x80\x99\x6E\xFF\x7B" + "\x64\xB0\x7B\x86\x29\x1D\x9F\x17" + "\x10\xA5\xA5\xEB\x16\x55\x9E\xE3" + "\x88\x18\x52\x56\x48\x58\xD1\x6B" + "\xE8\x74\x6E\x48\xB0\x2E\x69\x63" + "\x32\xAA\xAC\x26\x55\x45\x94\xDE" + "\x30\x26\x26\xE6\x08\x82\x2F\x5F" + "\xA7\x15\x94\x07\x75\x2D\xC6\x3A" + "\x1B\xA0\x39\xFB\xBA\xB9\x06\x56" + "\xF6\x9F\xF1\x2F\x9B\xF3\x89\x8B" + "\x08\xC8\x9D\x5E\x6B\x95\x09\xC7" + "\x98\xB7\x62\xA4\x1D\x25\xFA\xC5" + "\x62\xC8\x5D\x6B\xB4\x85\x88\x7F" + "\x3B\x29\xF9\xB4\x32\x62\x69\xBF" + "\x32\xB8\xEB\xFD\x0E\x26\xAA\xA3" + "\x44\x67\x90\x20\xAC\x41\xDF\x43" + "\xC6\xC7\x19\x9F\x2C\x28\x74\xEB" + "\x3E\x7F\x7A\x80\x5B\xE4\x08\x60" + "\xC7\xC9\x71\x34\x44\xCE\x05\xFD" + "\xA8\x91\xA8\x44\x5E\xD3\x89\x2C" + "\xAE\x59\x0F\x07\x88\x79\x53\x26" + "\xAF\xAC\xCB\x1D\x6F\x08\x25\x62" + "\xD0\x82\x65\x66\xE4\x2A\x29\x1C" + "\x9C\x64\x5F\x49\x9D\xF8\x62\xF9" + "\xED\xC4\x13\x52\x75\xDC\xE4\xF9" + "\x68\x0F\x8A\xCD\xA6\x8D\x75\xAA" + "\x49\xA1\x86\x86\x37\x5C\x6B\x3D" + "\x56\xE5\x6F\xBE\x27\xC0\x10\xF8" + "\x3C\x4D\x17\x35\x14\xDC\x1C\xA0" + "\x6E\xAE\xD1\x10\xDD\x83\x06\xC2" + "\x23\xD3\xC7\x27\x15\x04\x2C\x27" + "\xDD\x1F\x2E\x97\x09\x9C\x33\x7D" + "\xAC\x50\x1B\x2E\xC9\x52\x0C\x14" + "\x4B\x78\xC4\xDE\x07\x6A\x12\x02" + "\x6E\xD7\x4B\x91\xB9\x88\x4D\x02" + "\xC3\xB5\x04\xBC\xE0\x67\xCA\x18" + "\x22\xA1\xAE\x9A\x21\xEF\xB2\x06" + "\x35\xCD\xEC\x37\x70\x2D\xFC\x1E" + "\xA8\x31\xE7\xFC\xE5\x8E\x88\x66" + "\x16\xB5\xC8\x45\x21\x37\xBD\x24" + "\xA9\xD5\x36\x12\x9F\x6E\x67\x80" + "\x87\x54\xD5\xAF\x97\xE1\x15\xA7" + "\x11\xF0\x63\x7B\xE1\x44\x14\x1C" + "\x06\x32\x05\x8C\x6C\xDB\x9B\x36" + "\x6A\x6B\xAD\x3A\x27\x55\x20\x4C" + "\x76\x36\x43\xE8\x16\x60\xB5\xF3" + "\xDF\x5A\xC6\xA5\x69\x78\x59\x51" + "\x54\x68\x65\x06\x84\xDE\x3D\xAE" + "\x38\x91\xBD\xCC\xA2\x8A\xEC\xE6" + "\x9E\x83\xAE\x1E\x8E\x34\x5D\xDE" + "\x91\xCE\x8F\xED\x40\xF7\xC8\x8B" + "\x9A\x13\x4C\xAD\x89\x97\x9E\xD1" + "\x91\x01\xD7\x21\x23\x28\x1E\xCC" + "\x8C\x98\xDB\xDE\xFC\x72\x94\xAA" + "\xC0\x0D\x96\xAA\x23\xF8\xFE\x13", + .rlen = 496, + }, +}; + +static struct cipher_testvec cast5_ctr_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .input = "\xFF\xC4\x2E\x82\x3D\xF8\xA8\x39" + "\x7C\x52\xC4\xD3\xBB\x62\xC6\xA8" + "\x0C\x63\xA5\x55\xE3\xF8\x1C\x7F" + "\xDC\x59\xF9\xA0\x52\xAD\x83\xDF" + "\xD5\x3B\x53\x4A\xAA\x1F\x49\x44" + "\xE8\x20\xCC\xF8\x97\xE6\xE0\x3C" + "\x5A\xD2\x83\xEC\xEE\x25\x3F\xCF" + "\x0D\xC2\x79\x80\x99\x6E\xFF\x7B" + "\x64\xB0\x7B\x86\x29\x1D\x9F\x17" + "\x10\xA5\xA5\xEB\x16\x55\x9E\xE3" + "\x88\x18\x52\x56\x48\x58\xD1\x6B" + "\xE8\x74\x6E\x48\xB0\x2E\x69\x63" + "\x32\xAA\xAC\x26\x55\x45\x94\xDE" + "\x30\x26\x26\xE6\x08\x82\x2F\x5F" + "\xA7\x15\x94\x07\x75\x2D\xC6\x3A" + "\x1B\xA0\x39\xFB\xBA\xB9\x06\x56" + "\xF6\x9F\xF1\x2F\x9B\xF3\x89\x8B" + "\x08\xC8\x9D\x5E\x6B\x95\x09\xC7" + "\x98\xB7\x62\xA4\x1D\x25\xFA\xC5" + "\x62\xC8\x5D\x6B\xB4\x85\x88\x7F" + "\x3B\x29\xF9\xB4\x32\x62\x69\xBF" + "\x32\xB8\xEB\xFD\x0E\x26\xAA\xA3" + "\x44\x67\x90\x20\xAC\x41\xDF\x43" + "\xC6\xC7\x19\x9F\x2C\x28\x74\xEB" + "\x3E\x7F\x7A\x80\x5B\xE4\x08\x60" + "\xC7\xC9\x71\x34\x44\xCE\x05\xFD" + "\xA8\x91\xA8\x44\x5E\xD3\x89\x2C" + "\xAE\x59\x0F\x07\x88\x79\x53\x26" + "\xAF\xAC\xCB\x1D\x6F\x08\x25\x62" + "\xD0\x82\x65\x66\xE4\x2A\x29\x1C" + "\x9C\x64\x5F\x49\x9D\xF8\x62\xF9" + "\xED\xC4\x13\x52\x75\xDC\xE4\xF9" + "\x68\x0F\x8A\xCD\xA6\x8D\x75\xAA" + "\x49\xA1\x86\x86\x37\x5C\x6B\x3D" + "\x56\xE5\x6F\xBE\x27\xC0\x10\xF8" + "\x3C\x4D\x17\x35\x14\xDC\x1C\xA0" + "\x6E\xAE\xD1\x10\xDD\x83\x06\xC2" + "\x23\xD3\xC7\x27\x15\x04\x2C\x27" + "\xDD\x1F\x2E\x97\x09\x9C\x33\x7D" + "\xAC\x50\x1B\x2E\xC9\x52\x0C\x14" + "\x4B\x78\xC4\xDE\x07\x6A\x12\x02" + "\x6E\xD7\x4B\x91\xB9\x88\x4D\x02" + "\xC3\xB5\x04\xBC\xE0\x67\xCA\x18" + "\x22\xA1\xAE\x9A\x21\xEF\xB2\x06" + "\x35\xCD\xEC\x37\x70\x2D\xFC\x1E" + "\xA8\x31\xE7\xFC\xE5\x8E\x88\x66" + "\x16\xB5\xC8\x45\x21\x37\xBD\x24" + "\xA9\xD5\x36\x12\x9F\x6E\x67\x80" + "\x87\x54\xD5\xAF\x97\xE1\x15\xA7" + "\x11\xF0\x63\x7B\xE1\x44\x14\x1C" + "\x06\x32\x05\x8C\x6C\xDB\x9B\x36" + "\x6A\x6B\xAD\x3A\x27\x55\x20\x4C" + "\x76\x36\x43\xE8\x16\x60\xB5\xF3" + "\xDF\x5A\xC6\xA5\x69\x78\x59\x51" + "\x54\x68\x65\x06\x84\xDE\x3D\xAE" + "\x38\x91\xBD\xCC\xA2\x8A\xEC\xE6" + "\x9E\x83\xAE\x1E\x8E\x34\x5D\xDE" + "\x91\xCE\x8F\xED\x40\xF7\xC8\x8B" + "\x9A\x13\x4C\xAD\x89\x97\x9E\xD1" + "\x91\x01\xD7\x21\x23\x28\x1E\xCC" + "\x8C\x98\xDB\xDE\xFC\x72\x94\xAA" + "\xC0\x0D\x96\xAA\x23\xF8\xFE\x13", + .ilen = 496, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, }, }; From 4d6d6a2c850f89bc9283d02519cb536baba72032 Mon Sep 17 00:00:00 2001 From: Johannes Goetzfried Date: Wed, 11 Jul 2012 19:37:37 +0200 Subject: [PATCH 0169/5375] crypto: cast5 - add x86_64/avx assembler implementation This patch adds a x86_64/avx assembler implementation of the Cast5 block cipher. The implementation processes sixteen blocks in parallel (four 4 block chunk AVX operations). The table-lookups are done in general-purpose registers. For small blocksizes the functions from the generic module are called. A good performance increase is provided for blocksizes greater or equal to 128B. Patch has been tested with tcrypt and automated filesystem tests. Tcrypt benchmark results: Intel Core i5-2500 CPU (fam:6, model:42, step:7) cast5-avx-x86_64 vs. cast5-generic 64bit key: size ecb-enc ecb-dec cbc-enc cbc-dec ctr-enc ctr-dec 16B 0.99x 0.99x 1.00x 1.00x 1.02x 1.01x 64B 1.00x 1.00x 0.98x 1.00x 1.01x 1.02x 256B 2.03x 2.01x 0.95x 2.11x 2.12x 2.13x 1024B 2.30x 2.24x 0.95x 2.29x 2.35x 2.35x 8192B 2.31x 2.27x 0.95x 2.31x 2.39x 2.39x 128bit key: size ecb-enc ecb-dec cbc-enc cbc-dec ctr-enc ctr-dec 16B 0.99x 0.99x 1.00x 1.00x 1.01x 1.01x 64B 1.00x 1.00x 0.98x 1.01x 1.02x 1.01x 256B 2.17x 2.13x 0.96x 2.19x 2.19x 2.19x 1024B 2.29x 2.32x 0.95x 2.34x 2.37x 2.38x 8192B 2.35x 2.32x 0.95x 2.35x 2.39x 2.39x Signed-off-by: Johannes Goetzfried Signed-off-by: Herbert Xu --- arch/x86/crypto/Makefile | 2 + arch/x86/crypto/cast5-avx-x86_64-asm_64.S | 322 +++++++++++++ arch/x86/crypto/cast5_avx_glue.c | 530 ++++++++++++++++++++++ crypto/Kconfig | 14 + crypto/testmgr.c | 60 +++ 5 files changed, 928 insertions(+) create mode 100644 arch/x86/crypto/cast5-avx-x86_64-asm_64.S create mode 100644 arch/x86/crypto/cast5_avx_glue.c diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index e908e5de82d3..565e82b00142 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o +obj-$(CONFIG_CRYPTO_CAST5_AVX_X86_64) += cast5-avx-x86_64.o obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o @@ -32,6 +33,7 @@ serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o +cast5-avx-x86_64-y := cast5-avx-x86_64-asm_64.o cast5_avx_glue.o blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o diff --git a/arch/x86/crypto/cast5-avx-x86_64-asm_64.S b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S new file mode 100644 index 000000000000..94693c877e3b --- /dev/null +++ b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S @@ -0,0 +1,322 @@ +/* + * Cast5 Cipher 16-way parallel algorithm (AVX/x86_64) + * + * Copyright (C) 2012 Johannes Goetzfried + * + * + * 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 + * + */ + +.file "cast5-avx-x86_64-asm_64.S" +.text + +.extern cast5_s1 +.extern cast5_s2 +.extern cast5_s3 +.extern cast5_s4 + +/* structure of crypto context */ +#define km 0 +#define kr (16*4) +#define rr ((16*4)+16) + +/* s-boxes */ +#define s1 cast5_s1 +#define s2 cast5_s2 +#define s3 cast5_s3 +#define s4 cast5_s4 + +/********************************************************************** + 16-way AVX cast5 + **********************************************************************/ +#define CTX %rdi + +#define RL1 %xmm0 +#define RR1 %xmm1 +#define RL2 %xmm2 +#define RR2 %xmm3 +#define RL3 %xmm4 +#define RR3 %xmm5 +#define RL4 %xmm6 +#define RR4 %xmm7 + +#define RX %xmm8 + +#define RKM %xmm9 +#define RKRF %xmm10 +#define RKRR %xmm11 + +#define RTMP %xmm12 +#define RMASK %xmm13 +#define R32 %xmm14 + +#define RID1 %rax +#define RID1b %al +#define RID2 %rbx +#define RID2b %bl + +#define RGI1 %rdx +#define RGI1bl %dl +#define RGI1bh %dh +#define RGI2 %rcx +#define RGI2bl %cl +#define RGI2bh %ch + +#define RFS1 %r8 +#define RFS1d %r8d +#define RFS2 %r9 +#define RFS2d %r9d +#define RFS3 %r10 +#define RFS3d %r10d + + +#define lookup_32bit(src, dst, op1, op2, op3) \ + movb src ## bl, RID1b; \ + movb src ## bh, RID2b; \ + movl s1(, RID1, 4), dst ## d; \ + op1 s2(, RID2, 4), dst ## d; \ + shrq $16, src; \ + movb src ## bl, RID1b; \ + movb src ## bh, RID2b; \ + op2 s3(, RID1, 4), dst ## d; \ + op3 s4(, RID2, 4), dst ## d; + +#define F(a, x, op0, op1, op2, op3) \ + op0 a, RKM, x; \ + vpslld RKRF, x, RTMP; \ + vpsrld RKRR, x, x; \ + vpor RTMP, x, x; \ + \ + vpshufb RMASK, x, x; \ + vmovq x, RGI1; \ + vpsrldq $8, x, x; \ + vmovq x, RGI2; \ + \ + lookup_32bit(RGI1, RFS1, op1, op2, op3); \ + shrq $16, RGI1; \ + lookup_32bit(RGI1, RFS2, op1, op2, op3); \ + shlq $32, RFS2; \ + orq RFS1, RFS2; \ + \ + lookup_32bit(RGI2, RFS1, op1, op2, op3); \ + shrq $16, RGI2; \ + lookup_32bit(RGI2, RFS3, op1, op2, op3); \ + shlq $32, RFS3; \ + orq RFS1, RFS3; \ + \ + vmovq RFS2, x; \ + vpinsrq $1, RFS3, x, x; + +#define F1(b, x) F(b, x, vpaddd, xorl, subl, addl) +#define F2(b, x) F(b, x, vpxor, subl, addl, xorl) +#define F3(b, x) F(b, x, vpsubd, addl, xorl, subl) + +#define subround(a, b, x, n, f) \ + F ## f(b, x); \ + vpxor a, x, a; + +#define round(l, r, n, f) \ + vbroadcastss (km+(4*n))(CTX), RKM; \ + vpinsrb $0, (kr+n)(CTX), RKRF, RKRF; \ + vpsubq RKRF, R32, RKRR; \ + subround(l ## 1, r ## 1, RX, n, f); \ + subround(l ## 2, r ## 2, RX, n, f); \ + subround(l ## 3, r ## 3, RX, n, f); \ + subround(l ## 4, r ## 4, RX, n, f); + + +#define transpose_2x4(x0, x1, t0, t1) \ + vpunpckldq x1, x0, t0; \ + vpunpckhdq x1, x0, t1; \ + \ + vpunpcklqdq t1, t0, x0; \ + vpunpckhqdq t1, t0, x1; + +#define inpack_blocks(in, x0, x1, t0, t1) \ + vmovdqu (0*4*4)(in), x0; \ + vmovdqu (1*4*4)(in), x1; \ + vpshufb RMASK, x0, x0; \ + vpshufb RMASK, x1, x1; \ + \ + transpose_2x4(x0, x1, t0, t1) + +#define outunpack_blocks(out, x0, x1, t0, t1) \ + transpose_2x4(x0, x1, t0, t1) \ + \ + vpshufb RMASK, x0, x0; \ + vpshufb RMASK, x1, x1; \ + vmovdqu x0, (0*4*4)(out); \ + vmovdqu x1, (1*4*4)(out); + +#define outunpack_xor_blocks(out, x0, x1, t0, t1) \ + transpose_2x4(x0, x1, t0, t1) \ + \ + vpshufb RMASK, x0, x0; \ + vpshufb RMASK, x1, x1; \ + vpxor (0*4*4)(out), x0, x0; \ + vmovdqu x0, (0*4*4)(out); \ + vpxor (1*4*4)(out), x1, x1; \ + vmovdqu x1, (1*4*4)(out); + +.align 16 +.Lbswap_mask: + .byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 +.L32_mask: + .byte 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0 + +.align 16 +.global __cast5_enc_blk_16way +.type __cast5_enc_blk_16way,@function; + +__cast5_enc_blk_16way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + * %rcx: bool, if true: xor output + */ + + pushq %rbx; + pushq %rcx; + + vmovdqu .Lbswap_mask, RMASK; + vmovdqu .L32_mask, R32; + vpxor RKRF, RKRF, RKRF; + + inpack_blocks(%rdx, RL1, RR1, RTMP, RX); + leaq (2*4*4)(%rdx), %rax; + inpack_blocks(%rax, RL2, RR2, RTMP, RX); + leaq (2*4*4)(%rax), %rax; + inpack_blocks(%rax, RL3, RR3, RTMP, RX); + leaq (2*4*4)(%rax), %rax; + inpack_blocks(%rax, RL4, RR4, RTMP, RX); + + xorq RID1, RID1; + xorq RID2, RID2; + + round(RL, RR, 0, 1); + round(RR, RL, 1, 2); + round(RL, RR, 2, 3); + round(RR, RL, 3, 1); + round(RL, RR, 4, 2); + round(RR, RL, 5, 3); + round(RL, RR, 6, 1); + round(RR, RL, 7, 2); + round(RL, RR, 8, 3); + round(RR, RL, 9, 1); + round(RL, RR, 10, 2); + round(RR, RL, 11, 3); + + movb rr(CTX), %al; + testb %al, %al; + jnz __skip_enc; + + round(RL, RR, 12, 1); + round(RR, RL, 13, 2); + round(RL, RR, 14, 3); + round(RR, RL, 15, 1); + +__skip_enc: + popq %rcx; + popq %rbx; + + testb %cl, %cl; + jnz __enc_xor16; + + outunpack_blocks(%rsi, RR1, RL1, RTMP, RX); + leaq (2*4*4)(%rsi), %rax; + outunpack_blocks(%rax, RR2, RL2, RTMP, RX); + leaq (2*4*4)(%rax), %rax; + outunpack_blocks(%rax, RR3, RL3, RTMP, RX); + leaq (2*4*4)(%rax), %rax; + outunpack_blocks(%rax, RR4, RL4, RTMP, RX); + + ret; + +__enc_xor16: + outunpack_xor_blocks(%rsi, RR1, RL1, RTMP, RX); + leaq (2*4*4)(%rsi), %rax; + outunpack_xor_blocks(%rax, RR2, RL2, RTMP, RX); + leaq (2*4*4)(%rax), %rax; + outunpack_xor_blocks(%rax, RR3, RL3, RTMP, RX); + leaq (2*4*4)(%rax), %rax; + outunpack_xor_blocks(%rax, RR4, RL4, RTMP, RX); + + ret; + +.align 16 +.global cast5_dec_blk_16way +.type cast5_dec_blk_16way,@function; + +cast5_dec_blk_16way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + + pushq %rbx; + + vmovdqu .Lbswap_mask, RMASK; + vmovdqu .L32_mask, R32; + vpxor RKRF, RKRF, RKRF; + + inpack_blocks(%rdx, RL1, RR1, RTMP, RX); + leaq (2*4*4)(%rdx), %rax; + inpack_blocks(%rax, RL2, RR2, RTMP, RX); + leaq (2*4*4)(%rax), %rax; + inpack_blocks(%rax, RL3, RR3, RTMP, RX); + leaq (2*4*4)(%rax), %rax; + inpack_blocks(%rax, RL4, RR4, RTMP, RX); + + xorq RID1, RID1; + xorq RID2, RID2; + + movb rr(CTX), %al; + testb %al, %al; + jnz __skip_dec; + + round(RL, RR, 15, 1); + round(RR, RL, 14, 3); + round(RL, RR, 13, 2); + round(RR, RL, 12, 1); + +__skip_dec: + round(RL, RR, 11, 3); + round(RR, RL, 10, 2); + round(RL, RR, 9, 1); + round(RR, RL, 8, 3); + round(RL, RR, 7, 2); + round(RR, RL, 6, 1); + round(RL, RR, 5, 3); + round(RR, RL, 4, 2); + round(RL, RR, 3, 1); + round(RR, RL, 2, 3); + round(RL, RR, 1, 2); + round(RR, RL, 0, 1); + + popq %rbx; + + outunpack_blocks(%rsi, RR1, RL1, RTMP, RX); + leaq (2*4*4)(%rsi), %rax; + outunpack_blocks(%rax, RR2, RL2, RTMP, RX); + leaq (2*4*4)(%rax), %rax; + outunpack_blocks(%rax, RR3, RL3, RTMP, RX); + leaq (2*4*4)(%rax), %rax; + outunpack_blocks(%rax, RR4, RL4, RTMP, RX); + + ret; diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c new file mode 100644 index 000000000000..445aab06387b --- /dev/null +++ b/arch/x86/crypto/cast5_avx_glue.c @@ -0,0 +1,530 @@ +/* + * Glue Code for the AVX assembler implemention of the Cast5 Cipher + * + * Copyright (C) 2012 Johannes Goetzfried + * + * + * 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 + +#define CAST5_PARALLEL_BLOCKS 16 + +asmlinkage void __cast5_enc_blk_16way(struct cast5_ctx *ctx, u8 *dst, + const u8 *src, bool xor); +asmlinkage void cast5_dec_blk_16way(struct cast5_ctx *ctx, u8 *dst, + const u8 *src); + +static inline void cast5_enc_blk_xway(struct cast5_ctx *ctx, u8 *dst, + const u8 *src) +{ + __cast5_enc_blk_16way(ctx, dst, src, false); +} + +static inline void cast5_enc_blk_xway_xor(struct cast5_ctx *ctx, u8 *dst, + const u8 *src) +{ + __cast5_enc_blk_16way(ctx, dst, src, true); +} + +static inline void cast5_dec_blk_xway(struct cast5_ctx *ctx, u8 *dst, + const u8 *src) +{ + cast5_dec_blk_16way(ctx, dst, src); +} + + +static inline bool cast5_fpu_begin(bool fpu_enabled, unsigned int nbytes) +{ + return glue_fpu_begin(CAST5_BLOCK_SIZE, CAST5_PARALLEL_BLOCKS, + NULL, fpu_enabled, nbytes); +} + +static inline void cast5_fpu_end(bool fpu_enabled) +{ + return glue_fpu_end(fpu_enabled); +} + +static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, + bool enc) +{ + bool fpu_enabled = false; + struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + const unsigned int bsize = CAST5_BLOCK_SIZE; + unsigned int nbytes; + int err; + + err = blkcipher_walk_virt(desc, walk); + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + + while ((nbytes = walk->nbytes)) { + u8 *wsrc = walk->src.virt.addr; + u8 *wdst = walk->dst.virt.addr; + + fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes); + + /* Process multi-block batch */ + if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) { + do { + if (enc) + cast5_enc_blk_xway(ctx, wdst, wsrc); + else + cast5_dec_blk_xway(ctx, wdst, wsrc); + + wsrc += bsize * CAST5_PARALLEL_BLOCKS; + wdst += bsize * CAST5_PARALLEL_BLOCKS; + nbytes -= bsize * CAST5_PARALLEL_BLOCKS; + } while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + do { + if (enc) + __cast5_encrypt(ctx, wdst, wsrc); + else + __cast5_decrypt(ctx, wdst, wsrc); + + wsrc += bsize; + wdst += bsize; + nbytes -= bsize; + } while (nbytes >= bsize); + +done: + err = blkcipher_walk_done(desc, walk, nbytes); + } + + cast5_fpu_end(fpu_enabled); + return err; +} + +static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_crypt(desc, &walk, true); +} + +static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_crypt(desc, &walk, false); +} + +static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + const unsigned int bsize = CAST5_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u64 *src = (u64 *)walk->src.virt.addr; + u64 *dst = (u64 *)walk->dst.virt.addr; + u64 *iv = (u64 *)walk->iv; + + do { + *dst = *src ^ *iv; + __cast5_encrypt(ctx, (u8 *)dst, (u8 *)dst); + iv = dst; + + src += 1; + dst += 1; + nbytes -= bsize; + } while (nbytes >= bsize); + + *(u64 *)walk->iv ^= *iv; + return nbytes; +} + +static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + nbytes = __cbc_encrypt(desc, &walk); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static unsigned int __cbc_decrypt(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + const unsigned int bsize = CAST5_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u64 *src = (u64 *)walk->src.virt.addr; + u64 *dst = (u64 *)walk->dst.virt.addr; + u64 ivs[CAST5_PARALLEL_BLOCKS - 1]; + u64 last_iv; + int i; + + /* Start of the last block. */ + src += nbytes / bsize - 1; + dst += nbytes / bsize - 1; + + last_iv = *src; + + /* Process multi-block batch */ + if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) { + do { + nbytes -= bsize * (CAST5_PARALLEL_BLOCKS - 1); + src -= CAST5_PARALLEL_BLOCKS - 1; + dst -= CAST5_PARALLEL_BLOCKS - 1; + + for (i = 0; i < CAST5_PARALLEL_BLOCKS - 1; i++) + ivs[i] = src[i]; + + cast5_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src); + + for (i = 0; i < CAST5_PARALLEL_BLOCKS - 1; i++) + *(dst + (i + 1)) ^= *(ivs + i); + + nbytes -= bsize; + if (nbytes < bsize) + goto done; + + *dst ^= *(src - 1); + src -= 1; + dst -= 1; + } while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + for (;;) { + __cast5_decrypt(ctx, (u8 *)dst, (u8 *)src); + + nbytes -= bsize; + if (nbytes < bsize) + break; + + *dst ^= *(src - 1); + src -= 1; + dst -= 1; + } + +done: + *dst ^= *(u64 *)walk->iv; + *(u64 *)walk->iv = last_iv; + + return nbytes; +} + +static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + bool fpu_enabled = false; + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + + while ((nbytes = walk.nbytes)) { + fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes); + nbytes = __cbc_decrypt(desc, &walk); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + cast5_fpu_end(fpu_enabled); + return err; +} + +static void ctr_crypt_final(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + u8 *ctrblk = walk->iv; + u8 keystream[CAST5_BLOCK_SIZE]; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + unsigned int nbytes = walk->nbytes; + + __cast5_encrypt(ctx, keystream, ctrblk); + crypto_xor(keystream, src, nbytes); + memcpy(dst, keystream, nbytes); + + crypto_inc(ctrblk, CAST5_BLOCK_SIZE); +} + +static unsigned int __ctr_crypt(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + const unsigned int bsize = CAST5_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u64 *src = (u64 *)walk->src.virt.addr; + u64 *dst = (u64 *)walk->dst.virt.addr; + u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv); + __be64 ctrblocks[CAST5_PARALLEL_BLOCKS]; + int i; + + /* Process multi-block batch */ + if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) { + do { + /* create ctrblks for parallel encrypt */ + for (i = 0; i < CAST5_PARALLEL_BLOCKS; i++) { + if (dst != src) + dst[i] = src[i]; + + ctrblocks[i] = cpu_to_be64(ctrblk++); + } + + cast5_enc_blk_xway_xor(ctx, (u8 *)dst, + (u8 *)ctrblocks); + + src += CAST5_PARALLEL_BLOCKS; + dst += CAST5_PARALLEL_BLOCKS; + nbytes -= bsize * CAST5_PARALLEL_BLOCKS; + } while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + do { + if (dst != src) + *dst = *src; + + ctrblocks[0] = cpu_to_be64(ctrblk++); + + __cast5_encrypt(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks); + *dst ^= ctrblocks[0]; + + src += 1; + dst += 1; + nbytes -= bsize; + } while (nbytes >= bsize); + +done: + *(__be64 *)walk->iv = cpu_to_be64(ctrblk); + return nbytes; +} + +static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + bool fpu_enabled = false; + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, CAST5_BLOCK_SIZE); + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + + while ((nbytes = walk.nbytes) >= CAST5_BLOCK_SIZE) { + fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes); + nbytes = __ctr_crypt(desc, &walk); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + cast5_fpu_end(fpu_enabled); + + if (walk.nbytes) { + ctr_crypt_final(desc, &walk); + err = blkcipher_walk_done(desc, &walk, 0); + } + + return err; +} + + +static struct crypto_alg cast5_algs[6] = { { + .cra_name = "__ecb-cast5-avx", + .cra_driver_name = "__driver-ecb-cast5-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST5_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast5_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .setkey = cast5_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "__cbc-cast5-avx", + .cra_driver_name = "__driver-cbc-cast5-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST5_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast5_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .setkey = cast5_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { + .cra_name = "__ctr-cast5-avx", + .cra_driver_name = "__driver-ctr-cast5-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct cast5_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .ivsize = CAST5_BLOCK_SIZE, + .setkey = cast5_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}, { + .cra_name = "ecb(cast5)", + .cra_driver_name = "ecb-cast5-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST5_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}, { + .cra_name = "cbc(cast5)", + .cra_driver_name = "cbc-cast5-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST5_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .ivsize = CAST5_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = __ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}, { + .cra_name = "ctr(cast5)", + .cra_driver_name = "ctr-cast5-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .ivsize = CAST5_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_encrypt, + .geniv = "chainiv", + }, + }, +} }; + +static int __init cast5_init(void) +{ + u64 xcr0; + + if (!cpu_has_avx || !cpu_has_osxsave) { + pr_info("AVX instructions are not detected.\n"); + return -ENODEV; + } + + xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); + if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) { + pr_info("AVX detected but unusable.\n"); + return -ENODEV; + } + + return crypto_register_algs(cast5_algs, ARRAY_SIZE(cast5_algs)); +} + +static void __exit cast5_exit(void) +{ + crypto_unregister_algs(cast5_algs, ARRAY_SIZE(cast5_algs)); +} + +module_init(cast5_init); +module_exit(cast5_exit); + +MODULE_DESCRIPTION("Cast5 Cipher Algorithm, AVX optimized"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("cast5"); diff --git a/crypto/Kconfig b/crypto/Kconfig index a3238051b03e..cda97fcaa822 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -692,6 +692,20 @@ config CRYPTO_CAST5 The CAST5 encryption algorithm (synonymous with CAST-128) is described in RFC2144. +config CRYPTO_CAST5_AVX_X86_64 + tristate "CAST5 (CAST-128) cipher algorithm (x86_64/AVX)" + depends on X86 && 64BIT + select CRYPTO_ALGAPI + select CRYPTO_CRYPTD + select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_CAST5 + help + The CAST5 encryption algorithm (synonymous with CAST-128) is + described in RFC2144. + + This module provides the Cast5 cipher algorithm that processes + sixteen blocks parallel using the AVX instruction set. + config CRYPTO_CAST6 tristate "CAST6 (CAST-256) cipher algorithm" select CRYPTO_ALGAPI diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 7a91e540563f..def0f430b667 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1534,6 +1534,21 @@ static int alg_test_null(const struct alg_test_desc *desc, /* Please keep this list sorted by algorithm name. */ static const struct alg_test_desc alg_test_descs[] = { { + .alg = "__cbc-cast5-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { .alg = "__cbc-serpent-avx", .test = alg_test_null, .suite = { @@ -1594,6 +1609,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "__driver-cbc-cast5-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } }, { .alg = "__driver-cbc-serpent-avx", .test = alg_test_null, @@ -1655,6 +1685,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "__driver-ecb-cast5-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } }, { .alg = "__driver-ecb-serpent-avx", .test = alg_test_null, @@ -1951,6 +1996,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "cryptd(__driver-ecb-cast5-avx)", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } }, { .alg = "cryptd(__driver-ecb-serpent-avx)", .test = alg_test_null, From 2b49b906729644dd4696b9291b7e2f6cd1266dc0 Mon Sep 17 00:00:00 2001 From: Johannes Goetzfried Date: Wed, 11 Jul 2012 19:38:12 +0200 Subject: [PATCH 0170/5375] crypto: cast6 - prepare generic module for optimized implementations Rename cast6 module to cast6_generic to allow autoloading of optimized implementations. Generic functions and s-boxes are exported to be able to use them within optimized implementations. Signed-off-by: Johannes Goetzfried Signed-off-by: Herbert Xu --- crypto/Makefile | 2 +- crypto/{cast6.c => cast6_generic.c} | 66 +++++++++++++++++++---------- include/crypto/cast6.h | 23 ++++++++++ 3 files changed, 67 insertions(+), 24 deletions(-) rename crypto/{cast6.c => cast6_generic.c} (94%) create mode 100644 include/crypto/cast6.h diff --git a/crypto/Makefile b/crypto/Makefile index a56821e5d573..396966d2d849 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -69,7 +69,7 @@ obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o obj-$(CONFIG_CRYPTO_AES) += aes_generic.o obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o obj-$(CONFIG_CRYPTO_CAST5) += cast5_generic.o -obj-$(CONFIG_CRYPTO_CAST6) += cast6.o +obj-$(CONFIG_CRYPTO_CAST6) += cast6_generic.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o obj-$(CONFIG_CRYPTO_TEA) += tea.o obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o diff --git a/crypto/cast6.c b/crypto/cast6_generic.c similarity index 94% rename from crypto/cast6.c rename to crypto/cast6_generic.c index 04264f574601..dc9309d70405 100644 --- a/crypto/cast6.c +++ b/crypto/cast6_generic.c @@ -25,24 +25,21 @@ #include #include #include +#include -#define CAST6_BLOCK_SIZE 16 -#define CAST6_MIN_KEY_SIZE 16 -#define CAST6_MAX_KEY_SIZE 32 - -struct cast6_ctx { - u32 Km[12][4]; - u8 Kr[12][4]; -}; +#define s1 cast6_s1 +#define s2 cast6_s2 +#define s3 cast6_s3 +#define s4 cast6_s4 #define F1(D, r, m) ((I = ((m) + (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff])) + (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff])) #define F2(D, r, m) ((I = ((m) ^ (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff])) + (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff])) #define F3(D, r, m) ((I = ((m) - (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff])) + (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff])) -static const u32 s1[256] = { +const u32 cast6_s1[256] = { 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, @@ -108,8 +105,9 @@ static const u32 s1[256] = { 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf }; +EXPORT_SYMBOL_GPL(cast6_s1); -static const u32 s2[256] = { +const u32 cast6_s2[256] = { 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, @@ -175,8 +173,9 @@ static const u32 s2[256] = { 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 }; +EXPORT_SYMBOL_GPL(cast6_s2); -static const u32 s3[256] = { +const u32 cast6_s3[256] = { 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, @@ -242,8 +241,9 @@ static const u32 s3[256] = { 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 }; +EXPORT_SYMBOL_GPL(cast6_s3); -static const u32 s4[256] = { +const u32 cast6_s4[256] = { 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, @@ -309,6 +309,7 @@ static const u32 s4[256] = { 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 }; +EXPORT_SYMBOL_GPL(cast6_s4); static const u32 Tm[24][8] = { { 0x5a827999, 0xc95c653a, 0x383650db, 0xa7103c7c, 0x15ea281d, @@ -382,14 +383,12 @@ static void W(u32 *key, unsigned int i) key[7] ^= F2(key[0], Tr[i % 4][7], Tm[i][7]); } -static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key, - unsigned key_len) +int __cast6_setkey(struct cast6_ctx *c, const u8 *in_key, + unsigned key_len, u32 *flags) { int i; u32 key[8]; __be32 p_key[8]; /* padded key */ - struct cast6_ctx *c = crypto_tfm_ctx(tfm); - u32 *flags = &tfm->crt_flags; if (key_len % 4 != 0) { *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; @@ -425,6 +424,14 @@ static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key, return 0; } +EXPORT_SYMBOL_GPL(__cast6_setkey); + +int cast6_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +{ + return __cast6_setkey(crypto_tfm_ctx(tfm), key, keylen, + &tfm->crt_flags); +} +EXPORT_SYMBOL_GPL(cast6_setkey); /*forward quad round*/ static void Q(u32 *block, u8 *Kr, u32 *Km) @@ -446,9 +453,8 @@ static void QBAR(u32 *block, u8 *Kr, u32 *Km) block[2] ^= F1(block[3], Kr[0], Km[0]); } -static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +void __cast6_encrypt(struct cast6_ctx *c, u8 *outbuf, const u8 *inbuf) { - struct cast6_ctx *c = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)inbuf; __be32 *dst = (__be32 *)outbuf; u32 block[4]; @@ -478,10 +484,15 @@ static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) dst[2] = cpu_to_be32(block[2]); dst[3] = cpu_to_be32(block[3]); } +EXPORT_SYMBOL_GPL(__cast6_encrypt); -static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +{ + __cast6_encrypt(crypto_tfm_ctx(tfm), outbuf, inbuf); +} + +void __cast6_decrypt(struct cast6_ctx *c, u8 *outbuf, const u8 *inbuf) { - struct cast6_ctx *c = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)inbuf; __be32 *dst = (__be32 *)outbuf; u32 block[4]; @@ -511,9 +522,17 @@ static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) dst[2] = cpu_to_be32(block[2]); dst[3] = cpu_to_be32(block[3]); } +EXPORT_SYMBOL_GPL(__cast6_decrypt); + +static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +{ + __cast6_decrypt(crypto_tfm_ctx(tfm), outbuf, inbuf); +} static struct crypto_alg alg = { .cra_name = "cast6", + .cra_driver_name = "cast6-generic", + .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = CAST6_BLOCK_SIZE, .cra_ctxsize = sizeof(struct cast6_ctx), @@ -544,3 +563,4 @@ module_exit(cast6_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cast6 Cipher Algorithm"); +MODULE_ALIAS("cast6"); diff --git a/include/crypto/cast6.h b/include/crypto/cast6.h new file mode 100644 index 000000000000..02dde6b77e15 --- /dev/null +++ b/include/crypto/cast6.h @@ -0,0 +1,23 @@ +#ifndef _CRYPTO_CAST6_H +#define _CRYPTO_CAST6_H + +#include +#include + +#define CAST6_BLOCK_SIZE 16 +#define CAST6_MIN_KEY_SIZE 16 +#define CAST6_MAX_KEY_SIZE 32 + +struct cast6_ctx { + u32 Km[12][4]; + u8 Kr[12][4]; +}; + +int __cast6_setkey(struct cast6_ctx *ctx, const u8 *key, + unsigned int keylen, u32 *flags); +int cast6_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen); + +void __cast6_encrypt(struct cast6_ctx *ctx, u8 *dst, const u8 *src); +void __cast6_decrypt(struct cast6_ctx *ctx, u8 *dst, const u8 *src); + +#endif From 9b8b04051d0df1e2c7c31206caff05673a2c685f Mon Sep 17 00:00:00 2001 From: Johannes Goetzfried Date: Wed, 11 Jul 2012 19:38:29 +0200 Subject: [PATCH 0171/5375] crypto: testmgr - add larger cast6 testvectors New ECB, CBC, CTR, LRW and XTS testvectors for cast6. We need larger testvectors to check parallel code paths in the optimized implementation. Tests have also been added to the tcrypt module. Signed-off-by: Johannes Goetzfried Signed-off-by: Herbert Xu --- crypto/tcrypt.c | 50 ++ crypto/testmgr.c | 60 ++ crypto/testmgr.h | 1412 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 1520 insertions(+), 2 deletions(-) diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index a94bbd77dc60..871076b1e0ab 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1043,6 +1043,10 @@ static int do_test(int m) case 15: ret += tcrypt_test("ecb(cast6)"); + ret += tcrypt_test("cbc(cast6)"); + ret += tcrypt_test("ctr(cast6)"); + ret += tcrypt_test("lrw(cast6)"); + ret += tcrypt_test("xts(cast6)"); break; case 16: @@ -1376,6 +1380,29 @@ static int do_test(int m) speed_template_8_16); break; + case 210: + test_cipher_speed("ecb(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("ecb(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("cbc(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("cbc(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("ctr(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("ctr(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("lrw(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_32_48); + test_cipher_speed("lrw(cast6)", DECRYPT, sec, NULL, 0, + speed_template_32_48); + test_cipher_speed("xts(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_32_64); + test_cipher_speed("xts(cast6)", DECRYPT, sec, NULL, 0, + speed_template_32_64); + break; + case 300: /* fall through */ @@ -1671,6 +1698,29 @@ static int do_test(int m) speed_template_8_16); break; + case 507: + test_acipher_speed("ecb(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("ecb(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("cbc(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("cbc(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("ctr(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("ctr(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("lrw(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_32_48); + test_acipher_speed("lrw(cast6)", DECRYPT, sec, NULL, 0, + speed_template_32_48); + test_acipher_speed("xts(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_32_64); + test_acipher_speed("xts(cast6)", DECRYPT, sec, NULL, 0, + speed_template_32_64); + break; + case 1000: test_available(); break; diff --git a/crypto/testmgr.c b/crypto/testmgr.c index def0f430b667..cff3c1c3f83c 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1877,6 +1877,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "cbc(cast6)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast6_cbc_enc_tv_template, + .count = CAST6_CBC_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast6_cbc_dec_tv_template, + .count = CAST6_CBC_DEC_TEST_VECTORS + } + } + } }, { .alg = "cbc(des)", .test = alg_test_skcipher, @@ -2143,6 +2158,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "ctr(cast6)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast6_ctr_enc_tv_template, + .count = CAST6_CTR_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast6_ctr_dec_tv_template, + .count = CAST6_CTR_DEC_TEST_VECTORS + } + } + } }, { .alg = "ctr(serpent)", .test = alg_test_skcipher, @@ -2619,6 +2649,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "lrw(cast6)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast6_lrw_enc_tv_template, + .count = CAST6_LRW_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast6_lrw_dec_tv_template, + .count = CAST6_LRW_DEC_TEST_VECTORS + } + } + } }, { .alg = "lrw(serpent)", .test = alg_test_skcipher, @@ -2971,6 +3016,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "xts(cast6)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast6_xts_enc_tv_template, + .count = CAST6_XTS_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast6_xts_dec_tv_template, + .count = CAST6_XTS_DEC_TEST_VECTORS + } + } + } }, { .alg = "xts(serpent)", .test = alg_test_skcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 9309948a7028..6eb3ef5e3f88 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -6896,8 +6896,16 @@ static struct cipher_testvec serpent_xts_dec_tv_template[] = { }; /* Cast6 test vectors from RFC 2612 */ -#define CAST6_ENC_TEST_VECTORS 3 -#define CAST6_DEC_TEST_VECTORS 3 +#define CAST6_ENC_TEST_VECTORS 4 +#define CAST6_DEC_TEST_VECTORS 4 +#define CAST6_CBC_ENC_TEST_VECTORS 1 +#define CAST6_CBC_DEC_TEST_VECTORS 1 +#define CAST6_CTR_ENC_TEST_VECTORS 1 +#define CAST6_CTR_DEC_TEST_VECTORS 1 +#define CAST6_LRW_ENC_TEST_VECTORS 1 +#define CAST6_LRW_DEC_TEST_VECTORS 1 +#define CAST6_XTS_ENC_TEST_VECTORS 1 +#define CAST6_XTS_DEC_TEST_VECTORS 1 static struct cipher_testvec cast6_enc_tv_template[] = { { @@ -6930,6 +6938,140 @@ static struct cipher_testvec cast6_enc_tv_template[] = { .result = "\x4f\x6a\x20\x38\x28\x68\x97\xb9" "\xc9\x87\x01\x36\x55\x33\x17\xfa", .rlen = 16, + }, { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\xC3\x70\x22\x32\xF5\x80\xCB\x54" + "\xFC\x30\xE0\xF6\xEB\x39\x57\xA6" + "\xB6\xB9\xC5\xA4\x91\x55\x14\x97" + "\xC1\x20\xFF\x6C\x5C\xF0\x67\xEA" + "\x2F\xED\xD8\xC9\xFB\x38\x3F\xFE" + "\x93\xBE\xDC\x00\xD3\x7F\xAD\x4C" + "\x5A\x08\x92\xD1\x47\x0C\xFA\x6C" + "\xD0\x6A\x99\x10\x72\xF8\x47\x62" + "\x81\x42\xF8\xD8\xF5\xBB\x94\x08" + "\xAA\x97\xA2\x8B\x69\xB3\xD2\x7E" + "\xBC\xB5\x00\x0C\xE5\x44\x4B\x58" + "\xE8\x63\xDC\xB3\xC4\xE5\x23\x12" + "\x5A\x72\x85\x47\x8B\xEC\x9F\x26" + "\x84\xB6\xED\x10\x33\x63\x9B\x5F" + "\x4D\x53\xEE\x94\x45\x8B\x60\x58" + "\x86\x20\xF9\x1E\x82\x08\x3E\x58" + "\x60\x1B\x34\x19\x02\xBE\x4E\x09" + "\xBB\x7C\x15\xCC\x60\x27\x55\x7A" + "\x12\xB8\xD8\x08\x89\x3C\xA6\xF3" + "\xF1\xDD\xA7\x07\xA3\x12\x85\x28" + "\xE9\x57\xAC\x80\x0C\x5C\x0F\x3A" + "\x5D\xC2\x91\xC7\x90\xE4\x8C\x43" + "\x92\xE4\x7C\x26\x69\x4D\x83\x68" + "\x14\x96\x42\x47\xBD\xA9\xE4\x8A" + "\x33\x19\xEB\x54\x8E\x0D\x4B\x6E" + "\x91\x51\xB5\x36\x08\xDE\x1C\x06" + "\x03\xBD\xDE\x81\x26\xF7\x99\xC2" + "\xBA\xF7\x6D\x87\x0D\xE4\xA6\xCF" + "\xC1\xF5\x27\x05\xB8\x02\x57\x72" + "\xE6\x42\x13\x0B\xC6\x47\x05\x74" + "\x24\x15\xF7\x0D\xC2\x23\x9D\xB9" + "\x3C\x77\x18\x93\xBA\xB4\xFC\x8C" + "\x98\x82\x67\x67\xB4\xD7\xD3\x43" + "\x23\x08\x02\xB7\x9B\x99\x05\xFB" + "\xD3\xB5\x00\x0A\xA9\x9D\x66\xD6" + "\x2E\x49\x58\xD0\xA8\x57\x29\x7F" + "\x0A\x0E\x7D\xFC\x92\x83\xCC\x67" + "\xA2\xB1\x70\x3A\x8F\x87\x4A\x8D" + "\x17\xE2\x58\x2B\x88\x0D\x68\x62" + "\xBF\x35\xD1\x6F\xC0\xF0\x18\x62" + "\xB2\xC7\x2D\x58\xC7\x16\xDE\x08" + "\xEB\x84\x1D\x25\xA7\x38\x94\x06" + "\x93\x9D\xF8\xFE\x88\x71\xE7\x84" + "\x2C\xA0\x38\xA3\x1D\x48\xCF\x29" + "\x0B\xBC\xD8\x50\x99\x1A\x26\xFB" + "\x8E\x75\x3D\x73\xEB\x6A\xED\x29" + "\xE0\x8E\xED\xFC\xFE\x6F\xF6\xBA" + "\x41\xE2\x10\x4C\x01\x8B\x69\x2B" + "\x25\x3F\x4D\x70\x7B\x92\xD6\x3B" + "\xAC\xF9\x77\x18\xD9\x6A\x30\xA6" + "\x2E\xFA\x30\xFF\xC8\xD5\x1D\x06" + "\x59\x28\x1D\x86\x43\x04\x5D\x3B" + "\x99\x4C\x04\x5A\x21\x17\x8B\x76" + "\x8F\x72\xCB\xA1\x9C\x29\x4C\xC3" + "\x65\xA2\x58\x2A\xC5\x66\x24\xBF" + "\xBA\xE6\x0C\xDD\x34\x24\x74\xC8" + "\x84\x0A\x66\x2C\xBE\x8F\x32\xA9" + "\xE7\xE4\xA1\xD7\xDA\xAB\x23\x1E" + "\xEB\xEE\x6C\x94\x6F\x9C\x2E\xD1" + "\x49\x2C\xF3\xD4\x90\xCC\x93\x4C" + "\x84\x52\x6D\x68\xDE\xC6\x64\xB2" + "\x11\x74\x93\x57\xB4\x7E\xC6\x00", + .rlen = 496, }, }; @@ -6964,6 +7106,1272 @@ static struct cipher_testvec cast6_dec_tv_template[] = { .ilen = 16, .result = zeroed_string, .rlen = 16, + }, { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\xC3\x70\x22\x32\xF5\x80\xCB\x54" + "\xFC\x30\xE0\xF6\xEB\x39\x57\xA6" + "\xB6\xB9\xC5\xA4\x91\x55\x14\x97" + "\xC1\x20\xFF\x6C\x5C\xF0\x67\xEA" + "\x2F\xED\xD8\xC9\xFB\x38\x3F\xFE" + "\x93\xBE\xDC\x00\xD3\x7F\xAD\x4C" + "\x5A\x08\x92\xD1\x47\x0C\xFA\x6C" + "\xD0\x6A\x99\x10\x72\xF8\x47\x62" + "\x81\x42\xF8\xD8\xF5\xBB\x94\x08" + "\xAA\x97\xA2\x8B\x69\xB3\xD2\x7E" + "\xBC\xB5\x00\x0C\xE5\x44\x4B\x58" + "\xE8\x63\xDC\xB3\xC4\xE5\x23\x12" + "\x5A\x72\x85\x47\x8B\xEC\x9F\x26" + "\x84\xB6\xED\x10\x33\x63\x9B\x5F" + "\x4D\x53\xEE\x94\x45\x8B\x60\x58" + "\x86\x20\xF9\x1E\x82\x08\x3E\x58" + "\x60\x1B\x34\x19\x02\xBE\x4E\x09" + "\xBB\x7C\x15\xCC\x60\x27\x55\x7A" + "\x12\xB8\xD8\x08\x89\x3C\xA6\xF3" + "\xF1\xDD\xA7\x07\xA3\x12\x85\x28" + "\xE9\x57\xAC\x80\x0C\x5C\x0F\x3A" + "\x5D\xC2\x91\xC7\x90\xE4\x8C\x43" + "\x92\xE4\x7C\x26\x69\x4D\x83\x68" + "\x14\x96\x42\x47\xBD\xA9\xE4\x8A" + "\x33\x19\xEB\x54\x8E\x0D\x4B\x6E" + "\x91\x51\xB5\x36\x08\xDE\x1C\x06" + "\x03\xBD\xDE\x81\x26\xF7\x99\xC2" + "\xBA\xF7\x6D\x87\x0D\xE4\xA6\xCF" + "\xC1\xF5\x27\x05\xB8\x02\x57\x72" + "\xE6\x42\x13\x0B\xC6\x47\x05\x74" + "\x24\x15\xF7\x0D\xC2\x23\x9D\xB9" + "\x3C\x77\x18\x93\xBA\xB4\xFC\x8C" + "\x98\x82\x67\x67\xB4\xD7\xD3\x43" + "\x23\x08\x02\xB7\x9B\x99\x05\xFB" + "\xD3\xB5\x00\x0A\xA9\x9D\x66\xD6" + "\x2E\x49\x58\xD0\xA8\x57\x29\x7F" + "\x0A\x0E\x7D\xFC\x92\x83\xCC\x67" + "\xA2\xB1\x70\x3A\x8F\x87\x4A\x8D" + "\x17\xE2\x58\x2B\x88\x0D\x68\x62" + "\xBF\x35\xD1\x6F\xC0\xF0\x18\x62" + "\xB2\xC7\x2D\x58\xC7\x16\xDE\x08" + "\xEB\x84\x1D\x25\xA7\x38\x94\x06" + "\x93\x9D\xF8\xFE\x88\x71\xE7\x84" + "\x2C\xA0\x38\xA3\x1D\x48\xCF\x29" + "\x0B\xBC\xD8\x50\x99\x1A\x26\xFB" + "\x8E\x75\x3D\x73\xEB\x6A\xED\x29" + "\xE0\x8E\xED\xFC\xFE\x6F\xF6\xBA" + "\x41\xE2\x10\x4C\x01\x8B\x69\x2B" + "\x25\x3F\x4D\x70\x7B\x92\xD6\x3B" + "\xAC\xF9\x77\x18\xD9\x6A\x30\xA6" + "\x2E\xFA\x30\xFF\xC8\xD5\x1D\x06" + "\x59\x28\x1D\x86\x43\x04\x5D\x3B" + "\x99\x4C\x04\x5A\x21\x17\x8B\x76" + "\x8F\x72\xCB\xA1\x9C\x29\x4C\xC3" + "\x65\xA2\x58\x2A\xC5\x66\x24\xBF" + "\xBA\xE6\x0C\xDD\x34\x24\x74\xC8" + "\x84\x0A\x66\x2C\xBE\x8F\x32\xA9" + "\xE7\xE4\xA1\xD7\xDA\xAB\x23\x1E" + "\xEB\xEE\x6C\x94\x6F\x9C\x2E\xD1" + "\x49\x2C\xF3\xD4\x90\xCC\x93\x4C" + "\x84\x52\x6D\x68\xDE\xC6\x64\xB2" + "\x11\x74\x93\x57\xB4\x7E\xC6\x00", + .ilen = 496, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + }, +}; + +static struct cipher_testvec cast6_cbc_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\xDF\x77\x68\x96\xC7\xBA\xF8\xE2" + "\x0E\x24\x99\x1A\xAA\xF3\xC6\x9F" + "\xA0\x73\xB3\x70\xC3\x68\x64\x70" + "\xAD\x33\x02\xFB\x88\x74\xAA\x78" + "\xC7\x47\x1A\x18\x61\x2D\xAC\x9F" + "\x7E\x6F\xDF\x05\x13\x76\xA6\x72" + "\xB7\x13\x09\x0F\x7D\x38\xDF\x25" + "\x4E\xFD\x50\x45\xFA\x35\x6A\xC0" + "\x57\x95\xE1\x21\x26\x10\x9A\x21" + "\xA1\x8A\x51\x05\xD1\xB1\x78\x35" + "\x98\xF5\xAE\xC0\xC1\x8B\x94\xFF" + "\xD0\x69\x3F\x42\xC2\x01\xA7\x9B" + "\x23\x16\x47\x72\x81\x13\x3A\x72" + "\xEC\xD9\x40\x88\x00\x9C\xB0\xA8" + "\x9C\xAC\xCE\x11\x73\x7B\x63\x3E" + "\xA3\x63\x98\x7D\x35\xE4\xD9\x83" + "\xE2\xD0\x52\x87\x0C\x1F\xB0\xB3" + "\x41\x1A\x93\x8D\x76\x31\x9F\xF2" + "\xFE\x09\xA3\x8F\x22\x6A\x3B\xB9" + "\x6C\x9E\xE4\xA1\xA0\xC4\xE7\xA1" + "\x21\x9C\x1A\xCA\x65\xDE\x44\x03" + "\x99\xF2\xD2\x39\xE3\x3F\x0F\x37" + "\x53\x50\x23\xA4\x81\x6E\xDA\xFB" + "\xF8\x7B\x01\xD7\xB2\x32\x9C\xB8" + "\xB1\x0E\x99\x17\xB5\x38\xF9\xD7" + "\x86\x2D\x6E\x94\x5C\x99\x9D\xB3" + "\xD3\x63\x4B\x2A\x7D\x44\x6A\xB2" + "\xC1\x03\xE6\x5A\x37\xD8\x64\x18" + "\xAA\x32\xCE\x29\xED\xC0\xA2\xCB" + "\x8D\xAF\xCD\xBE\x8F\xB6\xEC\xB4" + "\x89\x05\x81\x6E\x71\x4F\xC3\x28" + "\x10\xC1\x62\xC4\x41\xE9\xD2\x39" + "\xF3\x22\x39\x12\x2C\xC2\x95\x2D" + "\xBF\x93\x58\x4B\x04\xD1\x8D\x57" + "\xAE\xEB\x60\x03\x56\x35\xAD\x5A" + "\xE9\xC3\xFF\x4E\x31\xE1\x37\xF8" + "\x7D\xEE\x65\x8A\xB6\x88\x1A\x3E" + "\x07\x09\x82\xBA\xF0\x80\x8A\xD0" + "\xA0\x3F\x6A\xE9\x24\x87\x19\x65" + "\x73\x3F\x12\x91\x47\x54\xBA\x39" + "\x30\x5B\x1E\xE5\xC2\xF9\x3F\xEF" + "\xD6\x75\xF9\xB8\x7C\x8B\x05\x76" + "\xEE\xB7\x08\x25\x4B\xB6\x7B\x47" + "\x72\xC0\x4C\xD4\xDA\xE0\x75\xF1" + "\x7C\xE8\x94\x9E\x16\x6E\xB8\x12" + "\xA1\xC1\x6E\x3B\x1C\x59\x41\x2D" + "\x23\xFA\x7D\x77\xB8\x46\x75\xFE" + "\x4F\x10\xD3\x09\x60\xA1\x36\x96" + "\x5B\xC2\xDC\x6E\x84\x7D\x9B\x14" + "\x80\x21\x83\x58\x3C\x76\xFD\x28" + "\x1D\xF9\x93\x13\xD7\x0E\x62\x14" + "\x5A\xC5\x4E\x08\xA5\x56\xA4\x3C" + "\x68\x93\x44\x70\xDF\xCF\x4A\x51" + "\x0B\x81\x29\x41\xE5\x62\x4D\x36" + "\xB3\xEA\x94\xA6\xB9\xDD\x3F\x09" + "\x62\x34\xA0\x6A\x7E\x7D\xF5\xF6" + "\x01\x91\xB4\x27\xDA\x59\xD6\x17" + "\x56\x4D\x82\x62\x37\xA3\x48\x01" + "\x99\x91\x77\xB2\x08\x6B\x2C\x37" + "\xC5\x5C\xAD\xB6\x07\xB6\x84\xF3" + "\x4D\x59\x7D\xC5\x28\x69\xFA\x92" + "\x22\x46\x89\x2D\x0F\x2B\x08\x24", + .rlen = 496, + }, +}; + +static struct cipher_testvec cast6_cbc_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\xDF\x77\x68\x96\xC7\xBA\xF8\xE2" + "\x0E\x24\x99\x1A\xAA\xF3\xC6\x9F" + "\xA0\x73\xB3\x70\xC3\x68\x64\x70" + "\xAD\x33\x02\xFB\x88\x74\xAA\x78" + "\xC7\x47\x1A\x18\x61\x2D\xAC\x9F" + "\x7E\x6F\xDF\x05\x13\x76\xA6\x72" + "\xB7\x13\x09\x0F\x7D\x38\xDF\x25" + "\x4E\xFD\x50\x45\xFA\x35\x6A\xC0" + "\x57\x95\xE1\x21\x26\x10\x9A\x21" + "\xA1\x8A\x51\x05\xD1\xB1\x78\x35" + "\x98\xF5\xAE\xC0\xC1\x8B\x94\xFF" + "\xD0\x69\x3F\x42\xC2\x01\xA7\x9B" + "\x23\x16\x47\x72\x81\x13\x3A\x72" + "\xEC\xD9\x40\x88\x00\x9C\xB0\xA8" + "\x9C\xAC\xCE\x11\x73\x7B\x63\x3E" + "\xA3\x63\x98\x7D\x35\xE4\xD9\x83" + "\xE2\xD0\x52\x87\x0C\x1F\xB0\xB3" + "\x41\x1A\x93\x8D\x76\x31\x9F\xF2" + "\xFE\x09\xA3\x8F\x22\x6A\x3B\xB9" + "\x6C\x9E\xE4\xA1\xA0\xC4\xE7\xA1" + "\x21\x9C\x1A\xCA\x65\xDE\x44\x03" + "\x99\xF2\xD2\x39\xE3\x3F\x0F\x37" + "\x53\x50\x23\xA4\x81\x6E\xDA\xFB" + "\xF8\x7B\x01\xD7\xB2\x32\x9C\xB8" + "\xB1\x0E\x99\x17\xB5\x38\xF9\xD7" + "\x86\x2D\x6E\x94\x5C\x99\x9D\xB3" + "\xD3\x63\x4B\x2A\x7D\x44\x6A\xB2" + "\xC1\x03\xE6\x5A\x37\xD8\x64\x18" + "\xAA\x32\xCE\x29\xED\xC0\xA2\xCB" + "\x8D\xAF\xCD\xBE\x8F\xB6\xEC\xB4" + "\x89\x05\x81\x6E\x71\x4F\xC3\x28" + "\x10\xC1\x62\xC4\x41\xE9\xD2\x39" + "\xF3\x22\x39\x12\x2C\xC2\x95\x2D" + "\xBF\x93\x58\x4B\x04\xD1\x8D\x57" + "\xAE\xEB\x60\x03\x56\x35\xAD\x5A" + "\xE9\xC3\xFF\x4E\x31\xE1\x37\xF8" + "\x7D\xEE\x65\x8A\xB6\x88\x1A\x3E" + "\x07\x09\x82\xBA\xF0\x80\x8A\xD0" + "\xA0\x3F\x6A\xE9\x24\x87\x19\x65" + "\x73\x3F\x12\x91\x47\x54\xBA\x39" + "\x30\x5B\x1E\xE5\xC2\xF9\x3F\xEF" + "\xD6\x75\xF9\xB8\x7C\x8B\x05\x76" + "\xEE\xB7\x08\x25\x4B\xB6\x7B\x47" + "\x72\xC0\x4C\xD4\xDA\xE0\x75\xF1" + "\x7C\xE8\x94\x9E\x16\x6E\xB8\x12" + "\xA1\xC1\x6E\x3B\x1C\x59\x41\x2D" + "\x23\xFA\x7D\x77\xB8\x46\x75\xFE" + "\x4F\x10\xD3\x09\x60\xA1\x36\x96" + "\x5B\xC2\xDC\x6E\x84\x7D\x9B\x14" + "\x80\x21\x83\x58\x3C\x76\xFD\x28" + "\x1D\xF9\x93\x13\xD7\x0E\x62\x14" + "\x5A\xC5\x4E\x08\xA5\x56\xA4\x3C" + "\x68\x93\x44\x70\xDF\xCF\x4A\x51" + "\x0B\x81\x29\x41\xE5\x62\x4D\x36" + "\xB3\xEA\x94\xA6\xB9\xDD\x3F\x09" + "\x62\x34\xA0\x6A\x7E\x7D\xF5\xF6" + "\x01\x91\xB4\x27\xDA\x59\xD6\x17" + "\x56\x4D\x82\x62\x37\xA3\x48\x01" + "\x99\x91\x77\xB2\x08\x6B\x2C\x37" + "\xC5\x5C\xAD\xB6\x07\xB6\x84\xF3" + "\x4D\x59\x7D\xC5\x28\x69\xFA\x92" + "\x22\x46\x89\x2D\x0F\x2B\x08\x24", + .ilen = 496, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + }, +}; + +static struct cipher_testvec cast6_ctr_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\x26\x0A\xF1\xE2\x3F\x8A\xEF\xA3" + "\x53\x9A\x5E\x1B\x2A\x1A\xC6\x0A" + "\x57\xA3\xEF\x47\x2A\xE8\x88\xA7" + "\x3C\xD0\xEC\xB9\x94\x50\x7D\x56" + "\xBC\xE1\xC1\xF5\xE1\xEE\x12\xF8" + "\x4F\x03\x82\x3A\x93\x6B\x4C\xD3" + "\xE3\xF3\xFA\xC2\x23\x55\x98\x20" + "\x49\x76\x9B\x6B\xC1\x23\xBF\xE5" + "\xD4\xC4\x2F\x61\xE1\x67\x2A\x30" + "\x6F\x29\xCA\x54\xF8\x1B\xA6\x7D" + "\x66\x45\xEE\xC8\x19\xBE\x50\xF0" + "\x5F\x65\xF8\x1E\x4D\x07\x87\xD9" + "\xD3\xD9\x1B\x09\x89\xFD\x42\xC5" + "\xDB\xEB\x86\xF1\x67\x04\x0F\x5C" + "\x81\xDF\x82\x12\xC7\x4C\x1B\x07" + "\xDE\xE6\xFA\x29\x86\xD1\xB0\xBA" + "\x3D\x6A\x69\x76\xEC\x0F\xB4\xE6" + "\xCD\xA7\xF8\xA8\xB8\xE0\x33\xF5" + "\x49\x61\x22\x52\x64\x8C\x46\x41" + "\x1F\x48\x5F\x4F\xA2\x89\x36\x17" + "\x20\xF8\x2F\x8F\x4B\xFA\xF2\xC0" + "\x1E\x18\xA2\xF8\xB7\x6D\x98\xE3" + "\x00\x14\x15\x59\xC1\x30\x64\xAF" + "\xA8\x01\x38\xAB\xD4\x8B\xEC\x7C" + "\x44\x9A\xC6\x2C\x2E\x2B\x2B\xF4" + "\x02\x37\xC4\x69\xEF\x36\xC1\xF3" + "\xA0\xFB\xFE\x29\xAD\x39\xCF\xD0" + "\x51\x73\xA3\x22\x42\x41\xAB\xD2" + "\x0F\x50\x14\xB9\x54\xD3\xD4\xFA" + "\xBF\xC9\xBB\xCE\xC4\x1D\x2D\xAF" + "\xC9\x3F\x07\x87\x42\x4B\x3A\x54" + "\x34\x8E\x37\xA3\x03\x6F\x65\x66" + "\xDB\x44\xC3\xE8\xD7\xDD\x7D\xDD" + "\x61\xB4\x2B\x80\xA3\x98\x13\xF5" + "\x5A\xD3\x34\x58\xC3\x6E\xF6\xB8" + "\x0A\xC6\x50\x01\x8E\xD5\x6C\x7D" + "\xFE\x16\xB6\xCF\xFC\x51\x40\xAE" + "\xB3\x15\xAC\x90\x6F\x0B\x28\x3A" + "\x60\x40\x38\x90\x20\x46\xC7\xB3" + "\x0B\x12\x6D\x3B\x15\x14\xF9\xF4" + "\x11\x41\x76\x6B\xB3\x60\x82\x3C" + "\x84\xFB\x08\x2E\x92\x25\xCB\x79" + "\x6F\x58\xC5\x94\x00\x00\x47\xB6" + "\x9E\xDC\x0F\x29\x70\x46\x20\x76" + "\x65\x75\x66\x5C\x00\x96\xB3\xE1" + "\x0B\xA7\x11\x8B\x2E\x61\x4E\x45" + "\x73\xFC\x91\xAB\x79\x41\x23\x14" + "\x13\xB6\x72\x6C\x46\xB3\x03\x11" + "\xE4\xF1\xEE\xC9\x7A\xCF\x96\x32" + "\xB6\xF0\x8B\x97\xB4\xCF\x82\xB7" + "\x15\x48\x44\x99\x09\xF6\xE0\xD7" + "\xBC\xF1\x5B\x91\x4F\x30\x22\xA2" + "\x45\xC4\x68\x55\xC2\xBE\xA7\xD2" + "\x12\x53\x35\x9C\xF9\xE7\x35\x5D" + "\x81\xE4\x86\x42\xC3\x58\xFB\xF0" + "\x38\x9B\x8E\x5A\xEF\x83\x33\x0F" + "\x00\x4E\x3F\x9F\xF5\x84\x62\xC4" + "\x19\x35\x88\x22\x45\x59\x0E\x8F" + "\xEC\x27\xDD\x4A\xA4\x1F\xBC\x41" + "\x9B\x66\x8D\x32\xBA\x81\x34\x87" + "\x0E\x74\x33\x30\x62\xB9\x89\xDF" + "\xF9\xC5\xDD\x27\xB3\x39\xCB\xCB", + .rlen = 496, + }, +}; + +static struct cipher_testvec cast6_ctr_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\x26\x0A\xF1\xE2\x3F\x8A\xEF\xA3" + "\x53\x9A\x5E\x1B\x2A\x1A\xC6\x0A" + "\x57\xA3\xEF\x47\x2A\xE8\x88\xA7" + "\x3C\xD0\xEC\xB9\x94\x50\x7D\x56" + "\xBC\xE1\xC1\xF5\xE1\xEE\x12\xF8" + "\x4F\x03\x82\x3A\x93\x6B\x4C\xD3" + "\xE3\xF3\xFA\xC2\x23\x55\x98\x20" + "\x49\x76\x9B\x6B\xC1\x23\xBF\xE5" + "\xD4\xC4\x2F\x61\xE1\x67\x2A\x30" + "\x6F\x29\xCA\x54\xF8\x1B\xA6\x7D" + "\x66\x45\xEE\xC8\x19\xBE\x50\xF0" + "\x5F\x65\xF8\x1E\x4D\x07\x87\xD9" + "\xD3\xD9\x1B\x09\x89\xFD\x42\xC5" + "\xDB\xEB\x86\xF1\x67\x04\x0F\x5C" + "\x81\xDF\x82\x12\xC7\x4C\x1B\x07" + "\xDE\xE6\xFA\x29\x86\xD1\xB0\xBA" + "\x3D\x6A\x69\x76\xEC\x0F\xB4\xE6" + "\xCD\xA7\xF8\xA8\xB8\xE0\x33\xF5" + "\x49\x61\x22\x52\x64\x8C\x46\x41" + "\x1F\x48\x5F\x4F\xA2\x89\x36\x17" + "\x20\xF8\x2F\x8F\x4B\xFA\xF2\xC0" + "\x1E\x18\xA2\xF8\xB7\x6D\x98\xE3" + "\x00\x14\x15\x59\xC1\x30\x64\xAF" + "\xA8\x01\x38\xAB\xD4\x8B\xEC\x7C" + "\x44\x9A\xC6\x2C\x2E\x2B\x2B\xF4" + "\x02\x37\xC4\x69\xEF\x36\xC1\xF3" + "\xA0\xFB\xFE\x29\xAD\x39\xCF\xD0" + "\x51\x73\xA3\x22\x42\x41\xAB\xD2" + "\x0F\x50\x14\xB9\x54\xD3\xD4\xFA" + "\xBF\xC9\xBB\xCE\xC4\x1D\x2D\xAF" + "\xC9\x3F\x07\x87\x42\x4B\x3A\x54" + "\x34\x8E\x37\xA3\x03\x6F\x65\x66" + "\xDB\x44\xC3\xE8\xD7\xDD\x7D\xDD" + "\x61\xB4\x2B\x80\xA3\x98\x13\xF5" + "\x5A\xD3\x34\x58\xC3\x6E\xF6\xB8" + "\x0A\xC6\x50\x01\x8E\xD5\x6C\x7D" + "\xFE\x16\xB6\xCF\xFC\x51\x40\xAE" + "\xB3\x15\xAC\x90\x6F\x0B\x28\x3A" + "\x60\x40\x38\x90\x20\x46\xC7\xB3" + "\x0B\x12\x6D\x3B\x15\x14\xF9\xF4" + "\x11\x41\x76\x6B\xB3\x60\x82\x3C" + "\x84\xFB\x08\x2E\x92\x25\xCB\x79" + "\x6F\x58\xC5\x94\x00\x00\x47\xB6" + "\x9E\xDC\x0F\x29\x70\x46\x20\x76" + "\x65\x75\x66\x5C\x00\x96\xB3\xE1" + "\x0B\xA7\x11\x8B\x2E\x61\x4E\x45" + "\x73\xFC\x91\xAB\x79\x41\x23\x14" + "\x13\xB6\x72\x6C\x46\xB3\x03\x11" + "\xE4\xF1\xEE\xC9\x7A\xCF\x96\x32" + "\xB6\xF0\x8B\x97\xB4\xCF\x82\xB7" + "\x15\x48\x44\x99\x09\xF6\xE0\xD7" + "\xBC\xF1\x5B\x91\x4F\x30\x22\xA2" + "\x45\xC4\x68\x55\xC2\xBE\xA7\xD2" + "\x12\x53\x35\x9C\xF9\xE7\x35\x5D" + "\x81\xE4\x86\x42\xC3\x58\xFB\xF0" + "\x38\x9B\x8E\x5A\xEF\x83\x33\x0F" + "\x00\x4E\x3F\x9F\xF5\x84\x62\xC4" + "\x19\x35\x88\x22\x45\x59\x0E\x8F" + "\xEC\x27\xDD\x4A\xA4\x1F\xBC\x41" + "\x9B\x66\x8D\x32\xBA\x81\x34\x87" + "\x0E\x74\x33\x30\x62\xB9\x89\xDF" + "\xF9\xC5\xDD\x27\xB3\x39\xCB\xCB", + .ilen = 496, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + }, +}; + +static struct cipher_testvec cast6_lrw_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" + "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" + "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21" + "\xa7\x9c\x21\xf8\xcb\x90\x02\x89" + "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1" + "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e", + .klen = 48, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x01", + .input = "\x05\x11\xb7\x18\xab\xc6\x2d\xac" + "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c" + "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8" + "\x50\x38\x1f\x71\x49\xb6\x57\xd6" + "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90" + "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6" + "\xad\x1e\x9e\x20\x5f\x38\xbe\x04" + "\xda\x10\x8e\xed\xa2\xa4\x87\xab" + "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c" + "\xc9\xac\x42\x31\x95\x7c\xc9\x04" + "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6" + "\x15\xd7\x3f\x4f\x2f\x66\x69\x03" + "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65" + "\x4c\x96\x12\xed\x7c\x92\x03\x01" + "\x6f\xbc\x35\x93\xac\xf1\x27\xf1" + "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50" + "\x89\xa4\x8e\x66\x44\x85\xcc\xfd" + "\x33\x14\x70\xe3\x96\xb2\xc3\xd3" + "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5" + "\x2d\x64\x75\xdd\xb4\x54\xe6\x74" + "\x8c\xd3\x9d\x9e\x86\xab\x51\x53" + "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40" + "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5" + "\x76\x12\x73\x44\x1a\x56\xd7\x72" + "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda" + "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd" + "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60" + "\x1a\xe2\x70\x85\x58\xc2\x1b\x09" + "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9" + "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8" + "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8" + "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10" + "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1" + "\x90\x3e\x76\x4a\x74\xa4\x21\x2c" + "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e" + "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f" + "\x8d\x23\x31\x74\x84\xeb\x88\x6e" + "\xcc\xb9\xbc\x22\x83\x19\x07\x22" + "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78" + "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5" + "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41" + "\x3c\xce\x8f\x42\x60\x71\xa7\x75" + "\x08\x40\x65\x8a\x82\xbf\xf5\x43" + "\x71\x96\xa9\x4d\x44\x8a\x20\xbe" + "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65" + "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9" + "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4" + "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a" + "\x62\x73\x65\xfd\x46\x63\x25\x3d" + "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf" + "\x24\xf3\xb4\xac\x64\xba\xdf\x4b" + "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7" + "\xc5\x68\x77\x84\x32\x2b\xcc\x85" + "\x74\x96\xf0\x12\x77\x61\xb9\xeb" + "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8" + "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24" + "\xda\x39\x87\x45\xc0\x2b\xbb\x01" + "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce" + "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6" + "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32" + "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45" + "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6" + "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4" + "\x21\xc4\xc2\x75\x67\x89\x37\x0a", + .ilen = 512, + .result = "\x55\x25\x09\x8B\xB5\xD5\xF8\xBF" + "\x37\x4A\xFE\x3C\x47\xD8\xE6\xEB" + "\xCA\xA4\x9B\xB0\xAB\x6D\x64\xCA" + "\x58\xB6\x73\xF0\xD7\x52\x34\xEF" + "\xFB\x3E\x96\x81\xB7\x71\x34\xA4" + "\x55\x20\xBE\x39\x5A\x2B\xF9\xD1" + "\x65\x0B\xDA\xD3\x7E\xB3\xA6\xF7" + "\x2E\x0B\x5A\x52\xDB\x39\x8C\x9B" + "\x61\x17\x5F\xAF\xB6\x5A\xC8\x08" + "\xA7\xB7\x2A\x11\x7C\x97\x38\x9D" + "\x59\x0E\x66\x59\x5E\xD8\x8B\xCE" + "\x70\xE0\xC3\x42\xB0\x8C\x0F\xBA" + "\xB2\x0D\x81\xB6\xBE\x61\x1C\x2D" + "\x7E\xEA\x91\x25\xAC\xEC\xF8\x28" + "\x80\x1D\xF0\x30\xBA\x62\x77\x7D" + "\xDB\x15\x69\xDF\xFA\x2A\x81\x64" + "\x95\x5B\xA4\x7F\x3E\x4F\xE3\x30" + "\xB0\x5C\xC2\x05\xF8\xF0\x29\xE7" + "\x0A\xA0\x66\xB2\x5D\x0F\x39\x2B" + "\xB4\xB3\x00\xA9\xD0\xAB\x63\x61" + "\x5E\xDB\xFC\x11\x74\x25\x96\x65" + "\xE8\xE2\x34\x57\x77\x15\x5E\x70" + "\xFF\x10\x90\xC3\x64\xF0\x11\x0A" + "\x63\x3A\xD3\x55\x92\x15\x4B\x0C" + "\xC7\x08\x89\x17\x3B\x99\xAD\x63" + "\xE7\x06\xDF\x52\xBC\x15\x64\x45" + "\x9D\x7A\xFB\x69\xBC\x2D\x6E\xA9" + "\x35\xD9\xD8\xF5\x0C\xC4\xA2\x23" + "\x9C\x18\x8B\xA8\x8C\xFE\xF8\x0E" + "\xBD\xAB\x60\x1A\x51\x17\x54\x27" + "\xB6\xE8\xBE\x0F\xA9\xA5\x82\x19" + "\x2F\x6F\x20\xA7\x47\xED\x74\x6C" + "\x4E\xC1\xF8\x8C\x14\xF3\xBB\x1F" + "\xED\x4D\x8F\x7C\x37\xEF\x19\xA1" + "\x07\x16\xDE\x76\xCC\x5E\x94\x02" + "\xFB\xBF\xE4\x81\x50\xCE\xFC\x0F" + "\x9E\xCF\x3D\xF6\x67\x00\xBF\xA7" + "\x6E\x21\x58\x36\x06\xDE\xB3\xD4" + "\xA2\xFA\xD8\x4E\xE0\xB9\x7F\x23" + "\x51\x21\x2B\x32\x68\xAA\xF8\xA8" + "\x93\x08\xB5\x6D\xE6\x43\x2C\xB7" + "\x31\xB2\x0F\xD0\xA2\x51\xC0\x25" + "\x30\xC7\x10\x3F\x97\x27\x01\x8E" + "\xFA\xD8\x4F\x78\xD8\x2E\x1D\xEB" + "\xA1\x37\x52\x0F\x7B\x5E\x87\xA8" + "\x22\xE2\xE6\x92\xA7\x5F\x11\x32" + "\xCC\x93\x34\xFC\xD1\x7E\xAE\x54" + "\xBC\x6A\x1B\x91\xD1\x2E\x21\xEC" + "\x5D\xF1\xC4\xF1\x55\x20\xBF\xE5" + "\x96\x3D\x69\x91\x20\x4E\xF2\x61" + "\xDA\x77\xFE\xEE\xC3\x74\x57\x2A" + "\x78\x39\xB0\xE0\xCF\x12\x56\xD6" + "\x05\xDC\xF9\x19\x66\x44\x1D\xF9" + "\x82\x37\xD4\xC2\x60\xB6\x31\xDF" + "\x0C\xAF\xBC\x8B\x55\x9A\xC8\x2D" + "\xAB\xA7\x88\x7B\x41\xE8\x29\xC9" + "\x9B\x8D\xA7\x00\x86\x25\xB6\x14" + "\xF5\x13\x73\xD7\x4B\x6B\x83\xF3" + "\xAF\x96\x00\xE4\xB7\x3C\x65\xA6" + "\x15\xB7\x94\x7D\x4E\x70\x4C\x75" + "\xF3\xB4\x02\xA9\x17\x1C\x7A\x0A" + "\xC0\xD5\x33\x11\x56\xDE\xDC\xF5" + "\x8D\xD9\xCD\x3B\x22\x67\x18\xC7" + "\xC4\xF5\x99\x61\xBC\xBB\x5B\x46", + .rlen = 512, + }, +}; + +static struct cipher_testvec cast6_lrw_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" + "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" + "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21" + "\xa7\x9c\x21\xf8\xcb\x90\x02\x89" + "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1" + "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e", + .klen = 48, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x01", + .input = "\x55\x25\x09\x8B\xB5\xD5\xF8\xBF" + "\x37\x4A\xFE\x3C\x47\xD8\xE6\xEB" + "\xCA\xA4\x9B\xB0\xAB\x6D\x64\xCA" + "\x58\xB6\x73\xF0\xD7\x52\x34\xEF" + "\xFB\x3E\x96\x81\xB7\x71\x34\xA4" + "\x55\x20\xBE\x39\x5A\x2B\xF9\xD1" + "\x65\x0B\xDA\xD3\x7E\xB3\xA6\xF7" + "\x2E\x0B\x5A\x52\xDB\x39\x8C\x9B" + "\x61\x17\x5F\xAF\xB6\x5A\xC8\x08" + "\xA7\xB7\x2A\x11\x7C\x97\x38\x9D" + "\x59\x0E\x66\x59\x5E\xD8\x8B\xCE" + "\x70\xE0\xC3\x42\xB0\x8C\x0F\xBA" + "\xB2\x0D\x81\xB6\xBE\x61\x1C\x2D" + "\x7E\xEA\x91\x25\xAC\xEC\xF8\x28" + "\x80\x1D\xF0\x30\xBA\x62\x77\x7D" + "\xDB\x15\x69\xDF\xFA\x2A\x81\x64" + "\x95\x5B\xA4\x7F\x3E\x4F\xE3\x30" + "\xB0\x5C\xC2\x05\xF8\xF0\x29\xE7" + "\x0A\xA0\x66\xB2\x5D\x0F\x39\x2B" + "\xB4\xB3\x00\xA9\xD0\xAB\x63\x61" + "\x5E\xDB\xFC\x11\x74\x25\x96\x65" + "\xE8\xE2\x34\x57\x77\x15\x5E\x70" + "\xFF\x10\x90\xC3\x64\xF0\x11\x0A" + "\x63\x3A\xD3\x55\x92\x15\x4B\x0C" + "\xC7\x08\x89\x17\x3B\x99\xAD\x63" + "\xE7\x06\xDF\x52\xBC\x15\x64\x45" + "\x9D\x7A\xFB\x69\xBC\x2D\x6E\xA9" + "\x35\xD9\xD8\xF5\x0C\xC4\xA2\x23" + "\x9C\x18\x8B\xA8\x8C\xFE\xF8\x0E" + "\xBD\xAB\x60\x1A\x51\x17\x54\x27" + "\xB6\xE8\xBE\x0F\xA9\xA5\x82\x19" + "\x2F\x6F\x20\xA7\x47\xED\x74\x6C" + "\x4E\xC1\xF8\x8C\x14\xF3\xBB\x1F" + "\xED\x4D\x8F\x7C\x37\xEF\x19\xA1" + "\x07\x16\xDE\x76\xCC\x5E\x94\x02" + "\xFB\xBF\xE4\x81\x50\xCE\xFC\x0F" + "\x9E\xCF\x3D\xF6\x67\x00\xBF\xA7" + "\x6E\x21\x58\x36\x06\xDE\xB3\xD4" + "\xA2\xFA\xD8\x4E\xE0\xB9\x7F\x23" + "\x51\x21\x2B\x32\x68\xAA\xF8\xA8" + "\x93\x08\xB5\x6D\xE6\x43\x2C\xB7" + "\x31\xB2\x0F\xD0\xA2\x51\xC0\x25" + "\x30\xC7\x10\x3F\x97\x27\x01\x8E" + "\xFA\xD8\x4F\x78\xD8\x2E\x1D\xEB" + "\xA1\x37\x52\x0F\x7B\x5E\x87\xA8" + "\x22\xE2\xE6\x92\xA7\x5F\x11\x32" + "\xCC\x93\x34\xFC\xD1\x7E\xAE\x54" + "\xBC\x6A\x1B\x91\xD1\x2E\x21\xEC" + "\x5D\xF1\xC4\xF1\x55\x20\xBF\xE5" + "\x96\x3D\x69\x91\x20\x4E\xF2\x61" + "\xDA\x77\xFE\xEE\xC3\x74\x57\x2A" + "\x78\x39\xB0\xE0\xCF\x12\x56\xD6" + "\x05\xDC\xF9\x19\x66\x44\x1D\xF9" + "\x82\x37\xD4\xC2\x60\xB6\x31\xDF" + "\x0C\xAF\xBC\x8B\x55\x9A\xC8\x2D" + "\xAB\xA7\x88\x7B\x41\xE8\x29\xC9" + "\x9B\x8D\xA7\x00\x86\x25\xB6\x14" + "\xF5\x13\x73\xD7\x4B\x6B\x83\xF3" + "\xAF\x96\x00\xE4\xB7\x3C\x65\xA6" + "\x15\xB7\x94\x7D\x4E\x70\x4C\x75" + "\xF3\xB4\x02\xA9\x17\x1C\x7A\x0A" + "\xC0\xD5\x33\x11\x56\xDE\xDC\xF5" + "\x8D\xD9\xCD\x3B\x22\x67\x18\xC7" + "\xC4\xF5\x99\x61\xBC\xBB\x5B\x46", + .ilen = 512, + .result = "\x05\x11\xb7\x18\xab\xc6\x2d\xac" + "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c" + "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8" + "\x50\x38\x1f\x71\x49\xb6\x57\xd6" + "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90" + "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6" + "\xad\x1e\x9e\x20\x5f\x38\xbe\x04" + "\xda\x10\x8e\xed\xa2\xa4\x87\xab" + "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c" + "\xc9\xac\x42\x31\x95\x7c\xc9\x04" + "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6" + "\x15\xd7\x3f\x4f\x2f\x66\x69\x03" + "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65" + "\x4c\x96\x12\xed\x7c\x92\x03\x01" + "\x6f\xbc\x35\x93\xac\xf1\x27\xf1" + "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50" + "\x89\xa4\x8e\x66\x44\x85\xcc\xfd" + "\x33\x14\x70\xe3\x96\xb2\xc3\xd3" + "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5" + "\x2d\x64\x75\xdd\xb4\x54\xe6\x74" + "\x8c\xd3\x9d\x9e\x86\xab\x51\x53" + "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40" + "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5" + "\x76\x12\x73\x44\x1a\x56\xd7\x72" + "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda" + "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd" + "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60" + "\x1a\xe2\x70\x85\x58\xc2\x1b\x09" + "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9" + "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8" + "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8" + "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10" + "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1" + "\x90\x3e\x76\x4a\x74\xa4\x21\x2c" + "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e" + "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f" + "\x8d\x23\x31\x74\x84\xeb\x88\x6e" + "\xcc\xb9\xbc\x22\x83\x19\x07\x22" + "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78" + "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5" + "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41" + "\x3c\xce\x8f\x42\x60\x71\xa7\x75" + "\x08\x40\x65\x8a\x82\xbf\xf5\x43" + "\x71\x96\xa9\x4d\x44\x8a\x20\xbe" + "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65" + "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9" + "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4" + "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a" + "\x62\x73\x65\xfd\x46\x63\x25\x3d" + "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf" + "\x24\xf3\xb4\xac\x64\xba\xdf\x4b" + "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7" + "\xc5\x68\x77\x84\x32\x2b\xcc\x85" + "\x74\x96\xf0\x12\x77\x61\xb9\xeb" + "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8" + "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24" + "\xda\x39\x87\x45\xc0\x2b\xbb\x01" + "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce" + "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6" + "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32" + "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45" + "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6" + "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4" + "\x21\xc4\xc2\x75\x67\x89\x37\x0a", + .rlen = 512, + }, +}; + +static struct cipher_testvec cast6_xts_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x62\x49\x77\x57\x24\x70\x93\x69" + "\x99\x59\x57\x49\x66\x96\x76\x27" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95" + "\x02\x88\x41\x97\x16\x93\x99\x37" + "\x51\x05\x82\x09\x74\x94\x45\x92", + .klen = 64, + .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .ilen = 512, + .result = "\xDE\x6F\x22\xA5\xE8\x39\xE8\x78" + "\x88\x5A\x4F\x8D\x82\x76\x52\x6D" + "\xB2\x41\x16\xF4\x2B\xA6\xEB\xF6" + "\xE2\xC5\x62\x8D\x61\xA1\x01\xED" + "\xD9\x38\x01\xC1\x43\x63\x4E\x88" + "\xC9\x4B\x5A\x88\x80\xB7\x5C\x71" + "\x47\xEE\x11\xD8\xB7\x2D\x5D\x13" + "\x1A\xB1\x68\x5B\x61\xA7\xA9\x81" + "\x8B\x83\xA1\x6A\xAA\x36\xD6\xB6" + "\x60\x54\x09\x32\xFE\x6A\x76\x2E" + "\x28\xFF\xD5\xD6\xDD\x1D\x45\x7D" + "\xF0\x8B\xF3\x32\x4E\x6C\x12\xCB" + "\xB8\x25\x70\xF8\x40\xBC\x90\x1B" + "\x11\xC3\x59\xAF\xF0\x2F\x92\xDD" + "\xD3\x3B\xCF\x60\xA1\x78\x94\x57" + "\xAF\x76\xC1\x67\xA6\x3C\xCD\x98" + "\xB1\xF7\x27\xB9\xA3\xBD\x10\xEA" + "\xCD\x8B\xC2\xF2\x14\xF2\xB2\x67" + "\x05\xDD\x1D\x58\x6E\x2F\x95\x08" + "\x3A\xF8\x78\x76\x82\x56\xA7\xEC" + "\x51\x4B\x85\x77\xC2\x4C\x4A\x34" + "\x71\x38\x17\x91\x44\xE8\xFC\x65" + "\x99\x0D\x52\x91\xEE\xF8\xEF\x27" + "\x2A\x9E\x6E\x78\xC4\x26\x87\xF4" + "\x8A\xF0\x2D\x04\xE8\x14\x92\x5D" + "\x59\x22\x9B\x29\x5C\x18\xF0\xC3" + "\x47\xF3\x76\xD8\xE4\xF3\x1B\xD1" + "\x70\xA3\x0D\xB5\x70\x02\x1D\xA3" + "\x91\x3B\x49\x73\x18\xAB\xD4\xC9" + "\xC3\x1E\xEF\x1F\xFE\xD5\x59\x8A" + "\xD7\xF6\xC9\x71\x67\x79\xD7\x0E" + "\xBE\x1F\x8E\xEC\x55\x7E\x4F\x24" + "\xE6\x87\xEA\xFE\x96\x25\x67\x8E" + "\x93\x03\xFA\xFF\xCE\xAF\xB2\x3C" + "\x6F\xEB\x57\xFB\xD3\x28\x87\xA9" + "\xCE\xC2\xF5\x9C\xC6\x67\xB5\x97" + "\x49\xF7\x04\xCB\xEF\x84\x98\x33" + "\xAF\x38\xD3\x04\x1C\x24\x71\x38" + "\xC7\x71\xDD\x43\x0D\x12\x4A\x18" + "\xBA\xC4\xAF\xBA\xB2\x5B\xEB\x95" + "\x02\x43\x5D\xCE\x19\xCC\xCD\x66" + "\x91\x0B\x8C\x7F\x51\xC4\xBF\x3C" + "\x8B\xF1\xCC\xAA\x29\xD7\x87\xCB" + "\x3E\xC5\xF3\xC9\x75\xE8\xA3\x5B" + "\x30\x45\xA9\xB7\xAF\x80\x64\x6F" + "\x75\x4A\xA7\xC0\x6D\x19\x6B\xDE" + "\x17\xDE\x6D\xEA\x87\x9F\x95\xAE" + "\xF5\x3C\xEE\x54\xB8\x27\x84\xF8" + "\x97\xA3\xE1\x6F\x38\x24\x34\x88" + "\xCE\xBD\x32\x52\xE0\x00\x6C\x94" + "\xC9\xD7\x5D\x37\x81\x33\x2E\x7F" + "\x4F\x7E\x2E\x0D\x94\xBD\xEA\x59" + "\x34\x39\xA8\x35\x12\xB7\xBC\xAC" + "\xEA\x52\x9C\x78\x02\x6D\x92\x36" + "\xFB\x59\x2B\xA4\xEA\x7B\x1B\x83" + "\xE1\x4D\x5E\x2A\x7E\x92\xB1\x64" + "\xDE\xE0\x27\x4B\x0A\x6F\x4C\xE3" + "\xB0\xEB\x31\xE4\x69\x95\xAB\x35" + "\x8B\x2C\xF5\x6B\x7F\xF1\xA2\x82" + "\xF8\xD9\x47\x82\xA9\x82\x03\x91" + "\x69\x1F\xBE\x4C\xE7\xC7\x34\x2F" + "\x45\x72\x80\x17\x81\xBD\x9D\x62" + "\xA1\xAC\xE8\xCF\xC6\x74\xCF\xDC" + "\x22\x60\x4E\xE8\xA4\x5D\x85\xB9", + .rlen = 512, + }, +}; + +static struct cipher_testvec cast6_xts_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x62\x49\x77\x57\x24\x70\x93\x69" + "\x99\x59\x57\x49\x66\x96\x76\x27" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95" + "\x02\x88\x41\x97\x16\x93\x99\x37" + "\x51\x05\x82\x09\x74\x94\x45\x92", + .klen = 64, + .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\xDE\x6F\x22\xA5\xE8\x39\xE8\x78" + "\x88\x5A\x4F\x8D\x82\x76\x52\x6D" + "\xB2\x41\x16\xF4\x2B\xA6\xEB\xF6" + "\xE2\xC5\x62\x8D\x61\xA1\x01\xED" + "\xD9\x38\x01\xC1\x43\x63\x4E\x88" + "\xC9\x4B\x5A\x88\x80\xB7\x5C\x71" + "\x47\xEE\x11\xD8\xB7\x2D\x5D\x13" + "\x1A\xB1\x68\x5B\x61\xA7\xA9\x81" + "\x8B\x83\xA1\x6A\xAA\x36\xD6\xB6" + "\x60\x54\x09\x32\xFE\x6A\x76\x2E" + "\x28\xFF\xD5\xD6\xDD\x1D\x45\x7D" + "\xF0\x8B\xF3\x32\x4E\x6C\x12\xCB" + "\xB8\x25\x70\xF8\x40\xBC\x90\x1B" + "\x11\xC3\x59\xAF\xF0\x2F\x92\xDD" + "\xD3\x3B\xCF\x60\xA1\x78\x94\x57" + "\xAF\x76\xC1\x67\xA6\x3C\xCD\x98" + "\xB1\xF7\x27\xB9\xA3\xBD\x10\xEA" + "\xCD\x8B\xC2\xF2\x14\xF2\xB2\x67" + "\x05\xDD\x1D\x58\x6E\x2F\x95\x08" + "\x3A\xF8\x78\x76\x82\x56\xA7\xEC" + "\x51\x4B\x85\x77\xC2\x4C\x4A\x34" + "\x71\x38\x17\x91\x44\xE8\xFC\x65" + "\x99\x0D\x52\x91\xEE\xF8\xEF\x27" + "\x2A\x9E\x6E\x78\xC4\x26\x87\xF4" + "\x8A\xF0\x2D\x04\xE8\x14\x92\x5D" + "\x59\x22\x9B\x29\x5C\x18\xF0\xC3" + "\x47\xF3\x76\xD8\xE4\xF3\x1B\xD1" + "\x70\xA3\x0D\xB5\x70\x02\x1D\xA3" + "\x91\x3B\x49\x73\x18\xAB\xD4\xC9" + "\xC3\x1E\xEF\x1F\xFE\xD5\x59\x8A" + "\xD7\xF6\xC9\x71\x67\x79\xD7\x0E" + "\xBE\x1F\x8E\xEC\x55\x7E\x4F\x24" + "\xE6\x87\xEA\xFE\x96\x25\x67\x8E" + "\x93\x03\xFA\xFF\xCE\xAF\xB2\x3C" + "\x6F\xEB\x57\xFB\xD3\x28\x87\xA9" + "\xCE\xC2\xF5\x9C\xC6\x67\xB5\x97" + "\x49\xF7\x04\xCB\xEF\x84\x98\x33" + "\xAF\x38\xD3\x04\x1C\x24\x71\x38" + "\xC7\x71\xDD\x43\x0D\x12\x4A\x18" + "\xBA\xC4\xAF\xBA\xB2\x5B\xEB\x95" + "\x02\x43\x5D\xCE\x19\xCC\xCD\x66" + "\x91\x0B\x8C\x7F\x51\xC4\xBF\x3C" + "\x8B\xF1\xCC\xAA\x29\xD7\x87\xCB" + "\x3E\xC5\xF3\xC9\x75\xE8\xA3\x5B" + "\x30\x45\xA9\xB7\xAF\x80\x64\x6F" + "\x75\x4A\xA7\xC0\x6D\x19\x6B\xDE" + "\x17\xDE\x6D\xEA\x87\x9F\x95\xAE" + "\xF5\x3C\xEE\x54\xB8\x27\x84\xF8" + "\x97\xA3\xE1\x6F\x38\x24\x34\x88" + "\xCE\xBD\x32\x52\xE0\x00\x6C\x94" + "\xC9\xD7\x5D\x37\x81\x33\x2E\x7F" + "\x4F\x7E\x2E\x0D\x94\xBD\xEA\x59" + "\x34\x39\xA8\x35\x12\xB7\xBC\xAC" + "\xEA\x52\x9C\x78\x02\x6D\x92\x36" + "\xFB\x59\x2B\xA4\xEA\x7B\x1B\x83" + "\xE1\x4D\x5E\x2A\x7E\x92\xB1\x64" + "\xDE\xE0\x27\x4B\x0A\x6F\x4C\xE3" + "\xB0\xEB\x31\xE4\x69\x95\xAB\x35" + "\x8B\x2C\xF5\x6B\x7F\xF1\xA2\x82" + "\xF8\xD9\x47\x82\xA9\x82\x03\x91" + "\x69\x1F\xBE\x4C\xE7\xC7\x34\x2F" + "\x45\x72\x80\x17\x81\xBD\x9D\x62" + "\xA1\xAC\xE8\xCF\xC6\x74\xCF\xDC" + "\x22\x60\x4E\xE8\xA4\x5D\x85\xB9", + .ilen = 512, + .result = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .rlen = 512, }, }; From 4ea1277d301eb776e321684cd4ea95116b4e8847 Mon Sep 17 00:00:00 2001 From: Johannes Goetzfried Date: Wed, 11 Jul 2012 19:38:57 +0200 Subject: [PATCH 0172/5375] crypto: cast6 - add x86_64/avx assembler implementation This patch adds a x86_64/avx assembler implementation of the Cast6 block cipher. The implementation processes eight blocks in parallel (two 4 block chunk AVX operations). The table-lookups are done in general-purpose registers. For small blocksizes the functions from the generic module are called. A good performance increase is provided for blocksizes greater or equal to 128B. Patch has been tested with tcrypt and automated filesystem tests. Tcrypt benchmark results: Intel Core i5-2500 CPU (fam:6, model:42, step:7) cast6-avx-x86_64 vs. cast6-generic 128bit key: (lrw:256bit) (xts:256bit) size ecb-enc ecb-dec cbc-enc cbc-dec ctr-enc ctr-dec lrw-enc lrw-dec xts-enc xts-dec 16B 0.97x 1.00x 1.01x 1.01x 0.99x 0.97x 0.98x 1.01x 0.96x 0.98x 64B 0.98x 0.99x 1.02x 1.01x 0.99x 1.00x 1.01x 0.99x 1.00x 0.99x 256B 1.77x 1.84x 0.99x 1.85x 1.77x 1.77x 1.70x 1.74x 1.69x 1.72x 1024B 1.93x 1.95x 0.99x 1.96x 1.93x 1.93x 1.84x 1.85x 1.89x 1.87x 8192B 1.91x 1.95x 0.99x 1.97x 1.95x 1.91x 1.86x 1.87x 1.93x 1.90x 256bit key: (lrw:384bit) (xts:512bit) size ecb-enc ecb-dec cbc-enc cbc-dec ctr-enc ctr-dec lrw-enc lrw-dec xts-enc xts-dec 16B 0.97x 0.99x 1.02x 1.01x 0.98x 0.99x 1.00x 1.00x 0.98x 0.98x 64B 0.98x 0.99x 1.01x 1.00x 1.00x 1.00x 1.01x 1.01x 0.97x 1.00x 256B 1.77x 1.83x 1.00x 1.86x 1.79x 1.78x 1.70x 1.76x 1.71x 1.69x 1024B 1.92x 1.95x 0.99x 1.96x 1.93x 1.93x 1.83x 1.86x 1.89x 1.87x 8192B 1.94x 1.95x 0.99x 1.97x 1.95x 1.95x 1.87x 1.87x 1.93x 1.91x Signed-off-by: Johannes Goetzfried Signed-off-by: Herbert Xu --- arch/x86/crypto/Makefile | 2 + arch/x86/crypto/cast6-avx-x86_64-asm_64.S | 335 +++++++++++ arch/x86/crypto/cast6_avx_glue.c | 648 ++++++++++++++++++++++ crypto/Kconfig | 17 + crypto/testmgr.c | 60 ++ 5 files changed, 1062 insertions(+) create mode 100644 arch/x86/crypto/cast6-avx-x86_64-asm_64.S create mode 100644 arch/x86/crypto/cast6_avx_glue.c diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index 565e82b00142..5bacb4a226ac 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o obj-$(CONFIG_CRYPTO_CAST5_AVX_X86_64) += cast5-avx-x86_64.o +obj-$(CONFIG_CRYPTO_CAST6_AVX_X86_64) += cast6-avx-x86_64.o obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o @@ -34,6 +35,7 @@ serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o cast5-avx-x86_64-y := cast5-avx-x86_64-asm_64.o cast5_avx_glue.o +cast6-avx-x86_64-y := cast6-avx-x86_64-asm_64.o cast6_avx_glue.o blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o diff --git a/arch/x86/crypto/cast6-avx-x86_64-asm_64.S b/arch/x86/crypto/cast6-avx-x86_64-asm_64.S new file mode 100644 index 000000000000..d258ce0d2e06 --- /dev/null +++ b/arch/x86/crypto/cast6-avx-x86_64-asm_64.S @@ -0,0 +1,335 @@ +/* + * Cast6 Cipher 8-way parallel algorithm (AVX/x86_64) + * + * Copyright (C) 2012 Johannes Goetzfried + * + * + * 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 + * + */ + +.file "cast6-avx-x86_64-asm_64.S" +.text + +.extern cast6_s1 +.extern cast6_s2 +.extern cast6_s3 +.extern cast6_s4 + +/* structure of crypto context */ +#define km 0 +#define kr (12*4*4) + +/* s-boxes */ +#define s1 cast6_s1 +#define s2 cast6_s2 +#define s3 cast6_s3 +#define s4 cast6_s4 + +/********************************************************************** + 8-way AVX cast6 + **********************************************************************/ +#define CTX %rdi + +#define RA1 %xmm0 +#define RB1 %xmm1 +#define RC1 %xmm2 +#define RD1 %xmm3 + +#define RA2 %xmm4 +#define RB2 %xmm5 +#define RC2 %xmm6 +#define RD2 %xmm7 + +#define RX %xmm8 + +#define RKM %xmm9 +#define RKRF %xmm10 +#define RKRR %xmm11 + +#define RTMP %xmm12 +#define RMASK %xmm13 +#define R32 %xmm14 + +#define RID1 %rax +#define RID1b %al +#define RID2 %rbx +#define RID2b %bl + +#define RGI1 %rdx +#define RGI1bl %dl +#define RGI1bh %dh +#define RGI2 %rcx +#define RGI2bl %cl +#define RGI2bh %ch + +#define RFS1 %r8 +#define RFS1d %r8d +#define RFS2 %r9 +#define RFS2d %r9d +#define RFS3 %r10 +#define RFS3d %r10d + + +#define lookup_32bit(src, dst, op1, op2, op3) \ + movb src ## bl, RID1b; \ + movb src ## bh, RID2b; \ + movl s1(, RID1, 4), dst ## d; \ + op1 s2(, RID2, 4), dst ## d; \ + shrq $16, src; \ + movb src ## bl, RID1b; \ + movb src ## bh, RID2b; \ + op2 s3(, RID1, 4), dst ## d; \ + op3 s4(, RID2, 4), dst ## d; + +#define F(a, x, op0, op1, op2, op3) \ + op0 a, RKM, x; \ + vpslld RKRF, x, RTMP; \ + vpsrld RKRR, x, x; \ + vpor RTMP, x, x; \ + \ + vpshufb RMASK, x, x; \ + vmovq x, RGI1; \ + vpsrldq $8, x, x; \ + vmovq x, RGI2; \ + \ + lookup_32bit(RGI1, RFS1, op1, op2, op3); \ + shrq $16, RGI1; \ + lookup_32bit(RGI1, RFS2, op1, op2, op3); \ + shlq $32, RFS2; \ + orq RFS1, RFS2; \ + \ + lookup_32bit(RGI2, RFS1, op1, op2, op3); \ + shrq $16, RGI2; \ + lookup_32bit(RGI2, RFS3, op1, op2, op3); \ + shlq $32, RFS3; \ + orq RFS1, RFS3; \ + \ + vmovq RFS2, x; \ + vpinsrq $1, RFS3, x, x; + +#define F1(b, x) F(b, x, vpaddd, xorl, subl, addl) +#define F2(b, x) F(b, x, vpxor, subl, addl, xorl) +#define F3(b, x) F(b, x, vpsubd, addl, xorl, subl) + +#define qop(in, out, x, f) \ + F ## f(in ## 1, x); \ + vpxor out ## 1, x, out ## 1; \ + F ## f(in ## 2, x); \ + vpxor out ## 2, x, out ## 2; \ + +#define Q(n) \ + vbroadcastss (km+(4*(4*n+0)))(CTX), RKM; \ + vpinsrb $0, (kr+(4*n+0))(CTX), RKRF, RKRF; \ + vpsubq RKRF, R32, RKRR; \ + qop(RD, RC, RX, 1); \ + \ + vbroadcastss (km+(4*(4*n+1)))(CTX), RKM; \ + vpinsrb $0, (kr+(4*n+1))(CTX), RKRF, RKRF; \ + vpsubq RKRF, R32, RKRR; \ + qop(RC, RB, RX, 2); \ + \ + vbroadcastss (km+(4*(4*n+2)))(CTX), RKM; \ + vpinsrb $0, (kr+(4*n+2))(CTX), RKRF, RKRF; \ + vpsubq RKRF, R32, RKRR; \ + qop(RB, RA, RX, 3); \ + \ + vbroadcastss (km+(4*(4*n+3)))(CTX), RKM; \ + vpinsrb $0, (kr+(4*n+3))(CTX), RKRF, RKRF; \ + vpsubq RKRF, R32, RKRR; \ + qop(RA, RD, RX, 1); + +#define QBAR(n) \ + vbroadcastss (km+(4*(4*n+3)))(CTX), RKM; \ + vpinsrb $0, (kr+(4*n+3))(CTX), RKRF, RKRF; \ + vpsubq RKRF, R32, RKRR; \ + qop(RA, RD, RX, 1); \ + \ + vbroadcastss (km+(4*(4*n+2)))(CTX), RKM; \ + vpinsrb $0, (kr+(4*n+2))(CTX), RKRF, RKRF; \ + vpsubq RKRF, R32, RKRR; \ + qop(RB, RA, RX, 3); \ + \ + vbroadcastss (km+(4*(4*n+1)))(CTX), RKM; \ + vpinsrb $0, (kr+(4*n+1))(CTX), RKRF, RKRF; \ + vpsubq RKRF, R32, RKRR; \ + qop(RC, RB, RX, 2); \ + \ + vbroadcastss (km+(4*(4*n+0)))(CTX), RKM; \ + vpinsrb $0, (kr+(4*n+0))(CTX), RKRF, RKRF; \ + vpsubq RKRF, R32, RKRR; \ + qop(RD, RC, RX, 1); + + +#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ + vpunpckldq x1, x0, t0; \ + vpunpckhdq x1, x0, t2; \ + vpunpckldq x3, x2, t1; \ + vpunpckhdq x3, x2, x3; \ + \ + vpunpcklqdq t1, t0, x0; \ + vpunpckhqdq t1, t0, x1; \ + vpunpcklqdq x3, t2, x2; \ + vpunpckhqdq x3, t2, x3; + +#define inpack_blocks(in, x0, x1, x2, x3, t0, t1, t2) \ + vmovdqu (0*4*4)(in), x0; \ + vmovdqu (1*4*4)(in), x1; \ + vmovdqu (2*4*4)(in), x2; \ + vmovdqu (3*4*4)(in), x3; \ + vpshufb RMASK, x0, x0; \ + vpshufb RMASK, x1, x1; \ + vpshufb RMASK, x2, x2; \ + vpshufb RMASK, x3, x3; \ + \ + transpose_4x4(x0, x1, x2, x3, t0, t1, t2) + +#define outunpack_blocks(out, x0, x1, x2, x3, t0, t1, t2) \ + transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ + \ + vpshufb RMASK, x0, x0; \ + vpshufb RMASK, x1, x1; \ + vpshufb RMASK, x2, x2; \ + vpshufb RMASK, x3, x3; \ + vmovdqu x0, (0*4*4)(out); \ + vmovdqu x1, (1*4*4)(out); \ + vmovdqu x2, (2*4*4)(out); \ + vmovdqu x3, (3*4*4)(out); + +#define outunpack_xor_blocks(out, x0, x1, x2, x3, t0, t1, t2) \ + transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ + \ + vpshufb RMASK, x0, x0; \ + vpshufb RMASK, x1, x1; \ + vpshufb RMASK, x2, x2; \ + vpshufb RMASK, x3, x3; \ + vpxor (0*4*4)(out), x0, x0; \ + vmovdqu x0, (0*4*4)(out); \ + vpxor (1*4*4)(out), x1, x1; \ + vmovdqu x1, (1*4*4)(out); \ + vpxor (2*4*4)(out), x2, x2; \ + vmovdqu x2, (2*4*4)(out); \ + vpxor (3*4*4)(out), x3, x3; \ + vmovdqu x3, (3*4*4)(out); + +.align 16 +.Lbswap_mask: + .byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 +.L32_mask: + .byte 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0 + +.align 16 +.global __cast6_enc_blk_8way +.type __cast6_enc_blk_8way,@function; + +__cast6_enc_blk_8way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + * %rcx: bool, if true: xor output + */ + + pushq %rbx; + pushq %rcx; + + vmovdqu .Lbswap_mask, RMASK; + vmovdqu .L32_mask, R32; + vpxor RKRF, RKRF, RKRF; + + leaq (4*4*4)(%rdx), %rax; + inpack_blocks(%rdx, RA1, RB1, RC1, RD1, RTMP, RX, RKM); + inpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM); + + xorq RID1, RID1; + xorq RID2, RID2; + + Q(0); + Q(1); + Q(2); + Q(3); + Q(4); + Q(5); + QBAR(6); + QBAR(7); + QBAR(8); + QBAR(9); + QBAR(10); + QBAR(11); + + popq %rcx; + popq %rbx; + + leaq (4*4*4)(%rsi), %rax; + + testb %cl, %cl; + jnz __enc_xor8; + + outunpack_blocks(%rsi, RA1, RB1, RC1, RD1, RTMP, RX, RKM); + outunpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM); + + ret; + +__enc_xor8: + outunpack_xor_blocks(%rsi, RA1, RB1, RC1, RD1, RTMP, RX, RKM); + outunpack_xor_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM); + + ret; + +.align 16 +.global cast6_dec_blk_8way +.type cast6_dec_blk_8way,@function; + +cast6_dec_blk_8way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + + pushq %rbx; + + vmovdqu .Lbswap_mask, RMASK; + vmovdqu .L32_mask, R32; + vpxor RKRF, RKRF, RKRF; + + leaq (4*4*4)(%rdx), %rax; + inpack_blocks(%rdx, RA1, RB1, RC1, RD1, RTMP, RX, RKM); + inpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM); + + xorq RID1, RID1; + xorq RID2, RID2; + + Q(11); + Q(10); + Q(9); + Q(8); + Q(7); + Q(6); + QBAR(5); + QBAR(4); + QBAR(3); + QBAR(2); + QBAR(1); + QBAR(0); + + popq %rbx; + + leaq (4*4*4)(%rsi), %rax; + outunpack_blocks(%rsi, RA1, RB1, RC1, RD1, RTMP, RX, RKM); + outunpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM); + + ret; diff --git a/arch/x86/crypto/cast6_avx_glue.c b/arch/x86/crypto/cast6_avx_glue.c new file mode 100644 index 000000000000..15e5f85a5011 --- /dev/null +++ b/arch/x86/crypto/cast6_avx_glue.c @@ -0,0 +1,648 @@ +/* + * Glue Code for the AVX assembler implemention of the Cast6 Cipher + * + * Copyright (C) 2012 Johannes Goetzfried + * + * + * 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 + +#define CAST6_PARALLEL_BLOCKS 8 + +asmlinkage void __cast6_enc_blk_8way(struct cast6_ctx *ctx, u8 *dst, + const u8 *src, bool xor); +asmlinkage void cast6_dec_blk_8way(struct cast6_ctx *ctx, u8 *dst, + const u8 *src); + +static inline void cast6_enc_blk_xway(struct cast6_ctx *ctx, u8 *dst, + const u8 *src) +{ + __cast6_enc_blk_8way(ctx, dst, src, false); +} + +static inline void cast6_enc_blk_xway_xor(struct cast6_ctx *ctx, u8 *dst, + const u8 *src) +{ + __cast6_enc_blk_8way(ctx, dst, src, true); +} + +static inline void cast6_dec_blk_xway(struct cast6_ctx *ctx, u8 *dst, + const u8 *src) +{ + cast6_dec_blk_8way(ctx, dst, src); +} + + +static void cast6_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src) +{ + u128 ivs[CAST6_PARALLEL_BLOCKS - 1]; + unsigned int j; + + for (j = 0; j < CAST6_PARALLEL_BLOCKS - 1; j++) + ivs[j] = src[j]; + + cast6_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src); + + for (j = 0; j < CAST6_PARALLEL_BLOCKS - 1; j++) + u128_xor(dst + (j + 1), dst + (j + 1), ivs + j); +} + +static void cast6_crypt_ctr(void *ctx, u128 *dst, const u128 *src, u128 *iv) +{ + be128 ctrblk; + + u128_to_be128(&ctrblk, iv); + u128_inc(iv); + + __cast6_encrypt(ctx, (u8 *)&ctrblk, (u8 *)&ctrblk); + u128_xor(dst, src, (u128 *)&ctrblk); +} + +static void cast6_crypt_ctr_xway(void *ctx, u128 *dst, const u128 *src, + u128 *iv) +{ + be128 ctrblks[CAST6_PARALLEL_BLOCKS]; + unsigned int i; + + for (i = 0; i < CAST6_PARALLEL_BLOCKS; i++) { + if (dst != src) + dst[i] = src[i]; + + u128_to_be128(&ctrblks[i], iv); + u128_inc(iv); + } + + cast6_enc_blk_xway_xor(ctx, (u8 *)dst, (u8 *)ctrblks); +} + +static const struct common_glue_ctx cast6_enc = { + .num_funcs = 2, + .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS, + + .funcs = { { + .num_blocks = CAST6_PARALLEL_BLOCKS, + .fn_u = { .ecb = GLUE_FUNC_CAST(cast6_enc_blk_xway) } + }, { + .num_blocks = 1, + .fn_u = { .ecb = GLUE_FUNC_CAST(__cast6_encrypt) } + } } +}; + +static const struct common_glue_ctx cast6_ctr = { + .num_funcs = 2, + .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS, + + .funcs = { { + .num_blocks = CAST6_PARALLEL_BLOCKS, + .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(cast6_crypt_ctr_xway) } + }, { + .num_blocks = 1, + .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(cast6_crypt_ctr) } + } } +}; + +static const struct common_glue_ctx cast6_dec = { + .num_funcs = 2, + .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS, + + .funcs = { { + .num_blocks = CAST6_PARALLEL_BLOCKS, + .fn_u = { .ecb = GLUE_FUNC_CAST(cast6_dec_blk_xway) } + }, { + .num_blocks = 1, + .fn_u = { .ecb = GLUE_FUNC_CAST(__cast6_decrypt) } + } } +}; + +static const struct common_glue_ctx cast6_dec_cbc = { + .num_funcs = 2, + .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS, + + .funcs = { { + .num_blocks = CAST6_PARALLEL_BLOCKS, + .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(cast6_decrypt_cbc_xway) } + }, { + .num_blocks = 1, + .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__cast6_decrypt) } + } } +}; + +static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return glue_ecb_crypt_128bit(&cast6_enc, desc, dst, src, nbytes); +} + +static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return glue_ecb_crypt_128bit(&cast6_dec, desc, dst, src, nbytes); +} + +static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__cast6_encrypt), desc, + dst, src, nbytes); +} + +static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return glue_cbc_decrypt_128bit(&cast6_dec_cbc, desc, dst, src, + nbytes); +} + +static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return glue_ctr_crypt_128bit(&cast6_ctr, desc, dst, src, nbytes); +} + +static inline bool cast6_fpu_begin(bool fpu_enabled, unsigned int nbytes) +{ + return glue_fpu_begin(CAST6_BLOCK_SIZE, CAST6_PARALLEL_BLOCKS, + NULL, fpu_enabled, nbytes); +} + +static inline void cast6_fpu_end(bool fpu_enabled) +{ + glue_fpu_end(fpu_enabled); +} + +struct crypt_priv { + struct cast6_ctx *ctx; + bool fpu_enabled; +}; + +static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) +{ + const unsigned int bsize = CAST6_BLOCK_SIZE; + struct crypt_priv *ctx = priv; + int i; + + ctx->fpu_enabled = cast6_fpu_begin(ctx->fpu_enabled, nbytes); + + if (nbytes == bsize * CAST6_PARALLEL_BLOCKS) { + cast6_enc_blk_xway(ctx->ctx, srcdst, srcdst); + return; + } + + for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) + __cast6_encrypt(ctx->ctx, srcdst, srcdst); +} + +static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) +{ + const unsigned int bsize = CAST6_BLOCK_SIZE; + struct crypt_priv *ctx = priv; + int i; + + ctx->fpu_enabled = cast6_fpu_begin(ctx->fpu_enabled, nbytes); + + if (nbytes == bsize * CAST6_PARALLEL_BLOCKS) { + cast6_dec_blk_xway(ctx->ctx, srcdst, srcdst); + return; + } + + for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) + __cast6_decrypt(ctx->ctx, srcdst, srcdst); +} + +struct cast6_lrw_ctx { + struct lrw_table_ctx lrw_table; + struct cast6_ctx cast6_ctx; +}; + +static int lrw_cast6_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct cast6_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + err = __cast6_setkey(&ctx->cast6_ctx, key, keylen - CAST6_BLOCK_SIZE, + &tfm->crt_flags); + if (err) + return err; + + return lrw_init_table(&ctx->lrw_table, key + keylen - CAST6_BLOCK_SIZE); +} + +static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct cast6_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[CAST6_PARALLEL_BLOCKS]; + struct crypt_priv crypt_ctx = { + .ctx = &ctx->cast6_ctx, + .fpu_enabled = false, + }; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = &crypt_ctx, + .crypt_fn = encrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + ret = lrw_crypt(desc, dst, src, nbytes, &req); + cast6_fpu_end(crypt_ctx.fpu_enabled); + + return ret; +} + +static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct cast6_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[CAST6_PARALLEL_BLOCKS]; + struct crypt_priv crypt_ctx = { + .ctx = &ctx->cast6_ctx, + .fpu_enabled = false, + }; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = &crypt_ctx, + .crypt_fn = decrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + ret = lrw_crypt(desc, dst, src, nbytes, &req); + cast6_fpu_end(crypt_ctx.fpu_enabled); + + return ret; +} + +static void lrw_exit_tfm(struct crypto_tfm *tfm) +{ + struct cast6_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + + lrw_free_table(&ctx->lrw_table); +} + +struct cast6_xts_ctx { + struct cast6_ctx tweak_ctx; + struct cast6_ctx crypt_ctx; +}; + +static int xts_cast6_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct cast6_xts_ctx *ctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + int err; + + /* key consists of keys of equal size concatenated, therefore + * the length must be even + */ + if (keylen % 2) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + /* first half of xts-key is for crypt */ + err = __cast6_setkey(&ctx->crypt_ctx, key, keylen / 2, flags); + if (err) + return err; + + /* second half of xts-key is for tweak */ + return __cast6_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2, + flags); +} + +static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[CAST6_PARALLEL_BLOCKS]; + struct crypt_priv crypt_ctx = { + .ctx = &ctx->crypt_ctx, + .fpu_enabled = false, + }; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = &ctx->tweak_ctx, + .tweak_fn = XTS_TWEAK_CAST(__cast6_encrypt), + .crypt_ctx = &crypt_ctx, + .crypt_fn = encrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + ret = xts_crypt(desc, dst, src, nbytes, &req); + cast6_fpu_end(crypt_ctx.fpu_enabled); + + return ret; +} + +static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[CAST6_PARALLEL_BLOCKS]; + struct crypt_priv crypt_ctx = { + .ctx = &ctx->crypt_ctx, + .fpu_enabled = false, + }; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = &ctx->tweak_ctx, + .tweak_fn = XTS_TWEAK_CAST(__cast6_encrypt), + .crypt_ctx = &crypt_ctx, + .crypt_fn = decrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + ret = xts_crypt(desc, dst, src, nbytes, &req); + cast6_fpu_end(crypt_ctx.fpu_enabled); + + return ret; +} + +static struct crypto_alg cast6_algs[10] = { { + .cra_name = "__ecb-cast6-avx", + .cra_driver_name = "__driver-ecb-cast6-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast6_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .setkey = cast6_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "__cbc-cast6-avx", + .cra_driver_name = "__driver-cbc-cast6-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast6_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .setkey = cast6_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { + .cra_name = "__ctr-cast6-avx", + .cra_driver_name = "__driver-ctr-cast6-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct cast6_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = cast6_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}, { + .cra_name = "__lrw-cast6-avx", + .cra_driver_name = "__driver-lrw-cast6-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast6_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_exit = lrw_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE + + CAST6_BLOCK_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE + + CAST6_BLOCK_SIZE, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = lrw_cast6_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}, { + .cra_name = "__xts-cast6-avx", + .cra_driver_name = "__driver-xts-cast6-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast6_xts_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE * 2, + .max_keysize = CAST6_MAX_KEY_SIZE * 2, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = xts_cast6_setkey, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, + }, + }, +}, { + .cra_name = "ecb(cast6)", + .cra_driver_name = "ecb-cast6-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}, { + .cra_name = "cbc(cast6)", + .cra_driver_name = "cbc-cast6-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = __ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}, { + .cra_name = "ctr(cast6)", + .cra_driver_name = "ctr-cast6-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_encrypt, + .geniv = "chainiv", + }, + }, +}, { + .cra_name = "lrw(cast6)", + .cra_driver_name = "lrw-cast6-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE + + CAST6_BLOCK_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE + + CAST6_BLOCK_SIZE, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}, { + .cra_name = "xts(cast6)", + .cra_driver_name = "xts-cast6-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE * 2, + .max_keysize = CAST6_MAX_KEY_SIZE * 2, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +} }; + +static int __init cast6_init(void) +{ + u64 xcr0; + + if (!cpu_has_avx || !cpu_has_osxsave) { + pr_info("AVX instructions are not detected.\n"); + return -ENODEV; + } + + xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); + if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) { + pr_info("AVX detected but unusable.\n"); + return -ENODEV; + } + + return crypto_register_algs(cast6_algs, ARRAY_SIZE(cast6_algs)); +} + +static void __exit cast6_exit(void) +{ + crypto_unregister_algs(cast6_algs, ARRAY_SIZE(cast6_algs)); +} + +module_init(cast6_init); +module_exit(cast6_exit); + +MODULE_DESCRIPTION("Cast6 Cipher Algorithm, AVX optimized"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("cast6"); diff --git a/crypto/Kconfig b/crypto/Kconfig index cda97fcaa822..fe8ed62efe2f 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -713,6 +713,23 @@ config CRYPTO_CAST6 The CAST6 encryption algorithm (synonymous with CAST-256) is described in RFC2612. +config CRYPTO_CAST6_AVX_X86_64 + tristate "CAST6 (CAST-256) cipher algorithm (x86_64/AVX)" + depends on X86 && 64BIT + select CRYPTO_ALGAPI + select CRYPTO_CRYPTD + select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_GLUE_HELPER_X86 + select CRYPTO_CAST6 + select CRYPTO_LRW + select CRYPTO_XTS + help + The CAST6 encryption algorithm (synonymous with CAST-256) is + described in RFC2612. + + This module provides the Cast6 cipher algorithm that processes + eight blocks parallel using the AVX instruction set. + config CRYPTO_DES tristate "DES and Triple DES EDE cipher algorithms" select CRYPTO_ALGAPI diff --git a/crypto/testmgr.c b/crypto/testmgr.c index cff3c1c3f83c..575b57c3244b 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1548,6 +1548,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "__cbc-cast6-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } }, { .alg = "__cbc-serpent-avx", .test = alg_test_null, @@ -1624,6 +1639,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "__driver-cbc-cast6-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } }, { .alg = "__driver-cbc-serpent-avx", .test = alg_test_null, @@ -1700,6 +1730,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "__driver-ecb-cast6-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } }, { .alg = "__driver-ecb-serpent-avx", .test = alg_test_null, @@ -2026,6 +2071,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } } + }, { + .alg = "cryptd(__driver-ecb-cast6-avx)", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } }, { .alg = "cryptd(__driver-ecb-serpent-avx)", .test = alg_test_null, From 4a905077134849ea30d1c6dbf4071ea9e8e71b93 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Fri, 13 Jul 2012 18:04:23 -0500 Subject: [PATCH 0173/5375] crypto: caam - fix possible deadlock condition commit "crypto: caam - use non-irq versions of spinlocks for job rings" made two bad assumptions: (a) The caam_jr_enqueue lock isn't used in softirq context. Not true: jr_enqueue can be interrupted by an incoming net interrupt and the received packet may be sent for encryption, via caam_jr_enqueue in softirq context, thereby inducing a deadlock. This is evidenced when running netperf over an IPSec tunnel between two P4080's, with spinlock debugging turned on: [ 892.092569] BUG: spinlock lockup on CPU#7, netperf/10634, e8bf5f70 [ 892.098747] Call Trace: [ 892.101197] [eff9fc10] [c00084c0] show_stack+0x48/0x15c (unreliable) [ 892.107563] [eff9fc50] [c0239c2c] do_raw_spin_lock+0x16c/0x174 [ 892.113399] [eff9fc80] [c0596494] _raw_spin_lock+0x3c/0x50 [ 892.118889] [eff9fc90] [c0445e74] caam_jr_enqueue+0xf8/0x250 [ 892.124550] [eff9fcd0] [c044a644] aead_decrypt+0x6c/0xc8 [ 892.129625] BUG: spinlock lockup on CPU#5, swapper/5/0, e8bf5f70 [ 892.129629] Call Trace: [ 892.129637] [effa7c10] [c00084c0] show_stack+0x48/0x15c (unreliable) [ 892.129645] [effa7c50] [c0239c2c] do_raw_spin_lock+0x16c/0x174 [ 892.129652] [effa7c80] [c0596494] _raw_spin_lock+0x3c/0x50 [ 892.129660] [effa7c90] [c0445e74] caam_jr_enqueue+0xf8/0x250 [ 892.129666] [effa7cd0] [c044a644] aead_decrypt+0x6c/0xc8 [ 892.129674] [effa7d00] [c0509724] esp_input+0x178/0x334 [ 892.129681] [effa7d50] [c0519778] xfrm_input+0x77c/0x818 [ 892.129688] [effa7da0] [c050e344] xfrm4_rcv_encap+0x20/0x30 [ 892.129697] [effa7db0] [c04b90c8] ip_local_deliver+0x190/0x408 [ 892.129703] [effa7de0] [c04b966c] ip_rcv+0x32c/0x898 [ 892.129709] [effa7e10] [c048b998] __netif_receive_skb+0x27c/0x4e8 [ 892.129715] [effa7e80] [c048d744] netif_receive_skb+0x4c/0x13c [ 892.129726] [effa7eb0] [c03c28ac] _dpa_rx+0x1a8/0x354 [ 892.129732] [effa7ef0] [c03c2ac4] ingress_rx_default_dqrr+0x6c/0x108 [ 892.129742] [effa7f10] [c0467ae0] qman_poll_dqrr+0x170/0x1d4 [ 892.129748] [effa7f40] [c03c153c] dpaa_eth_poll+0x20/0x94 [ 892.129754] [effa7f60] [c048dbd0] net_rx_action+0x13c/0x1f4 [ 892.129763] [effa7fa0] [c003d1b8] __do_softirq+0x108/0x1b0 [ 892.129769] [effa7ff0] [c000df58] call_do_softirq+0x14/0x24 [ 892.129775] [ebacfe70] [c0004868] do_softirq+0xd8/0x104 [ 892.129780] [ebacfe90] [c003d5a4] irq_exit+0xb8/0xd8 [ 892.129786] [ebacfea0] [c0004498] do_IRQ+0xa4/0x1b0 [ 892.129792] [ebacfed0] [c000fad8] ret_from_except+0x0/0x18 [ 892.129798] [ebacff90] [c0009010] cpu_idle+0x94/0xf0 [ 892.129804] [ebacffb0] [c059ff88] start_secondary+0x42c/0x430 [ 892.129809] [ebacfff0] [c0001e28] __secondary_start+0x30/0x84 [ 892.281474] [ 892.282959] [eff9fd00] [c0509724] esp_input+0x178/0x334 [ 892.288186] [eff9fd50] [c0519778] xfrm_input+0x77c/0x818 [ 892.293499] [eff9fda0] [c050e344] xfrm4_rcv_encap+0x20/0x30 [ 892.299074] [eff9fdb0] [c04b90c8] ip_local_deliver+0x190/0x408 [ 892.304907] [eff9fde0] [c04b966c] ip_rcv+0x32c/0x898 [ 892.309872] [eff9fe10] [c048b998] __netif_receive_skb+0x27c/0x4e8 [ 892.315966] [eff9fe80] [c048d744] netif_receive_skb+0x4c/0x13c [ 892.321803] [eff9feb0] [c03c28ac] _dpa_rx+0x1a8/0x354 [ 892.326855] [eff9fef0] [c03c2ac4] ingress_rx_default_dqrr+0x6c/0x108 [ 892.333212] [eff9ff10] [c0467ae0] qman_poll_dqrr+0x170/0x1d4 [ 892.338872] [eff9ff40] [c03c153c] dpaa_eth_poll+0x20/0x94 [ 892.344271] [eff9ff60] [c048dbd0] net_rx_action+0x13c/0x1f4 [ 892.349846] [eff9ffa0] [c003d1b8] __do_softirq+0x108/0x1b0 [ 892.355338] [eff9fff0] [c000df58] call_do_softirq+0x14/0x24 [ 892.360910] [e7169950] [c0004868] do_softirq+0xd8/0x104 [ 892.366135] [e7169970] [c003d5a4] irq_exit+0xb8/0xd8 [ 892.371101] [e7169980] [c0004498] do_IRQ+0xa4/0x1b0 [ 892.375979] [e71699b0] [c000fad8] ret_from_except+0x0/0x18 [ 892.381466] [e7169a70] [c0445e74] caam_jr_enqueue+0xf8/0x250 [ 892.387127] [e7169ab0] [c044ad4c] aead_givencrypt+0x6ac/0xa70 [ 892.392873] [e7169b20] [c050a0b8] esp_output+0x2b4/0x570 [ 892.398186] [e7169b80] [c0519b9c] xfrm_output_resume+0x248/0x7c0 [ 892.404194] [e7169bb0] [c050e89c] xfrm4_output_finish+0x18/0x28 [ 892.410113] [e7169bc0] [c050e8f4] xfrm4_output+0x48/0x98 [ 892.415427] [e7169bd0] [c04beac0] ip_local_out+0x48/0x98 [ 892.420740] [e7169be0] [c04bec7c] ip_queue_xmit+0x16c/0x490 [ 892.426314] [e7169c10] [c04d6128] tcp_transmit_skb+0x35c/0x9a4 [ 892.432147] [e7169c70] [c04d6f98] tcp_write_xmit+0x200/0xa04 [ 892.437808] [e7169cc0] [c04c8ccc] tcp_sendmsg+0x994/0xcec [ 892.443213] [e7169d40] [c04eebfc] inet_sendmsg+0xd0/0x164 [ 892.448617] [e7169d70] [c04792f8] sock_sendmsg+0x8c/0xbc [ 892.453931] [e7169e40] [c047aecc] sys_sendto+0xc0/0xfc [ 892.459069] [e7169f10] [c047b934] sys_socketcall+0x110/0x25c [ 892.464729] [e7169f40] [c000f480] ret_from_syscall+0x0/0x3c (b) since the caam_jr_dequeue lock is only used in bh context, then semantically it should use _bh spin_lock types. spin_lock_bh semantics are to disable back-halves, and used when a lock is shared between softirq (bh) context and process and/or h/w IRQ context. Since the lock is only used within softirq context, and this tasklet is atomic, there is no need to do the additional work to disable back halves. This patch adds back-half disabling protection to caam_jr_enqueue spin_locks to fix (a), and drops it from caam_jr_dequeue to fix (b). Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/caam/jr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 53c8c51d5881..93d14070141a 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -63,7 +63,7 @@ static void caam_jr_dequeue(unsigned long devarg) head = ACCESS_ONCE(jrp->head); - spin_lock_bh(&jrp->outlock); + spin_lock(&jrp->outlock); sw_idx = tail = jrp->tail; hw_idx = jrp->out_ring_read_index; @@ -115,7 +115,7 @@ static void caam_jr_dequeue(unsigned long devarg) jrp->tail = tail; } - spin_unlock_bh(&jrp->outlock); + spin_unlock(&jrp->outlock); /* Finally, execute user's callback */ usercall(dev, userdesc, userstatus, userarg); @@ -236,14 +236,14 @@ int caam_jr_enqueue(struct device *dev, u32 *desc, return -EIO; } - spin_lock(&jrp->inplock); + spin_lock_bh(&jrp->inplock); head = jrp->head; tail = ACCESS_ONCE(jrp->tail); if (!rd_reg32(&jrp->rregs->inpring_avail) || CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) { - spin_unlock(&jrp->inplock); + spin_unlock_bh(&jrp->inplock); dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE); return -EBUSY; } @@ -265,7 +265,7 @@ int caam_jr_enqueue(struct device *dev, u32 *desc, wr_reg32(&jrp->rregs->inpring_jobadd, 1); - spin_unlock(&jrp->inplock); + spin_unlock_bh(&jrp->inplock); return 0; } From 95bcaa39053ff518021572ca00ebf626ee8cbaf8 Mon Sep 17 00:00:00 2001 From: Shengzhou Liu Date: Fri, 13 Jul 2012 17:49:21 -0500 Subject: [PATCH 0174/5375] crypto: caam - add backward compatible string sec4.0 In some device trees of previous version, there were string "fsl,sec4.0". To be backward compatible with device trees, we first check "fsl,sec-v4.0", if it fails, then check for "fsl,sec4.0". Signed-off-by: Shengzhou Liu extended to include new hash and rng code, which was omitted from the previous version of this patch during a rebase of the SDK version. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 14 ++++++++++---- drivers/crypto/caam/caamrng.c | 7 +++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 895aaf2bca92..dca3c1904eda 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -1736,8 +1736,11 @@ static void __exit caam_algapi_hash_exit(void) struct caam_hash_alg *t_alg, *n; dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) - return; + if (!dev_node) { + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return; + } pdev = of_find_device_by_node(dev_node); if (!pdev) @@ -1812,8 +1815,11 @@ static int __init caam_algapi_hash_init(void) int i = 0, err = 0; dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) - return -ENODEV; + if (!dev_node) { + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return -ENODEV; + } pdev = of_find_device_by_node(dev_node); if (!pdev) diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index e2bfe161dece..ccedb54317e1 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -284,8 +284,11 @@ static int __init caam_rng_init(void) struct caam_drv_private *priv; dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) - return -ENODEV; + if (!dev_node) { + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return -ENODEV; + } pdev = of_find_device_by_node(dev_node); if (!pdev) From 61bb86bba169507a5f223b94b9176c32c84b4721 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Fri, 13 Jul 2012 17:49:28 -0500 Subject: [PATCH 0175/5375] crypto: caam - set descriptor sharing type to SERIAL SHARE_WAIT, whilst more optimal for association-less crypto, has the ability to start thrashing the CCB descriptor/key caches, given high levels of traffic across multiple security associations (and thus keys). Switch to using the SERIAL sharing type, which prefers the last used CCB for the SA. On a 2-DECO platform such as the P3041, this can improve performance by about 3.7%. Signed-off-by: Kim Phillips Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 8 ++++---- drivers/crypto/caam/caamhash.c | 4 ++-- drivers/crypto/caam/caamrng.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 0c1ea8492eff..6b48295e218b 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -205,7 +205,7 @@ static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, { u32 *key_jump_cmd; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | @@ -302,7 +302,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) desc = ctx->sh_desc_dec; /* aead_decrypt shared descriptor */ - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | @@ -564,7 +564,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, /* ablkcipher_encrypt shared descriptor */ desc = ctx->sh_desc_enc; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); @@ -605,7 +605,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, /* ablkcipher_decrypt shared descriptor */ desc = ctx->sh_desc_dec; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index dca3c1904eda..fbf3fe8b62f0 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -225,7 +225,7 @@ static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) { u32 *key_jump_cmd; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); if (ctx->split_key_len) { /* Skip if already shared */ @@ -311,7 +311,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_update shared descriptor */ desc = ctx->sh_desc_update; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Import context from software */ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index ccedb54317e1..d1939a9539c0 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -193,7 +193,7 @@ static inline void rng_create_sh_desc(struct caam_rng_ctx *ctx) struct device *jrdev = ctx->jrdev; u32 *desc = ctx->sh_desc; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Propagate errors from shared to job descriptor */ append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); From 322cacce0a3c36d3ad89d8836b9ed6fcb06e1a61 Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Thu, 19 Jul 2012 09:42:38 -0500 Subject: [PATCH 0176/5375] powerpc/crypto: rework Kconfig This patch creates a new submenu for the NX cryptographic hardware accelerator and breaks the NX options into their own Kconfig file under drivers/crypto/nx/Kconfig. This will permit additional NX functionality to be easily and more cleanly added in the future without touching drivers/crypto/Makefile|Kconfig. Signed-off-by: Seth Jennings Signed-off-by: Herbert Xu --- arch/powerpc/configs/ppc64_defconfig | 3 ++- arch/powerpc/configs/pseries_defconfig | 3 ++- drivers/crypto/Kconfig | 20 +++++++------------- drivers/crypto/nx/Kconfig | 17 +++++++++++++++++ drivers/crypto/nx/Makefile | 2 +- 5 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 drivers/crypto/nx/Kconfig diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index db27c82e0542..2d9150a1c2ba 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -487,7 +487,8 @@ CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_HW=y -CONFIG_CRYPTO_DEV_NX=m +CONFIG_CRYPTO_DEV_NX=y +CONFIG_CRYPTO_DEV_NX_ENCRYPT=m CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=y diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 1f65b3c9b59a..9f4a9368f51b 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -369,7 +369,8 @@ CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_HW=y -CONFIG_CRYPTO_DEV_NX=m +CONFIG_CRYPTO_DEV_NX=y +CONFIG_CRYPTO_DEV_NX_ENCRYPT=m CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=y diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 7d74d092aa8f..662588a1c41b 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -298,21 +298,15 @@ config CRYPTO_DEV_TEGRA_AES will be called tegra-aes. config CRYPTO_DEV_NX - tristate "Support for Power7+ in-Nest cryptographic acceleration" + bool "Support for IBM Power7+ in-Nest cryptographic acceleration" depends on PPC64 && IBMVIO - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_ECB - select CRYPTO_CCM - select CRYPTO_GCM - select CRYPTO_AUTHENC - select CRYPTO_XCBC - select CRYPTO_SHA256 - select CRYPTO_SHA512 + default n help - Support for Power7+ in-Nest cryptographic acceleration. This - module supports acceleration for AES and SHA2 algorithms. If you - choose 'M' here, this module will be called nx_crypto. + Support for Power7+ in-Nest cryptographic acceleration. + +if CRYPTO_DEV_NX + source "drivers/crypto/nx/Kconfig" +endif config CRYPTO_DEV_UX500 tristate "Driver for ST-Ericsson UX500 crypto hardware acceleration" diff --git a/drivers/crypto/nx/Kconfig b/drivers/crypto/nx/Kconfig new file mode 100644 index 000000000000..dedde535024e --- /dev/null +++ b/drivers/crypto/nx/Kconfig @@ -0,0 +1,17 @@ +config CRYPTO_DEV_NX_ENCRYPT + tristate "Encryption acceleration support" + depends on PPC64 && IBMVIO + default y + select CRYPTO_AES + select CRYPTO_CBC + select CRYPTO_ECB + select CRYPTO_CCM + select CRYPTO_GCM + select CRYPTO_AUTHENC + select CRYPTO_XCBC + select CRYPTO_SHA256 + select CRYPTO_SHA512 + help + Support for Power7+ in-Nest encryption acceleration. This + module supports acceleration for AES and SHA2 algorithms. If you + choose 'M' here, this module will be called nx_crypto. diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile index 411ce59c80d1..7f110e460da3 100644 --- a/drivers/crypto/nx/Makefile +++ b/drivers/crypto/nx/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_CRYPTO_DEV_NX) += nx-crypto.o +obj-$(CONFIG_CRYPTO_DEV_NX_ENCRYPT) += nx-crypto.o nx-crypto-objs := nx.o \ nx_debugfs.o \ nx-aes-cbc.o \ From da29aa8f2ab178903a1ac23ce19442f92be4f09c Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Thu, 19 Jul 2012 09:42:39 -0500 Subject: [PATCH 0177/5375] powerpc/crypto: add compression support to arch vec This patch enables compression engine support in the architecture vector. This causes the Power hypervisor to allow access to the nx comrpession accelerator. Signed-off-by: Seth Jennings Signed-off-by: Herbert Xu --- arch/powerpc/kernel/prom_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 0794a3017b1b..9ec5e5525777 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -705,6 +705,7 @@ static void __init early_cmdline_parse(void) #endif #define OV5_TYPE1_AFFINITY 0x80 /* Type 1 NUMA affinity */ #define OV5_PFO_HW_RNG 0x80 /* PFO Random Number Generator */ +#define OV5_PFO_HW_842 0x40 /* PFO Compression Accelerator */ #define OV5_PFO_HW_ENCR 0x20 /* PFO Encryption Accelerator */ /* Option Vector 6: IBM PAPR hints */ @@ -774,8 +775,7 @@ static unsigned char ibm_architecture_vec[] = { 0, 0, 0, - OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR, - + OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR | OV5_PFO_HW_842, /* option vector 6: IBM PAPR hints */ 4 - 2, /* length */ 0, From 0e16aafb12046e12effbdaab179fbe1a38427ba9 Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Thu, 19 Jul 2012 09:42:40 -0500 Subject: [PATCH 0178/5375] powerpc/crypto: add 842 hardware compression driver This patch adds the driver for interacting with the 842 compression accelerator on IBM Power7+ systems. The device is a child of the Platform Facilities Option (PFO) and shows up as a child of the IBM VIO bus. The compression/decompression API takes the same arguments as existing compression methods like lzo and deflate. The 842 hardware operates on 4K hardware pages and the driver breaks up input on 4K boundaries to submit it to the hardware accelerator. Signed-off-by: Robert Jennings Signed-off-by: Seth Jennings Signed-off-by: Herbert Xu --- MAINTAINERS | 6 + drivers/crypto/nx/Kconfig | 9 + drivers/crypto/nx/Makefile | 3 + drivers/crypto/nx/nx-842.c | 1615 ++++++++++++++++++++++++++++++++++++ include/linux/nx842.h | 11 + 5 files changed, 1644 insertions(+) create mode 100644 drivers/crypto/nx/nx-842.c create mode 100644 include/linux/nx842.h diff --git a/MAINTAINERS b/MAINTAINERS index 6720018bc674..f2dfb204c8e9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3415,6 +3415,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git S: Maintained F: arch/ia64/ +IBM Power 842 compression accelerator +M: Robert Jennings +S: Supported +F: drivers/crypto/nx/nx-842.c +F: include/linux/nx842.h + IBM Power Linux RAID adapter M: Brian King S: Supported diff --git a/drivers/crypto/nx/Kconfig b/drivers/crypto/nx/Kconfig index dedde535024e..f82616621ae1 100644 --- a/drivers/crypto/nx/Kconfig +++ b/drivers/crypto/nx/Kconfig @@ -15,3 +15,12 @@ config CRYPTO_DEV_NX_ENCRYPT Support for Power7+ in-Nest encryption acceleration. This module supports acceleration for AES and SHA2 algorithms. If you choose 'M' here, this module will be called nx_crypto. + +config CRYPTO_DEV_NX_COMPRESS + tristate "Compression acceleration support" + depends on PPC64 && IBMVIO + default y + help + Support for Power7+ in-Nest compression acceleration. This + module supports acceleration for AES and SHA2 algorithms. If you + choose 'M' here, this module will be called nx_compress. diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile index 7f110e460da3..bb770ea45ce9 100644 --- a/drivers/crypto/nx/Makefile +++ b/drivers/crypto/nx/Makefile @@ -9,3 +9,6 @@ nx-crypto-objs := nx.o \ nx-aes-xcbc.o \ nx-sha256.o \ nx-sha512.o + +obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o +nx-compress-objs := nx-842.o diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c new file mode 100644 index 000000000000..9da0fb2d3f64 --- /dev/null +++ b/drivers/crypto/nx/nx-842.c @@ -0,0 +1,1615 @@ +/* + * Driver for IBM Power 842 compression accelerator + * + * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corporation, 2012 + * + * Authors: Robert Jennings + * Seth Jennings + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "nx_csbcpb.h" /* struct nx_csbcpb */ + +#define MODULE_NAME "nx-compress" +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Jennings "); +MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors"); + +#define SHIFT_4K 12 +#define SHIFT_64K 16 +#define SIZE_4K (1UL << SHIFT_4K) +#define SIZE_64K (1UL << SHIFT_64K) + +/* IO buffer must be 128 byte aligned */ +#define IO_BUFFER_ALIGN 128 + +struct nx842_header { + int blocks_nr; /* number of compressed blocks */ + int offset; /* offset of the first block (from beginning of header) */ + int sizes[0]; /* size of compressed blocks */ +}; + +static inline int nx842_header_size(const struct nx842_header *hdr) +{ + return sizeof(struct nx842_header) + + hdr->blocks_nr * sizeof(hdr->sizes[0]); +} + +/* Macros for fields within nx_csbcpb */ +/* Check the valid bit within the csbcpb valid field */ +#define NX842_CSBCBP_VALID_CHK(x) (x & BIT_MASK(7)) + +/* CE macros operate on the completion_extension field bits in the csbcpb. + * CE0 0=full completion, 1=partial completion + * CE1 0=CE0 indicates completion, 1=termination (output may be modified) + * CE2 0=processed_bytes is source bytes, 1=processed_bytes is target bytes */ +#define NX842_CSBCPB_CE0(x) (x & BIT_MASK(7)) +#define NX842_CSBCPB_CE1(x) (x & BIT_MASK(6)) +#define NX842_CSBCPB_CE2(x) (x & BIT_MASK(5)) + +/* The NX unit accepts data only on 4K page boundaries */ +#define NX842_HW_PAGE_SHIFT SHIFT_4K +#define NX842_HW_PAGE_SIZE (ASM_CONST(1) << NX842_HW_PAGE_SHIFT) +#define NX842_HW_PAGE_MASK (~(NX842_HW_PAGE_SIZE-1)) + +enum nx842_status { + UNAVAILABLE, + AVAILABLE +}; + +struct ibm_nx842_counters { + atomic64_t comp_complete; + atomic64_t comp_failed; + atomic64_t decomp_complete; + atomic64_t decomp_failed; + atomic64_t swdecomp; + atomic64_t comp_times[32]; + atomic64_t decomp_times[32]; +}; + +static struct nx842_devdata { + struct vio_dev *vdev; + struct device *dev; + struct ibm_nx842_counters *counters; + unsigned int max_sg_len; + unsigned int max_sync_size; + unsigned int max_sync_sg; + enum nx842_status status; +} __rcu *devdata; +static DEFINE_SPINLOCK(devdata_mutex); + +#define NX842_COUNTER_INC(_x) \ +static inline void nx842_inc_##_x( \ + const struct nx842_devdata *dev) { \ + if (dev) \ + atomic64_inc(&dev->counters->_x); \ +} +NX842_COUNTER_INC(comp_complete); +NX842_COUNTER_INC(comp_failed); +NX842_COUNTER_INC(decomp_complete); +NX842_COUNTER_INC(decomp_failed); +NX842_COUNTER_INC(swdecomp); + +#define NX842_HIST_SLOTS 16 + +static void ibm_nx842_incr_hist(atomic64_t *times, unsigned int time) +{ + int bucket = fls(time); + + if (bucket) + bucket = min((NX842_HIST_SLOTS - 1), bucket - 1); + + atomic64_inc(×[bucket]); +} + +/* NX unit operation flags */ +#define NX842_OP_COMPRESS 0x0 +#define NX842_OP_CRC 0x1 +#define NX842_OP_DECOMPRESS 0x2 +#define NX842_OP_COMPRESS_CRC (NX842_OP_COMPRESS | NX842_OP_CRC) +#define NX842_OP_DECOMPRESS_CRC (NX842_OP_DECOMPRESS | NX842_OP_CRC) +#define NX842_OP_ASYNC (1<<23) +#define NX842_OP_NOTIFY (1<<22) +#define NX842_OP_NOTIFY_INT(x) ((x & 0xff)<<8) + +static unsigned long nx842_get_desired_dma(struct vio_dev *viodev) +{ + /* No use of DMA mappings within the driver. */ + return 0; +} + +struct nx842_slentry { + unsigned long ptr; /* Absolute address (use virt_to_abs()) */ + unsigned long len; +}; + +/* pHyp scatterlist entry */ +struct nx842_scatterlist { + int entry_nr; /* number of slentries */ + struct nx842_slentry *entries; /* ptr to array of slentries */ +}; + +/* Does not include sizeof(entry_nr) in the size */ +static inline unsigned long nx842_get_scatterlist_size( + struct nx842_scatterlist *sl) +{ + return sl->entry_nr * sizeof(struct nx842_slentry); +} + +static int nx842_build_scatterlist(unsigned long buf, int len, + struct nx842_scatterlist *sl) +{ + unsigned long nextpage; + struct nx842_slentry *entry; + + sl->entry_nr = 0; + + entry = sl->entries; + while (len) { + entry->ptr = virt_to_abs(buf); + nextpage = ALIGN(buf + 1, NX842_HW_PAGE_SIZE); + if (nextpage < buf + len) { + /* we aren't at the end yet */ + if (IS_ALIGNED(buf, NX842_HW_PAGE_SIZE)) + /* we are in the middle (or beginning) */ + entry->len = NX842_HW_PAGE_SIZE; + else + /* we are at the beginning */ + entry->len = nextpage - buf; + } else { + /* at the end */ + entry->len = len; + } + + len -= entry->len; + buf += entry->len; + sl->entry_nr++; + entry++; + } + + return 0; +} + +/* + * Working memory for software decompression + */ +struct sw842_fifo { + union { + char f8[256][8]; + char f4[512][4]; + }; + char f2[256][2]; + unsigned char f84_full; + unsigned char f2_full; + unsigned char f8_count; + unsigned char f2_count; + unsigned int f4_count; +}; + +/* + * Working memory for crypto API + */ +struct nx842_workmem { + char bounce[PAGE_SIZE]; /* bounce buffer for decompression input */ + union { + /* hardware working memory */ + struct { + /* scatterlist */ + char slin[SIZE_4K]; + char slout[SIZE_4K]; + /* coprocessor status/parameter block */ + struct nx_csbcpb csbcpb; + }; + /* software working memory */ + struct sw842_fifo swfifo; /* software decompression fifo */ + }; +}; + +int nx842_get_workmem_size(void) +{ + return sizeof(struct nx842_workmem) + NX842_HW_PAGE_SIZE; +} +EXPORT_SYMBOL_GPL(nx842_get_workmem_size); + +int nx842_get_workmem_size_aligned(void) +{ + return sizeof(struct nx842_workmem); +} +EXPORT_SYMBOL_GPL(nx842_get_workmem_size_aligned); + +static int nx842_validate_result(struct device *dev, + struct cop_status_block *csb) +{ + /* The csb must be valid after returning from vio_h_cop_sync */ + if (!NX842_CSBCBP_VALID_CHK(csb->valid)) { + dev_err(dev, "%s: cspcbp not valid upon completion.\n", + __func__); + dev_dbg(dev, "valid:0x%02x cs:0x%02x cc:0x%02x ce:0x%02x\n", + csb->valid, + csb->crb_seq_number, + csb->completion_code, + csb->completion_extension); + dev_dbg(dev, "processed_bytes:%d address:0x%016lx\n", + csb->processed_byte_count, + (unsigned long)csb->address); + return -EIO; + } + + /* Check return values from the hardware in the CSB */ + switch (csb->completion_code) { + case 0: /* Completed without error */ + break; + case 64: /* Target bytes > Source bytes during compression */ + case 13: /* Output buffer too small */ + dev_dbg(dev, "%s: Compression output larger than input\n", + __func__); + return -ENOSPC; + case 66: /* Input data contains an illegal template field */ + case 67: /* Template indicates data past the end of the input stream */ + dev_dbg(dev, "%s: Bad data for decompression (code:%d)\n", + __func__, csb->completion_code); + return -EINVAL; + default: + dev_dbg(dev, "%s: Unspecified error (code:%d)\n", + __func__, csb->completion_code); + return -EIO; + } + + /* Hardware sanity check */ + if (!NX842_CSBCPB_CE2(csb->completion_extension)) { + dev_err(dev, "%s: No error returned by hardware, but " + "data returned is unusable, contact support.\n" + "(Additional info: csbcbp->processed bytes " + "does not specify processed bytes for the " + "target buffer.)\n", __func__); + return -EIO; + } + + return 0; +} + +/** + * nx842_compress - Compress data using the 842 algorithm + * + * Compression provide by the NX842 coprocessor on IBM Power systems. + * The input buffer is compressed and the result is stored in the + * provided output buffer. + * + * Upon return from this function @outlen contains the length of the + * compressed data. If there is an error then @outlen will be 0 and an + * error will be specified by the return code from this function. + * + * @in: Pointer to input buffer, must be page aligned + * @inlen: Length of input buffer, must be PAGE_SIZE + * @out: Pointer to output buffer + * @outlen: Length of output buffer + * @wrkmem: ptr to buffer for working memory, size determined by + * nx842_get_workmem_size() + * + * Returns: + * 0 Success, output of length @outlen stored in the buffer at @out + * -ENOMEM Unable to allocate internal buffers + * -ENOSPC Output buffer is to small + * -EMSGSIZE XXX Difficult to describe this limitation + * -EIO Internal error + * -ENODEV Hardware unavailable + */ +int nx842_compress(const unsigned char *in, unsigned int inlen, + unsigned char *out, unsigned int *outlen, void *wmem) +{ + struct nx842_header *hdr; + struct nx842_devdata *local_devdata; + struct device *dev = NULL; + struct nx842_workmem *workmem; + struct nx842_scatterlist slin, slout; + struct nx_csbcpb *csbcpb; + int ret = 0, max_sync_size, i, bytesleft, size, hdrsize; + unsigned long inbuf, outbuf, padding; + struct vio_pfo_op op = { + .done = NULL, + .handle = 0, + .timeout = 0, + }; + unsigned long start_time = get_tb(); + + /* + * Make sure input buffer is 64k page aligned. This is assumed since + * this driver is designed for page compression only (for now). This + * is very nice since we can now use direct DDE(s) for the input and + * the alignment is guaranteed. + */ + inbuf = (unsigned long)in; + if (!IS_ALIGNED(inbuf, PAGE_SIZE) || inlen != PAGE_SIZE) + return -EINVAL; + + rcu_read_lock(); + local_devdata = rcu_dereference(devdata); + if (!local_devdata || !local_devdata->dev) { + rcu_read_unlock(); + return -ENODEV; + } + max_sync_size = local_devdata->max_sync_size; + dev = local_devdata->dev; + + /* Create the header */ + hdr = (struct nx842_header *)out; + hdr->blocks_nr = PAGE_SIZE / max_sync_size; + hdrsize = nx842_header_size(hdr); + outbuf = (unsigned long)out + hdrsize; + bytesleft = *outlen - hdrsize; + + /* Init scatterlist */ + workmem = (struct nx842_workmem *)ALIGN((unsigned long)wmem, + NX842_HW_PAGE_SIZE); + slin.entries = (struct nx842_slentry *)workmem->slin; + slout.entries = (struct nx842_slentry *)workmem->slout; + + /* Init operation */ + op.flags = NX842_OP_COMPRESS; + csbcpb = &workmem->csbcpb; + memset(csbcpb, 0, sizeof(*csbcpb)); + op.csbcpb = virt_to_abs(csbcpb); + op.out = virt_to_abs(slout.entries); + + for (i = 0; i < hdr->blocks_nr; i++) { + /* + * Aligning the output blocks to 128 bytes does waste space, + * but it prevents the need for bounce buffers and memory + * copies. It also simplifies the code a lot. In the worst + * case (64k page, 4k max_sync_size), you lose up to + * (128*16)/64k = ~3% the compression factor. For 64k + * max_sync_size, the loss would be at most 128/64k = ~0.2%. + */ + padding = ALIGN(outbuf, IO_BUFFER_ALIGN) - outbuf; + outbuf += padding; + bytesleft -= padding; + if (i == 0) + /* save offset into first block in header */ + hdr->offset = padding + hdrsize; + + if (bytesleft <= 0) { + ret = -ENOSPC; + goto unlock; + } + + /* + * NOTE: If the default max_sync_size is changed from 4k + * to 64k, remove the "likely" case below, since a + * scatterlist will always be needed. + */ + if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) { + /* Create direct DDE */ + op.in = virt_to_abs(inbuf); + op.inlen = max_sync_size; + + } else { + /* Create indirect DDE (scatterlist) */ + nx842_build_scatterlist(inbuf, max_sync_size, &slin); + op.in = virt_to_abs(slin.entries); + op.inlen = -nx842_get_scatterlist_size(&slin); + } + + /* + * If max_sync_size != NX842_HW_PAGE_SIZE, an indirect + * DDE is required for the outbuf. + * If max_sync_size == NX842_HW_PAGE_SIZE, outbuf must + * also be page aligned (1 in 128/4k=32 chance) in order + * to use a direct DDE. + * This is unlikely, just use an indirect DDE always. + */ + nx842_build_scatterlist(outbuf, + min(bytesleft, max_sync_size), &slout); + /* op.out set before loop */ + op.outlen = -nx842_get_scatterlist_size(&slout); + + /* Send request to pHyp */ + ret = vio_h_cop_sync(local_devdata->vdev, &op); + + /* Check for pHyp error */ + if (ret) { + dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n", + __func__, ret, op.hcall_err); + ret = -EIO; + goto unlock; + } + + /* Check for hardware error */ + ret = nx842_validate_result(dev, &csbcpb->csb); + if (ret && ret != -ENOSPC) + goto unlock; + + /* Handle incompressible data */ + if (unlikely(ret == -ENOSPC)) { + if (bytesleft < max_sync_size) { + /* + * Not enough space left in the output buffer + * to store uncompressed block + */ + goto unlock; + } else { + /* Store incompressible block */ + memcpy((void *)outbuf, (void *)inbuf, + max_sync_size); + hdr->sizes[i] = -max_sync_size; + outbuf += max_sync_size; + bytesleft -= max_sync_size; + /* Reset ret, incompressible data handled */ + ret = 0; + } + } else { + /* Normal case, compression was successful */ + size = csbcpb->csb.processed_byte_count; + dev_dbg(dev, "%s: processed_bytes=%d\n", + __func__, size); + hdr->sizes[i] = size; + outbuf += size; + bytesleft -= size; + } + + inbuf += max_sync_size; + } + + *outlen = (unsigned int)(outbuf - (unsigned long)out); + +unlock: + if (ret) + nx842_inc_comp_failed(local_devdata); + else { + nx842_inc_comp_complete(local_devdata); + ibm_nx842_incr_hist(local_devdata->counters->comp_times, + (get_tb() - start_time) / tb_ticks_per_usec); + } + rcu_read_unlock(); + return ret; +} +EXPORT_SYMBOL_GPL(nx842_compress); + +static int sw842_decompress(const unsigned char *, int, unsigned char *, int *, + const void *); + +/** + * nx842_decompress - Decompress data using the 842 algorithm + * + * Decompression provide by the NX842 coprocessor on IBM Power systems. + * The input buffer is decompressed and the result is stored in the + * provided output buffer. The size allocated to the output buffer is + * provided by the caller of this function in @outlen. Upon return from + * this function @outlen contains the length of the decompressed data. + * If there is an error then @outlen will be 0 and an error will be + * specified by the return code from this function. + * + * @in: Pointer to input buffer, will use bounce buffer if not 128 byte + * aligned + * @inlen: Length of input buffer + * @out: Pointer to output buffer, must be page aligned + * @outlen: Length of output buffer, must be PAGE_SIZE + * @wrkmem: ptr to buffer for working memory, size determined by + * nx842_get_workmem_size() + * + * Returns: + * 0 Success, output of length @outlen stored in the buffer at @out + * -ENODEV Hardware decompression device is unavailable + * -ENOMEM Unable to allocate internal buffers + * -ENOSPC Output buffer is to small + * -EINVAL Bad input data encountered when attempting decompress + * -EIO Internal error + */ +int nx842_decompress(const unsigned char *in, unsigned int inlen, + unsigned char *out, unsigned int *outlen, void *wmem) +{ + struct nx842_header *hdr; + struct nx842_devdata *local_devdata; + struct device *dev = NULL; + struct nx842_workmem *workmem; + struct nx842_scatterlist slin, slout; + struct nx_csbcpb *csbcpb; + int ret = 0, i, size, max_sync_size; + unsigned long inbuf, outbuf; + struct vio_pfo_op op = { + .done = NULL, + .handle = 0, + .timeout = 0, + }; + unsigned long start_time = get_tb(); + + /* Ensure page alignment and size */ + outbuf = (unsigned long)out; + if (!IS_ALIGNED(outbuf, PAGE_SIZE) || *outlen != PAGE_SIZE) + return -EINVAL; + + rcu_read_lock(); + local_devdata = rcu_dereference(devdata); + if (local_devdata) + dev = local_devdata->dev; + + /* Get header */ + hdr = (struct nx842_header *)in; + + workmem = (struct nx842_workmem *)ALIGN((unsigned long)wmem, + NX842_HW_PAGE_SIZE); + + inbuf = (unsigned long)in + hdr->offset; + if (likely(!IS_ALIGNED(inbuf, IO_BUFFER_ALIGN))) { + /* Copy block(s) into bounce buffer for alignment */ + memcpy(workmem->bounce, in + hdr->offset, inlen - hdr->offset); + inbuf = (unsigned long)workmem->bounce; + } + + /* Init scatterlist */ + slin.entries = (struct nx842_slentry *)workmem->slin; + slout.entries = (struct nx842_slentry *)workmem->slout; + + /* Init operation */ + op.flags = NX842_OP_DECOMPRESS; + csbcpb = &workmem->csbcpb; + memset(csbcpb, 0, sizeof(*csbcpb)); + op.csbcpb = virt_to_abs(csbcpb); + + /* + * max_sync_size may have changed since compression, + * so we can't read it from the device info. We need + * to derive it from hdr->blocks_nr. + */ + max_sync_size = PAGE_SIZE / hdr->blocks_nr; + + for (i = 0; i < hdr->blocks_nr; i++) { + /* Skip padding */ + inbuf = ALIGN(inbuf, IO_BUFFER_ALIGN); + + if (hdr->sizes[i] < 0) { + /* Negative sizes indicate uncompressed data blocks */ + size = abs(hdr->sizes[i]); + memcpy((void *)outbuf, (void *)inbuf, size); + outbuf += size; + inbuf += size; + continue; + } + + if (!dev) + goto sw; + + /* + * The better the compression, the more likely the "likely" + * case becomes. + */ + if (likely((inbuf & NX842_HW_PAGE_MASK) == + ((inbuf + hdr->sizes[i] - 1) & NX842_HW_PAGE_MASK))) { + /* Create direct DDE */ + op.in = virt_to_abs(inbuf); + op.inlen = hdr->sizes[i]; + } else { + /* Create indirect DDE (scatterlist) */ + nx842_build_scatterlist(inbuf, hdr->sizes[i] , &slin); + op.in = virt_to_abs(slin.entries); + op.inlen = -nx842_get_scatterlist_size(&slin); + } + + /* + * NOTE: If the default max_sync_size is changed from 4k + * to 64k, remove the "likely" case below, since a + * scatterlist will always be needed. + */ + if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) { + /* Create direct DDE */ + op.out = virt_to_abs(outbuf); + op.outlen = max_sync_size; + } else { + /* Create indirect DDE (scatterlist) */ + nx842_build_scatterlist(outbuf, max_sync_size, &slout); + op.out = virt_to_abs(slout.entries); + op.outlen = -nx842_get_scatterlist_size(&slout); + } + + /* Send request to pHyp */ + ret = vio_h_cop_sync(local_devdata->vdev, &op); + + /* Check for pHyp error */ + if (ret) { + dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n", + __func__, ret, op.hcall_err); + dev = NULL; + goto sw; + } + + /* Check for hardware error */ + ret = nx842_validate_result(dev, &csbcpb->csb); + if (ret) { + dev = NULL; + goto sw; + } + + /* HW decompression success */ + inbuf += hdr->sizes[i]; + outbuf += csbcpb->csb.processed_byte_count; + continue; + +sw: + /* software decompression */ + size = max_sync_size; + ret = sw842_decompress( + (unsigned char *)inbuf, hdr->sizes[i], + (unsigned char *)outbuf, &size, wmem); + if (ret) + pr_debug("%s: sw842_decompress failed with %d\n", + __func__, ret); + + if (ret) { + if (ret != -ENOSPC && ret != -EINVAL && + ret != -EMSGSIZE) + ret = -EIO; + goto unlock; + } + + /* SW decompression success */ + inbuf += hdr->sizes[i]; + outbuf += size; + } + + *outlen = (unsigned int)(outbuf - (unsigned long)out); + +unlock: + if (ret) + /* decompress fail */ + nx842_inc_decomp_failed(local_devdata); + else { + if (!dev) + /* software decompress */ + nx842_inc_swdecomp(local_devdata); + nx842_inc_decomp_complete(local_devdata); + ibm_nx842_incr_hist(local_devdata->counters->decomp_times, + (get_tb() - start_time) / tb_ticks_per_usec); + } + + rcu_read_unlock(); + return ret; +} +EXPORT_SYMBOL_GPL(nx842_decompress); + +/** + * nx842_OF_set_defaults -- Set default (disabled) values for devdata + * + * @devdata - struct nx842_devdata to update + * + * Returns: + * 0 on success + * -ENOENT if @devdata ptr is NULL + */ +static int nx842_OF_set_defaults(struct nx842_devdata *devdata) +{ + if (devdata) { + devdata->max_sync_size = 0; + devdata->max_sync_sg = 0; + devdata->max_sg_len = 0; + devdata->status = UNAVAILABLE; + return 0; + } else + return -ENOENT; +} + +/** + * nx842_OF_upd_status -- Update the device info from OF status prop + * + * The status property indicates if the accelerator is enabled. If the + * device is in the OF tree it indicates that the hardware is present. + * The status field indicates if the device is enabled when the status + * is 'okay'. Otherwise the device driver will be disabled. + * + * @devdata - struct nx842_devdata to update + * @prop - struct property point containing the maxsyncop for the update + * + * Returns: + * 0 - Device is available + * -EINVAL - Device is not available + */ +static int nx842_OF_upd_status(struct nx842_devdata *devdata, + struct property *prop) { + int ret = 0; + const char *status = (const char *)prop->value; + + if (!strncmp(status, "okay", (size_t)prop->length)) { + devdata->status = AVAILABLE; + } else { + dev_info(devdata->dev, "%s: status '%s' is not 'okay'\n", + __func__, status); + devdata->status = UNAVAILABLE; + } + + return ret; +} + +/** + * nx842_OF_upd_maxsglen -- Update the device info from OF maxsglen prop + * + * Definition of the 'ibm,max-sg-len' OF property: + * This field indicates the maximum byte length of a scatter list + * for the platform facility. It is a single cell encoded as with encode-int. + * + * Example: + * # od -x ibm,max-sg-len + * 0000000 0000 0ff0 + * + * In this example, the maximum byte length of a scatter list is + * 0x0ff0 (4,080). + * + * @devdata - struct nx842_devdata to update + * @prop - struct property point containing the maxsyncop for the update + * + * Returns: + * 0 on success + * -EINVAL on failure + */ +static int nx842_OF_upd_maxsglen(struct nx842_devdata *devdata, + struct property *prop) { + int ret = 0; + const int *maxsglen = prop->value; + + if (prop->length != sizeof(*maxsglen)) { + dev_err(devdata->dev, "%s: unexpected format for ibm,max-sg-len property\n", __func__); + dev_dbg(devdata->dev, "%s: ibm,max-sg-len is %d bytes long, expected %lu bytes\n", __func__, + prop->length, sizeof(*maxsglen)); + ret = -EINVAL; + } else { + devdata->max_sg_len = (unsigned int)min(*maxsglen, + (int)NX842_HW_PAGE_SIZE); + } + + return ret; +} + +/** + * nx842_OF_upd_maxsyncop -- Update the device info from OF maxsyncop prop + * + * Definition of the 'ibm,max-sync-cop' OF property: + * Two series of cells. The first series of cells represents the maximums + * that can be synchronously compressed. The second series of cells + * represents the maximums that can be synchronously decompressed. + * 1. The first cell in each series contains the count of the number of + * data length, scatter list elements pairs that follow – each being + * of the form + * a. One cell data byte length + * b. One cell total number of scatter list elements + * + * Example: + * # od -x ibm,max-sync-cop + * 0000000 0000 0001 0000 1000 0000 01fe 0000 0001 + * 0000020 0000 1000 0000 01fe + * + * In this example, compression supports 0x1000 (4,096) data byte length + * and 0x1fe (510) total scatter list elements. Decompression supports + * 0x1000 (4,096) data byte length and 0x1f3 (510) total scatter list + * elements. + * + * @devdata - struct nx842_devdata to update + * @prop - struct property point containing the maxsyncop for the update + * + * Returns: + * 0 on success + * -EINVAL on failure + */ +static int nx842_OF_upd_maxsyncop(struct nx842_devdata *devdata, + struct property *prop) { + int ret = 0; + const struct maxsynccop_t { + int comp_elements; + int comp_data_limit; + int comp_sg_limit; + int decomp_elements; + int decomp_data_limit; + int decomp_sg_limit; + } *maxsynccop; + + if (prop->length != sizeof(*maxsynccop)) { + dev_err(devdata->dev, "%s: unexpected format for ibm,max-sync-cop property\n", __func__); + dev_dbg(devdata->dev, "%s: ibm,max-sync-cop is %d bytes long, expected %lu bytes\n", __func__, prop->length, + sizeof(*maxsynccop)); + ret = -EINVAL; + goto out; + } + + maxsynccop = (const struct maxsynccop_t *)prop->value; + + /* Use one limit rather than separate limits for compression and + * decompression. Set a maximum for this so as not to exceed the + * size that the header can support and round the value down to + * the hardware page size (4K) */ + devdata->max_sync_size = + (unsigned int)min(maxsynccop->comp_data_limit, + maxsynccop->decomp_data_limit); + + devdata->max_sync_size = min_t(unsigned int, devdata->max_sync_size, + SIZE_64K); + + if (devdata->max_sync_size < SIZE_4K) { + dev_err(devdata->dev, "%s: hardware max data size (%u) is " + "less than the driver minimum, unable to use " + "the hardware device\n", + __func__, devdata->max_sync_size); + ret = -EINVAL; + goto out; + } + + devdata->max_sync_sg = (unsigned int)min(maxsynccop->comp_sg_limit, + maxsynccop->decomp_sg_limit); + if (devdata->max_sync_sg < 1) { + dev_err(devdata->dev, "%s: hardware max sg size (%u) is " + "less than the driver minimum, unable to use " + "the hardware device\n", + __func__, devdata->max_sync_sg); + ret = -EINVAL; + goto out; + } + +out: + return ret; +} + +/** + * + * nx842_OF_upd -- Handle OF properties updates for the device. + * + * Set all properties from the OF tree. Optionally, a new property + * can be provided by the @new_prop pointer to overwrite an existing value. + * The device will remain disabled until all values are valid, this function + * will return an error for updates unless all values are valid. + * + * @new_prop: If not NULL, this property is being updated. If NULL, update + * all properties from the current values in the OF tree. + * + * Returns: + * 0 - Success + * -ENOMEM - Could not allocate memory for new devdata structure + * -EINVAL - property value not found, new_prop is not a recognized + * property for the device or property value is not valid. + * -ENODEV - Device is not available + */ +static int nx842_OF_upd(struct property *new_prop) +{ + struct nx842_devdata *old_devdata = NULL; + struct nx842_devdata *new_devdata = NULL; + struct device_node *of_node = NULL; + struct property *status = NULL; + struct property *maxsglen = NULL; + struct property *maxsyncop = NULL; + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&devdata_mutex, flags); + old_devdata = rcu_dereference_check(devdata, + lockdep_is_held(&devdata_mutex)); + if (old_devdata) + of_node = old_devdata->dev->of_node; + + if (!old_devdata || !of_node) { + pr_err("%s: device is not available\n", __func__); + spin_unlock_irqrestore(&devdata_mutex, flags); + return -ENODEV; + } + + new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS); + if (!new_devdata) { + dev_err(old_devdata->dev, "%s: Could not allocate memory for device data\n", __func__); + ret = -ENOMEM; + goto error_out; + } + + memcpy(new_devdata, old_devdata, sizeof(*old_devdata)); + new_devdata->counters = old_devdata->counters; + + /* Set ptrs for existing properties */ + status = of_find_property(of_node, "status", NULL); + maxsglen = of_find_property(of_node, "ibm,max-sg-len", NULL); + maxsyncop = of_find_property(of_node, "ibm,max-sync-cop", NULL); + if (!status || !maxsglen || !maxsyncop) { + dev_err(old_devdata->dev, "%s: Could not locate device properties\n", __func__); + ret = -EINVAL; + goto error_out; + } + + /* Set ptr to new property if provided */ + if (new_prop) { + /* Single property */ + if (!strncmp(new_prop->name, "status", new_prop->length)) { + status = new_prop; + + } else if (!strncmp(new_prop->name, "ibm,max-sg-len", + new_prop->length)) { + maxsglen = new_prop; + + } else if (!strncmp(new_prop->name, "ibm,max-sync-cop", + new_prop->length)) { + maxsyncop = new_prop; + + } else { + /* + * Skip the update, the property being updated + * has no impact. + */ + goto out; + } + } + + /* Perform property updates */ + ret = nx842_OF_upd_status(new_devdata, status); + if (ret) + goto error_out; + + ret = nx842_OF_upd_maxsglen(new_devdata, maxsglen); + if (ret) + goto error_out; + + ret = nx842_OF_upd_maxsyncop(new_devdata, maxsyncop); + if (ret) + goto error_out; + +out: + dev_info(old_devdata->dev, "%s: max_sync_size new:%u old:%u\n", + __func__, new_devdata->max_sync_size, + old_devdata->max_sync_size); + dev_info(old_devdata->dev, "%s: max_sync_sg new:%u old:%u\n", + __func__, new_devdata->max_sync_sg, + old_devdata->max_sync_sg); + dev_info(old_devdata->dev, "%s: max_sg_len new:%u old:%u\n", + __func__, new_devdata->max_sg_len, + old_devdata->max_sg_len); + + rcu_assign_pointer(devdata, new_devdata); + spin_unlock_irqrestore(&devdata_mutex, flags); + synchronize_rcu(); + dev_set_drvdata(new_devdata->dev, new_devdata); + kfree(old_devdata); + return 0; + +error_out: + if (new_devdata) { + dev_info(old_devdata->dev, "%s: device disabled\n", __func__); + nx842_OF_set_defaults(new_devdata); + rcu_assign_pointer(devdata, new_devdata); + spin_unlock_irqrestore(&devdata_mutex, flags); + synchronize_rcu(); + dev_set_drvdata(new_devdata->dev, new_devdata); + kfree(old_devdata); + } else { + dev_err(old_devdata->dev, "%s: could not update driver from hardware\n", __func__); + spin_unlock_irqrestore(&devdata_mutex, flags); + } + + if (!ret) + ret = -EINVAL; + return ret; +} + +/** + * nx842_OF_notifier - Process updates to OF properties for the device + * + * @np: notifier block + * @action: notifier action + * @update: struct pSeries_reconfig_prop_update pointer if action is + * PSERIES_UPDATE_PROPERTY + * + * Returns: + * NOTIFY_OK on success + * NOTIFY_BAD encoded with error number on failure, use + * notifier_to_errno() to decode this value + */ +static int nx842_OF_notifier(struct notifier_block *np, + unsigned long action, + void *update) +{ + struct pSeries_reconfig_prop_update *upd; + struct nx842_devdata *local_devdata; + struct device_node *node = NULL; + + upd = (struct pSeries_reconfig_prop_update *)update; + + rcu_read_lock(); + local_devdata = rcu_dereference(devdata); + if (local_devdata) + node = local_devdata->dev->of_node; + + if (local_devdata && + action == PSERIES_UPDATE_PROPERTY && + !strcmp(upd->node->name, node->name)) { + rcu_read_unlock(); + nx842_OF_upd(upd->property); + } else + rcu_read_unlock(); + + return NOTIFY_OK; +} + +static struct notifier_block nx842_of_nb = { + .notifier_call = nx842_OF_notifier, +}; + +#define nx842_counter_read(_name) \ +static ssize_t nx842_##_name##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) { \ + struct nx842_devdata *local_devdata; \ + int p = 0; \ + rcu_read_lock(); \ + local_devdata = rcu_dereference(devdata); \ + if (local_devdata) \ + p = snprintf(buf, PAGE_SIZE, "%ld\n", \ + atomic64_read(&local_devdata->counters->_name)); \ + rcu_read_unlock(); \ + return p; \ +} + +#define NX842DEV_COUNTER_ATTR_RO(_name) \ + nx842_counter_read(_name); \ + static struct device_attribute dev_attr_##_name = __ATTR(_name, \ + 0444, \ + nx842_##_name##_show,\ + NULL); + +NX842DEV_COUNTER_ATTR_RO(comp_complete); +NX842DEV_COUNTER_ATTR_RO(comp_failed); +NX842DEV_COUNTER_ATTR_RO(decomp_complete); +NX842DEV_COUNTER_ATTR_RO(decomp_failed); +NX842DEV_COUNTER_ATTR_RO(swdecomp); + +static ssize_t nx842_timehist_show(struct device *, + struct device_attribute *, char *); + +static struct device_attribute dev_attr_comp_times = __ATTR(comp_times, 0444, + nx842_timehist_show, NULL); +static struct device_attribute dev_attr_decomp_times = __ATTR(decomp_times, + 0444, nx842_timehist_show, NULL); + +static ssize_t nx842_timehist_show(struct device *dev, + struct device_attribute *attr, char *buf) { + char *p = buf; + struct nx842_devdata *local_devdata; + atomic64_t *times; + int bytes_remain = PAGE_SIZE; + int bytes; + int i; + + rcu_read_lock(); + local_devdata = rcu_dereference(devdata); + if (!local_devdata) { + rcu_read_unlock(); + return 0; + } + + if (attr == &dev_attr_comp_times) + times = local_devdata->counters->comp_times; + else if (attr == &dev_attr_decomp_times) + times = local_devdata->counters->decomp_times; + else { + rcu_read_unlock(); + return 0; + } + + for (i = 0; i < (NX842_HIST_SLOTS - 2); i++) { + bytes = snprintf(p, bytes_remain, "%u-%uus:\t%ld\n", + i ? (2<<(i-1)) : 0, (2<vdev != NULL) { + dev_err(&viodev->dev, "%s: Attempt to register more than one instance of the hardware\n", __func__); + ret = -1; + goto error_unlock; + } + + dev_set_drvdata(&viodev->dev, NULL); + + new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS); + if (!new_devdata) { + dev_err(&viodev->dev, "%s: Could not allocate memory for device data\n", __func__); + ret = -ENOMEM; + goto error_unlock; + } + + new_devdata->counters = kzalloc(sizeof(*new_devdata->counters), + GFP_NOFS); + if (!new_devdata->counters) { + dev_err(&viodev->dev, "%s: Could not allocate memory for performance counters\n", __func__); + ret = -ENOMEM; + goto error_unlock; + } + + new_devdata->vdev = viodev; + new_devdata->dev = &viodev->dev; + nx842_OF_set_defaults(new_devdata); + + rcu_assign_pointer(devdata, new_devdata); + spin_unlock_irqrestore(&devdata_mutex, flags); + synchronize_rcu(); + kfree(old_devdata); + + pSeries_reconfig_notifier_register(&nx842_of_nb); + + ret = nx842_OF_upd(NULL); + if (ret && ret != -ENODEV) { + dev_err(&viodev->dev, "could not parse device tree. %d\n", ret); + ret = -1; + goto error; + } + + rcu_read_lock(); + if (dev_set_drvdata(&viodev->dev, rcu_dereference(devdata))) { + rcu_read_unlock(); + dev_err(&viodev->dev, "failed to set driver data for device\n"); + ret = -1; + goto error; + } + rcu_read_unlock(); + + if (sysfs_create_group(&viodev->dev.kobj, &nx842_attribute_group)) { + dev_err(&viodev->dev, "could not create sysfs device attributes\n"); + ret = -1; + goto error; + } + + return 0; + +error_unlock: + spin_unlock_irqrestore(&devdata_mutex, flags); + if (new_devdata) + kfree(new_devdata->counters); + kfree(new_devdata); +error: + return ret; +} + +static int __exit nx842_remove(struct vio_dev *viodev) +{ + struct nx842_devdata *old_devdata; + unsigned long flags; + + pr_info("Removing IBM Power 842 compression device\n"); + sysfs_remove_group(&viodev->dev.kobj, &nx842_attribute_group); + + spin_lock_irqsave(&devdata_mutex, flags); + old_devdata = rcu_dereference_check(devdata, + lockdep_is_held(&devdata_mutex)); + pSeries_reconfig_notifier_unregister(&nx842_of_nb); + rcu_assign_pointer(devdata, NULL); + spin_unlock_irqrestore(&devdata_mutex, flags); + synchronize_rcu(); + dev_set_drvdata(&viodev->dev, NULL); + if (old_devdata) + kfree(old_devdata->counters); + kfree(old_devdata); + return 0; +} + +static struct vio_device_id nx842_driver_ids[] = { + {"ibm,compression-v1", "ibm,compression"}, + {"", ""}, +}; + +static struct vio_driver nx842_driver = { + .name = MODULE_NAME, + .probe = nx842_probe, + .remove = nx842_remove, + .get_desired_dma = nx842_get_desired_dma, + .id_table = nx842_driver_ids, +}; + +static int __init nx842_init(void) +{ + struct nx842_devdata *new_devdata; + pr_info("Registering IBM Power 842 compression driver\n"); + + RCU_INIT_POINTER(devdata, NULL); + new_devdata = kzalloc(sizeof(*new_devdata), GFP_KERNEL); + if (!new_devdata) { + pr_err("Could not allocate memory for device data\n"); + return -ENOMEM; + } + new_devdata->status = UNAVAILABLE; + RCU_INIT_POINTER(devdata, new_devdata); + + return vio_register_driver(&nx842_driver); +} + +module_init(nx842_init); + +static void __exit nx842_exit(void) +{ + struct nx842_devdata *old_devdata; + unsigned long flags; + + pr_info("Exiting IBM Power 842 compression driver\n"); + spin_lock_irqsave(&devdata_mutex, flags); + old_devdata = rcu_dereference_check(devdata, + lockdep_is_held(&devdata_mutex)); + rcu_assign_pointer(devdata, NULL); + spin_unlock_irqrestore(&devdata_mutex, flags); + synchronize_rcu(); + if (old_devdata) + dev_set_drvdata(old_devdata->dev, NULL); + kfree(old_devdata); + vio_unregister_driver(&nx842_driver); +} + +module_exit(nx842_exit); + +/********************************* + * 842 software decompressor +*********************************/ +typedef int (*sw842_template_op)(const char **, int *, unsigned char **, + struct sw842_fifo *); + +static int sw842_data8(const char **, int *, unsigned char **, + struct sw842_fifo *); +static int sw842_data4(const char **, int *, unsigned char **, + struct sw842_fifo *); +static int sw842_data2(const char **, int *, unsigned char **, + struct sw842_fifo *); +static int sw842_ptr8(const char **, int *, unsigned char **, + struct sw842_fifo *); +static int sw842_ptr4(const char **, int *, unsigned char **, + struct sw842_fifo *); +static int sw842_ptr2(const char **, int *, unsigned char **, + struct sw842_fifo *); + +/* special templates */ +#define SW842_TMPL_REPEAT 0x1B +#define SW842_TMPL_ZEROS 0x1C +#define SW842_TMPL_EOF 0x1E + +static sw842_template_op sw842_tmpl_ops[26][4] = { + { sw842_data8, NULL}, /* 0 (00000) */ + { sw842_data4, sw842_data2, sw842_ptr2, NULL}, + { sw842_data4, sw842_ptr2, sw842_data2, NULL}, + { sw842_data4, sw842_ptr2, sw842_ptr2, NULL}, + { sw842_data4, sw842_ptr4, NULL}, + { sw842_data2, sw842_ptr2, sw842_data4, NULL}, + { sw842_data2, sw842_ptr2, sw842_data2, sw842_ptr2}, + { sw842_data2, sw842_ptr2, sw842_ptr2, sw842_data2}, + { sw842_data2, sw842_ptr2, sw842_ptr2, sw842_ptr2,}, + { sw842_data2, sw842_ptr2, sw842_ptr4, NULL}, + { sw842_ptr2, sw842_data2, sw842_data4, NULL}, /* 10 (01010) */ + { sw842_ptr2, sw842_data4, sw842_ptr2, NULL}, + { sw842_ptr2, sw842_data2, sw842_ptr2, sw842_data2}, + { sw842_ptr2, sw842_data2, sw842_ptr2, sw842_ptr2}, + { sw842_ptr2, sw842_data2, sw842_ptr4, NULL}, + { sw842_ptr2, sw842_ptr2, sw842_data4, NULL}, + { sw842_ptr2, sw842_ptr2, sw842_data2, sw842_ptr2}, + { sw842_ptr2, sw842_ptr2, sw842_ptr2, sw842_data2}, + { sw842_ptr2, sw842_ptr2, sw842_ptr2, sw842_ptr2}, + { sw842_ptr2, sw842_ptr2, sw842_ptr4, NULL}, + { sw842_ptr4, sw842_data4, NULL}, /* 20 (10100) */ + { sw842_ptr4, sw842_data2, sw842_ptr2, NULL}, + { sw842_ptr4, sw842_ptr2, sw842_data2, NULL}, + { sw842_ptr4, sw842_ptr2, sw842_ptr2, NULL}, + { sw842_ptr4, sw842_ptr4, NULL}, + { sw842_ptr8, NULL} +}; + +/* Software decompress helpers */ + +static uint8_t sw842_get_byte(const char *buf, int bit) +{ + uint8_t tmpl; + uint16_t tmp; + tmp = htons(*(uint16_t *)(buf)); + tmp = (uint16_t)(tmp << bit); + tmp = ntohs(tmp); + memcpy(&tmpl, &tmp, 1); + return tmpl; +} + +static uint8_t sw842_get_template(const char **buf, int *bit) +{ + uint8_t byte; + byte = sw842_get_byte(*buf, *bit); + byte = byte >> 3; + byte &= 0x1F; + *buf += (*bit + 5) / 8; + *bit = (*bit + 5) % 8; + return byte; +} + +/* repeat_count happens to be 5-bit too (like the template) */ +static uint8_t sw842_get_repeat_count(const char **buf, int *bit) +{ + uint8_t byte; + byte = sw842_get_byte(*buf, *bit); + byte = byte >> 2; + byte &= 0x3F; + *buf += (*bit + 6) / 8; + *bit = (*bit + 6) % 8; + return byte; +} + +static uint8_t sw842_get_ptr2(const char **buf, int *bit) +{ + uint8_t ptr; + ptr = sw842_get_byte(*buf, *bit); + (*buf)++; + return ptr; +} + +static uint16_t sw842_get_ptr4(const char **buf, int *bit, + struct sw842_fifo *fifo) +{ + uint16_t ptr; + ptr = htons(*(uint16_t *)(*buf)); + ptr = (uint16_t)(ptr << *bit); + ptr = ptr >> 7; + ptr &= 0x01FF; + *buf += (*bit + 9) / 8; + *bit = (*bit + 9) % 8; + return ptr; +} + +static uint8_t sw842_get_ptr8(const char **buf, int *bit, + struct sw842_fifo *fifo) +{ + return sw842_get_ptr2(buf, bit); +} + +/* Software decompress template ops */ + +static int sw842_data8(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + int ret; + + ret = sw842_data4(inbuf, inbit, outbuf, fifo); + if (ret) + return ret; + ret = sw842_data4(inbuf, inbit, outbuf, fifo); + return ret; +} + +static int sw842_data4(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + int ret; + + ret = sw842_data2(inbuf, inbit, outbuf, fifo); + if (ret) + return ret; + ret = sw842_data2(inbuf, inbit, outbuf, fifo); + return ret; +} + +static int sw842_data2(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + **outbuf = sw842_get_byte(*inbuf, *inbit); + (*inbuf)++; + (*outbuf)++; + **outbuf = sw842_get_byte(*inbuf, *inbit); + (*inbuf)++; + (*outbuf)++; + return 0; +} + +static int sw842_ptr8(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + uint8_t ptr; + ptr = sw842_get_ptr8(inbuf, inbit, fifo); + if (!fifo->f84_full && (ptr >= fifo->f8_count)) + return 1; + memcpy(*outbuf, fifo->f8[ptr], 8); + *outbuf += 8; + return 0; +} + +static int sw842_ptr4(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + uint16_t ptr; + ptr = sw842_get_ptr4(inbuf, inbit, fifo); + if (!fifo->f84_full && (ptr >= fifo->f4_count)) + return 1; + memcpy(*outbuf, fifo->f4[ptr], 4); + *outbuf += 4; + return 0; +} + +static int sw842_ptr2(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + uint8_t ptr; + ptr = sw842_get_ptr2(inbuf, inbit); + if (!fifo->f2_full && (ptr >= fifo->f2_count)) + return 1; + memcpy(*outbuf, fifo->f2[ptr], 2); + *outbuf += 2; + return 0; +} + +static void sw842_copy_to_fifo(const char *buf, struct sw842_fifo *fifo) +{ + unsigned char initial_f2count = fifo->f2_count; + + memcpy(fifo->f8[fifo->f8_count], buf, 8); + fifo->f4_count += 2; + fifo->f8_count += 1; + + if (!fifo->f84_full && fifo->f4_count >= 512) { + fifo->f84_full = 1; + fifo->f4_count /= 512; + } + + memcpy(fifo->f2[fifo->f2_count++], buf, 2); + memcpy(fifo->f2[fifo->f2_count++], buf + 2, 2); + memcpy(fifo->f2[fifo->f2_count++], buf + 4, 2); + memcpy(fifo->f2[fifo->f2_count++], buf + 6, 2); + if (fifo->f2_count < initial_f2count) + fifo->f2_full = 1; +} + +static int sw842_decompress(const unsigned char *src, int srclen, + unsigned char *dst, int *destlen, + const void *wrkmem) +{ + uint8_t tmpl; + const char *inbuf; + int inbit = 0; + unsigned char *outbuf, *outbuf_end, *origbuf, *prevbuf; + const char *inbuf_end; + sw842_template_op op; + int opindex; + int i, repeat_count; + struct sw842_fifo *fifo; + int ret = 0; + + fifo = &((struct nx842_workmem *)(wrkmem))->swfifo; + memset(fifo, 0, sizeof(*fifo)); + + origbuf = NULL; + inbuf = src; + inbuf_end = src + srclen; + outbuf = dst; + outbuf_end = dst + *destlen; + + while ((tmpl = sw842_get_template(&inbuf, &inbit)) != SW842_TMPL_EOF) { + if (inbuf >= inbuf_end) { + ret = -EINVAL; + goto out; + } + + opindex = 0; + prevbuf = origbuf; + origbuf = outbuf; + switch (tmpl) { + case SW842_TMPL_REPEAT: + if (prevbuf == NULL) { + ret = -EINVAL; + goto out; + } + + repeat_count = sw842_get_repeat_count(&inbuf, + &inbit) + 1; + + /* Did the repeat count advance past the end of input */ + if (inbuf > inbuf_end) { + ret = -EINVAL; + goto out; + } + + for (i = 0; i < repeat_count; i++) { + /* Would this overflow the output buffer */ + if ((outbuf + 8) > outbuf_end) { + ret = -ENOSPC; + goto out; + } + + memcpy(outbuf, prevbuf, 8); + sw842_copy_to_fifo(outbuf, fifo); + outbuf += 8; + } + break; + + case SW842_TMPL_ZEROS: + /* Would this overflow the output buffer */ + if ((outbuf + 8) > outbuf_end) { + ret = -ENOSPC; + goto out; + } + + memset(outbuf, 0, 8); + sw842_copy_to_fifo(outbuf, fifo); + outbuf += 8; + break; + + default: + if (tmpl > 25) { + ret = -EINVAL; + goto out; + } + + /* Does this go past the end of the input buffer */ + if ((inbuf + 2) > inbuf_end) { + ret = -EINVAL; + goto out; + } + + /* Would this overflow the output buffer */ + if ((outbuf + 8) > outbuf_end) { + ret = -ENOSPC; + goto out; + } + + while (opindex < 4 && + (op = sw842_tmpl_ops[tmpl][opindex++]) + != NULL) { + ret = (*op)(&inbuf, &inbit, &outbuf, fifo); + if (ret) { + ret = -EINVAL; + goto out; + } + sw842_copy_to_fifo(origbuf, fifo); + } + } + } + +out: + if (!ret) + *destlen = (unsigned int)(outbuf - dst); + else + *destlen = 0; + + return ret; +} diff --git a/include/linux/nx842.h b/include/linux/nx842.h new file mode 100644 index 000000000000..a4d324c6406a --- /dev/null +++ b/include/linux/nx842.h @@ -0,0 +1,11 @@ +#ifndef __NX842_H__ +#define __NX842_H__ + +int nx842_get_workmem_size(void); +int nx842_get_workmem_size_aligned(void); +int nx842_compress(const unsigned char *in, unsigned int in_len, + unsigned char *out, unsigned int *out_len, void *wrkmem); +int nx842_decompress(const unsigned char *in, unsigned int in_len, + unsigned char *out, unsigned int *out_len, void *wrkmem); + +#endif From 35a1fc1873dd6deac6c005ead85424a8ee28183a Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Thu, 19 Jul 2012 09:42:41 -0500 Subject: [PATCH 0179/5375] powerpc/crypto: add 842 crypto driver This patch add the 842 cryptographic API driver that submits compression requests to the 842 hardware compression accelerator driver (nx-compress). If the hardware accelerator goes offline for any reason (dynamic disable, migration, etc...), this driver will use LZO as a software failover for all future compression requests. For decompression requests, the 842 hardware driver contains a software implementation of the 842 decompressor to support the decompression of data that was compressed before the accelerator went offline. Signed-off-by: Robert Jennings Signed-off-by: Seth Jennings Signed-off-by: Herbert Xu --- crypto/842.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++ crypto/Kconfig | 9 +++ crypto/Makefile | 1 + 3 files changed, 193 insertions(+) create mode 100644 crypto/842.c diff --git a/crypto/842.c b/crypto/842.c new file mode 100644 index 000000000000..144767db44e5 --- /dev/null +++ b/crypto/842.c @@ -0,0 +1,183 @@ +/* + * Cryptographic API for the 842 compression algorithm. + * + * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corporation, 2011 + * + * Authors: Robert Jennings + * Seth Jennings + */ + +#include +#include +#include +#include +#include +#include +#include + +static int nx842_uselzo; + +struct nx842_ctx { + void *nx842_wmem; /* working memory for 842/lzo */ +}; + +enum nx842_crypto_type { + NX842_CRYPTO_TYPE_842, + NX842_CRYPTO_TYPE_LZO +}; + +#define NX842_SENTINEL 0xdeadbeef + +struct nx842_crypto_header { + unsigned int sentinel; /* debug */ + enum nx842_crypto_type type; +}; + +static int nx842_init(struct crypto_tfm *tfm) +{ + struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); + int wmemsize; + + wmemsize = max_t(int, nx842_get_workmem_size(), LZO1X_MEM_COMPRESS); + ctx->nx842_wmem = kmalloc(wmemsize, GFP_NOFS); + if (!ctx->nx842_wmem) + return -ENOMEM; + + return 0; +} + +static void nx842_exit(struct crypto_tfm *tfm) +{ + struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); + + kfree(ctx->nx842_wmem); +} + +static void nx842_reset_uselzo(unsigned long data) +{ + nx842_uselzo = 0; +} + +static DEFINE_TIMER(failover_timer, nx842_reset_uselzo, 0, 0); + +static int nx842_crypto_compress(struct crypto_tfm *tfm, const u8 *src, + unsigned int slen, u8 *dst, unsigned int *dlen) +{ + struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); + struct nx842_crypto_header *hdr; + unsigned int tmp_len = *dlen; + size_t lzodlen; /* needed for lzo */ + int err; + + *dlen = 0; + hdr = (struct nx842_crypto_header *)dst; + hdr->sentinel = NX842_SENTINEL; /* debug */ + dst += sizeof(struct nx842_crypto_header); + tmp_len -= sizeof(struct nx842_crypto_header); + lzodlen = tmp_len; + + if (likely(!nx842_uselzo)) { + err = nx842_compress(src, slen, dst, &tmp_len, ctx->nx842_wmem); + + if (likely(!err)) { + hdr->type = NX842_CRYPTO_TYPE_842; + *dlen = tmp_len + sizeof(struct nx842_crypto_header); + return 0; + } + + /* hardware failed */ + nx842_uselzo = 1; + + /* set timer to check for hardware again in 1 second */ + mod_timer(&failover_timer, jiffies + msecs_to_jiffies(1000)); + } + + /* no hardware, use lzo */ + err = lzo1x_1_compress(src, slen, dst, &lzodlen, ctx->nx842_wmem); + if (err != LZO_E_OK) + return -EINVAL; + + hdr->type = NX842_CRYPTO_TYPE_LZO; + *dlen = lzodlen + sizeof(struct nx842_crypto_header); + return 0; +} + +static int nx842_crypto_decompress(struct crypto_tfm *tfm, const u8 *src, + unsigned int slen, u8 *dst, unsigned int *dlen) +{ + struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); + struct nx842_crypto_header *hdr; + unsigned int tmp_len = *dlen; + size_t lzodlen; /* needed for lzo */ + int err; + + *dlen = 0; + hdr = (struct nx842_crypto_header *)src; + + if (unlikely(hdr->sentinel != NX842_SENTINEL)) + return -EINVAL; + + src += sizeof(struct nx842_crypto_header); + slen -= sizeof(struct nx842_crypto_header); + + if (likely(hdr->type == NX842_CRYPTO_TYPE_842)) { + err = nx842_decompress(src, slen, dst, &tmp_len, + ctx->nx842_wmem); + if (err) + return -EINVAL; + *dlen = tmp_len; + } else if (hdr->type == NX842_CRYPTO_TYPE_LZO) { + lzodlen = tmp_len; + err = lzo1x_decompress_safe(src, slen, dst, &lzodlen); + if (err != LZO_E_OK) + return -EINVAL; + *dlen = lzodlen; + } else + return -EINVAL; + + return 0; +} + +static struct crypto_alg alg = { + .cra_name = "842", + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct nx842_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_init = nx842_init, + .cra_exit = nx842_exit, + .cra_u = { .compress = { + .coa_compress = nx842_crypto_compress, + .coa_decompress = nx842_crypto_decompress } } +}; + +static int __init nx842_mod_init(void) +{ + del_timer(&failover_timer); + return crypto_register_alg(&alg); +} + +static void __exit nx842_mod_exit(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(nx842_mod_init); +module_exit(nx842_mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("842 Compression Algorithm"); diff --git a/crypto/Kconfig b/crypto/Kconfig index fe8ed62efe2f..cbcc0e2eeda0 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -1039,6 +1039,15 @@ config CRYPTO_LZO help This is the LZO algorithm. +config CRYPTO_842 + tristate "842 compression algorithm" + depends on CRYPTO_DEV_NX_COMPRESS + # 842 uses lzo if the hardware becomes unavailable + select LZO_COMPRESS + select LZO_DECOMPRESS + help + This is the 842 algorithm. + comment "Random Number Generation" config CRYPTO_ANSI_CPRNG diff --git a/crypto/Makefile b/crypto/Makefile index 396966d2d849..a301ad2b258c 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o obj-$(CONFIG_CRYPTO_LZO) += lzo.o +obj-$(CONFIG_CRYPTO_842) += 842.o obj-$(CONFIG_CRYPTO_RNG2) += rng.o obj-$(CONFIG_CRYPTO_RNG2) += krng.o obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o From de4bb3b9c788ea5504dfe094e34d831e8395075d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 31 Jul 2012 16:15:36 +0200 Subject: [PATCH 0180/5375] samples/seccomp: fix endianness bug in LO_ARG define The LO_ARG define needs to consider endianness also for 32 bit builds. The "bpf_fancy" test case didn't work on s390 in 32 bit and compat mode because the LO_ARG define resulted in a BPF program which read the upper halve of the 64 bit system call arguments instead of the lower halves. Signed-off-by: Heiko Carstens Acked-by: Kees Cook Signed-off-by: James Morris --- samples/seccomp/bpf-helper.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/samples/seccomp/bpf-helper.h b/samples/seccomp/bpf-helper.h index 643279dd30fb..38ee70f3cd5b 100644 --- a/samples/seccomp/bpf-helper.h +++ b/samples/seccomp/bpf-helper.h @@ -59,6 +59,16 @@ void seccomp_bpf_print(struct sock_filter *filter, size_t count); #define FIND_LABEL(labels, label) seccomp_bpf_label((labels), #label) #define EXPAND(...) __VA_ARGS__ + +/* Ensure that we load the logically correct offset. */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) +#else +#error "Unknown endianness" +#endif + /* Map all width-sensitive operations */ #if __BITS_PER_LONG == 32 @@ -70,21 +80,16 @@ void seccomp_bpf_print(struct sock_filter *filter, size_t count); #define JLE(x, jt) JLE32(x, EXPAND(jt)) #define JA(x, jt) JA32(x, EXPAND(jt)) #define ARG(i) ARG_32(i) -#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) #elif __BITS_PER_LONG == 64 /* Ensure that we load the logically correct offset. */ #if __BYTE_ORDER == __LITTLE_ENDIAN #define ENDIAN(_lo, _hi) _lo, _hi -#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) #elif __BYTE_ORDER == __BIG_ENDIAN #define ENDIAN(_lo, _hi) _hi, _lo -#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) -#else -#error "Unknown endianness" #endif union arg64 { From 9f99798ff49e73dded73a8c674044ea6fb6af651 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 31 Jul 2012 20:37:00 +0900 Subject: [PATCH 0181/5375] ptrace: mark __ptrace_may_access() static __ptrace_may_access() is used within only kernel/ptrace.c. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- include/linux/ptrace.h | 2 -- kernel/ptrace.c | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 597e4fdb97fe..3db698aee34c 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -130,8 +130,6 @@ extern void exit_ptrace(struct task_struct *tracer); #define PTRACE_MODE_READ 0x01 #define PTRACE_MODE_ATTACH 0x02 #define PTRACE_MODE_NOAUDIT 0x04 -/* Returns 0 on success, -errno on denial. */ -extern int __ptrace_may_access(struct task_struct *task, unsigned int mode); /* Returns true on success, false on denial. */ extern bool ptrace_may_access(struct task_struct *task, unsigned int mode); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index a232bb59d93f..1f5e55dda955 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -180,7 +180,8 @@ static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) return has_ns_capability(current, ns, CAP_SYS_PTRACE); } -int __ptrace_may_access(struct task_struct *task, unsigned int mode) +/* Returns 0 on success, -errno on denial. */ +static int __ptrace_may_access(struct task_struct *task, unsigned int mode) { const struct cred *cred = current_cred(), *tcred; From 988aec3de5f0fa848f26fbf64f9e83364d6b3c25 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Wed, 1 Aug 2012 16:05:39 +0200 Subject: [PATCH 0182/5375] ALSA: isa: Move snd_legacy_find_free_ioport to initval.h Move snd_legacy_find_free_ioport() function back to initval.h as it is used by two drivers. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- include/sound/initval.h | 14 ++++++++++++++ sound/isa/opti9xx/miro.c | 15 +-------------- sound/isa/opti9xx/opti92x-ad1848.c | 14 +------------- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/include/sound/initval.h b/include/sound/initval.h index f99a0d2ddfe7..ac62c67e6f42 100644 --- a/include/sound/initval.h +++ b/include/sound/initval.h @@ -50,6 +50,20 @@ #define SNDRV_DEFAULT_DMA_SIZE { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_DMA_SIZE } #define SNDRV_DEFAULT_PTR SNDRV_DEFAULT_STR +#ifdef SNDRV_LEGACY_FIND_FREE_IOPORT +static long snd_legacy_find_free_ioport(long *port_table, long size) +{ + while (*port_table != -1) { + if (request_region(*port_table, size, "ALSA test")) { + release_region(*port_table, size); + return *port_table; + } + port_table++; + } + return -1; +} +#endif + #ifdef SNDRV_LEGACY_FIND_FREE_IRQ #include diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index c24594c866f4..3d1afb612b35 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -37,6 +37,7 @@ #include #include #include +#define SNDRV_LEGACY_FIND_FREE_IOPORT #define SNDRV_LEGACY_FIND_FREE_IRQ #define SNDRV_LEGACY_FIND_FREE_DMA #include @@ -770,20 +771,6 @@ static int __devinit snd_miro_mixer(struct snd_card *card, return 0; } -static long snd_legacy_find_free_ioport(long *port_table, long size) -{ - while (*port_table != -1) { - struct resource *res; - if ((res = request_region(*port_table, size, - "ALSA test")) != NULL) { - release_and_free_resource(res); - return *port_table; - } - port_table++; - } - return -1; -} - static int __devinit snd_miro_init(struct snd_miro *chip, unsigned short hardware) { diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index f8fbe22515c9..2899c9fd1ceb 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -39,6 +39,7 @@ #ifndef OPTi93X #include #endif +#define SNDRV_LEGACY_FIND_FREE_IOPORT #define SNDRV_LEGACY_FIND_FREE_IRQ #define SNDRV_LEGACY_FIND_FREE_DMA #include @@ -185,19 +186,6 @@ static char * snd_opti9xx_names[] = { "82C930", "82C931", "82C933" }; - -static long __devinit snd_legacy_find_free_ioport(long *port_table, long size) -{ - while (*port_table != -1) { - if (request_region(*port_table, size, "ALSA test")) { - release_region(*port_table, size); - return *port_table; - } - port_table++; - } - return -1; -} - static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip, unsigned short hardware) { From 5d61b165c892853f2daf6220d2ec6577487e273a Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 25 Jul 2012 17:34:37 -0600 Subject: [PATCH 0183/5375] of: Allow busses with #size-cells=0 It's quite legitimate for a DT node to specify #size-cells=0. One example is a node that's used to collect a number of non-memory-mapped devices. In that scenario, there may be multiple child nodes with the same name (type) thus necessitating the use of unit addresses in node names, and reg properties: / { regulators { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <0>; regulator@0 { compatible = "regulator-fixed"; reg = <0>; ... }; regulator@1 { compatible = "regulator-fixed"; reg = <1>; ... }; ... }; }; However, #size-cells=0 prevents translation of reg property values into the parent node's address space. In turn, this triggers the kernel to emit error messages during boot, such as: prom_parse: Bad cell count for /regulators/regulator@0 To prevent printing these error messages for legitimate DT content, a number of changes are made: 1) of_get_address()/of_get_pci_address() are modified only to validate the value of #address-cells, and not #size-cells. 2) of_can_translate_address() is added to indicate whether address translation is possible. 3) of_device_make_bus_id() is modified to name devices based on the translated address only where possible, and otherwise fall back to using the (first cell of the) raw untranslated address. 4) of_device_alloc() is modified to create memory resources for a device only if the address can be translated into the CPU's address space. Signed-off-by: Stephen Warren Signed-off-by: Rob Herring --- drivers/of/address.c | 27 +++++++++++++++++++++++---- drivers/of/platform.c | 16 +++++++++++++--- include/linux/of_address.h | 1 + 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/drivers/of/address.c b/drivers/of/address.c index 7e262a6124c5..7a07751428de 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -9,8 +9,8 @@ /* Max address size we deal with */ #define OF_MAX_ADDR_CELLS 4 -#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ - (ns) > 0) +#define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS) +#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && (ns) > 0) static struct of_bus *of_match_bus(struct device_node *np); static int __of_address_to_resource(struct device_node *dev, @@ -182,7 +182,7 @@ const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, } bus->count_cells(dev, &na, &ns); of_node_put(parent); - if (!OF_CHECK_COUNTS(na, ns)) + if (!OF_CHECK_ADDR_COUNT(na)) return NULL; /* Get "reg" or "assigned-addresses" property */ @@ -490,6 +490,25 @@ u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) } EXPORT_SYMBOL(of_translate_dma_address); +bool of_can_translate_address(struct device_node *dev) +{ + struct device_node *parent; + struct of_bus *bus; + int na, ns; + + parent = of_get_parent(dev); + if (parent == NULL) + return false; + + bus = of_match_bus(parent); + bus->count_cells(dev, &na, &ns); + + of_node_put(parent); + + return OF_CHECK_COUNTS(na, ns); +} +EXPORT_SYMBOL(of_can_translate_address); + const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags) { @@ -506,7 +525,7 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, bus = of_match_bus(parent); bus->count_cells(dev, &na, &ns); of_node_put(parent); - if (!OF_CHECK_COUNTS(na, ns)) + if (!OF_CHECK_ADDR_COUNT(na)) return NULL; /* Get "reg" or "assigned-addresses" property */ diff --git a/drivers/of/platform.c b/drivers/of/platform.c index e44f8c2d239d..9bdeaf30b17d 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -78,6 +78,7 @@ void of_device_make_bus_id(struct device *dev) struct device_node *node = dev->of_node; const u32 *reg; u64 addr; + const __be32 *addrp; int magic; #ifdef CONFIG_PPC_DCR @@ -105,7 +106,15 @@ void of_device_make_bus_id(struct device *dev) */ reg = of_get_property(node, "reg", NULL); if (reg) { - addr = of_translate_address(node, reg); + if (of_can_translate_address(node)) { + addr = of_translate_address(node, reg); + } else { + addrp = of_get_address(node, 0, NULL, NULL); + if (addrp) + addr = of_read_number(addrp, 1); + else + addr = OF_BAD_ADDR; + } if (addr != OF_BAD_ADDR) { dev_set_name(dev, "%llx.%s", (unsigned long long)addr, node->name); @@ -140,8 +149,9 @@ struct platform_device *of_device_alloc(struct device_node *np, return NULL; /* count the io and irq resources */ - while (of_address_to_resource(np, num_reg, &temp_res) == 0) - num_reg++; + if (of_can_translate_address(np)) + while (of_address_to_resource(np, num_reg, &temp_res) == 0) + num_reg++; num_irq = of_irq_count(np); /* Populate the resource table */ diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 01b925ad8d78..c3cdc1025c30 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -6,6 +6,7 @@ #ifdef CONFIG_OF_ADDRESS extern u64 of_translate_address(struct device_node *np, const __be32 *addr); +extern bool of_can_translate_address(struct device_node *dev); extern int of_address_to_resource(struct device_node *dev, int index, struct resource *r); extern struct device_node *of_find_matching_node_by_address( From 39abf8aa7dfad0badb4741373023cda369aacc8e Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Thu, 2 Aug 2012 11:46:40 +0300 Subject: [PATCH 0184/5375] iommu/tegra: smmu: debugfs for TLB/PTC statistics Add debugfs entries to collect TLB/PTC statistics. $ echo "reset" > /sys/kernel/debug/smmu/mc/{tlb,ptc} $ echo "on" > /sys/kernel/debug/smmu/mc/{tlb,ptc} $ echo "off" > /sys/kernel/debug/smmu/mc/{tlb,ptc} $ cat /sys/kernel/debug/smmu/mc/{tlb,ptc} hit:0014910c miss:00014d22 The above format is: hit:miss: fscanf(fp, "hit:%lx miss:%lx", &hit, &miss); Signed-off-by: Hiroshi Doyu Signed-off-by: Joerg Roedel --- drivers/iommu/tegra-smmu.c | 202 ++++++++++++++++++++++++++++++++++--- 1 file changed, 190 insertions(+), 12 deletions(-) diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 4ba325ab6262..95b4698abd3e 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include @@ -47,16 +49,29 @@ #define SMMU_CONFIG_DISABLE 0 #define SMMU_CONFIG_ENABLE 1 -#define SMMU_TLB_CONFIG 0x14 -#define SMMU_TLB_CONFIG_STATS__MASK (1 << 31) -#define SMMU_TLB_CONFIG_STATS__ENABLE (1 << 31) +/* REVISIT: To support multiple MCs */ +enum { + _MC = 0, +}; + +enum { + _TLB = 0, + _PTC, +}; + +#define SMMU_CACHE_CONFIG_BASE 0x14 +#define __SMMU_CACHE_CONFIG(mc, cache) (SMMU_CACHE_CONFIG_BASE + 4 * cache) +#define SMMU_CACHE_CONFIG(cache) __SMMU_CACHE_CONFIG(_MC, cache) + +#define SMMU_CACHE_CONFIG_STATS_SHIFT 31 +#define SMMU_CACHE_CONFIG_STATS_ENABLE (1 << SMMU_CACHE_CONFIG_STATS_SHIFT) +#define SMMU_CACHE_CONFIG_STATS_TEST_SHIFT 30 +#define SMMU_CACHE_CONFIG_STATS_TEST (1 << SMMU_CACHE_CONFIG_STATS_TEST_SHIFT) + #define SMMU_TLB_CONFIG_HIT_UNDER_MISS__ENABLE (1 << 29) #define SMMU_TLB_CONFIG_ACTIVE_LINES__VALUE 0x10 #define SMMU_TLB_CONFIG_RESET_VAL 0x20000010 -#define SMMU_PTC_CONFIG 0x18 -#define SMMU_PTC_CONFIG_STATS__MASK (1 << 31) -#define SMMU_PTC_CONFIG_STATS__ENABLE (1 << 31) #define SMMU_PTC_CONFIG_CACHE__ENABLE (1 << 29) #define SMMU_PTC_CONFIG_INDEX_MAP__PATTERN 0x3f #define SMMU_PTC_CONFIG_RESET_VAL 0x2000003f @@ -86,10 +101,10 @@ #define SMMU_ASID_SECURITY 0x38 -#define SMMU_STATS_TLB_HIT_COUNT 0x1f0 -#define SMMU_STATS_TLB_MISS_COUNT 0x1f4 -#define SMMU_STATS_PTC_HIT_COUNT 0x1f8 -#define SMMU_STATS_PTC_MISS_COUNT 0x1fc +#define SMMU_STATS_CACHE_COUNT_BASE 0x1f0 + +#define SMMU_STATS_CACHE_COUNT(mc, cache, hitmiss) \ + (SMMU_STATS_CACHE_COUNT_BASE + 8 * cache + 4 * hitmiss) #define SMMU_TRANSLATION_ENABLE_0 0x228 #define SMMU_TRANSLATION_ENABLE_1 0x22c @@ -251,6 +266,8 @@ struct smmu_device { unsigned long translation_enable_2; unsigned long asid_security; + struct dentry *debugfs_root; + struct device_node *ahb; int num_as; @@ -412,8 +429,8 @@ static int smmu_setup_regs(struct smmu_device *smmu) smmu_write(smmu, smmu->translation_enable_1, SMMU_TRANSLATION_ENABLE_1); smmu_write(smmu, smmu->translation_enable_2, SMMU_TRANSLATION_ENABLE_2); smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY); - smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_TLB_CONFIG); - smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_PTC_CONFIG); + smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_TLB)); + smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_PTC)); smmu_flush_regs(smmu, 1); @@ -892,6 +909,164 @@ static struct iommu_ops smmu_iommu_ops = { .pgsize_bitmap = SMMU_IOMMU_PGSIZES, }; +/* Should be in the order of enum */ +static const char * const smmu_debugfs_mc[] = { "mc", }; +static const char * const smmu_debugfs_cache[] = { "tlb", "ptc", }; + +static ssize_t smmu_debugfs_stats_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *pos) +{ + struct smmu_device *smmu; + struct dentry *dent; + int i, cache, mc; + enum { + _OFF = 0, + _ON, + _RESET, + }; + const char * const command[] = { + [_OFF] = "off", + [_ON] = "on", + [_RESET] = "reset", + }; + char str[] = "reset"; + u32 val; + size_t offs; + + count = min_t(size_t, count, sizeof(str)); + if (copy_from_user(str, buffer, count)) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(command); i++) + if (strncmp(str, command[i], + strlen(command[i])) == 0) + break; + + if (i == ARRAY_SIZE(command)) + return -EINVAL; + + dent = file->f_dentry; + cache = (int)dent->d_inode->i_private; + mc = (int)dent->d_parent->d_inode->i_private; + smmu = dent->d_parent->d_parent->d_inode->i_private; + + offs = SMMU_CACHE_CONFIG(cache); + val = smmu_read(smmu, offs); + switch (i) { + case _OFF: + val &= ~SMMU_CACHE_CONFIG_STATS_ENABLE; + val &= ~SMMU_CACHE_CONFIG_STATS_TEST; + smmu_write(smmu, val, offs); + break; + case _ON: + val |= SMMU_CACHE_CONFIG_STATS_ENABLE; + val &= ~SMMU_CACHE_CONFIG_STATS_TEST; + smmu_write(smmu, val, offs); + break; + case _RESET: + val |= SMMU_CACHE_CONFIG_STATS_TEST; + smmu_write(smmu, val, offs); + val &= ~SMMU_CACHE_CONFIG_STATS_TEST; + smmu_write(smmu, val, offs); + break; + default: + BUG(); + break; + } + + dev_dbg(smmu->dev, "%s() %08x, %08x @%08x\n", __func__, + val, smmu_read(smmu, offs), offs); + + return count; +} + +static int smmu_debugfs_stats_show(struct seq_file *s, void *v) +{ + struct smmu_device *smmu; + struct dentry *dent; + int i, cache, mc; + const char * const stats[] = { "hit", "miss", }; + + dent = d_find_alias(s->private); + cache = (int)dent->d_inode->i_private; + mc = (int)dent->d_parent->d_inode->i_private; + smmu = dent->d_parent->d_parent->d_inode->i_private; + + for (i = 0; i < ARRAY_SIZE(stats); i++) { + u32 val; + size_t offs; + + offs = SMMU_STATS_CACHE_COUNT(mc, cache, i); + val = smmu_read(smmu, offs); + seq_printf(s, "%s:%08x ", stats[i], val); + + dev_dbg(smmu->dev, "%s() %s %08x @%08x\n", __func__, + stats[i], val, offs); + } + seq_printf(s, "\n"); + + return 0; +} + +static int smmu_debugfs_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, smmu_debugfs_stats_show, inode); +} + +static const struct file_operations smmu_debugfs_stats_fops = { + .open = smmu_debugfs_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = smmu_debugfs_stats_write, +}; + +static void smmu_debugfs_delete(struct smmu_device *smmu) +{ + debugfs_remove_recursive(smmu->debugfs_root); +} + +static void smmu_debugfs_create(struct smmu_device *smmu) +{ + int i; + struct dentry *root; + + root = debugfs_create_file(dev_name(smmu->dev), + S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, + NULL, smmu, NULL); + if (!root) + goto err_out; + smmu->debugfs_root = root; + + for (i = 0; i < ARRAY_SIZE(smmu_debugfs_mc); i++) { + int j; + struct dentry *mc; + + mc = debugfs_create_file(smmu_debugfs_mc[i], + S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, + root, (void *)i, NULL); + if (!mc) + goto err_out; + + for (j = 0; j < ARRAY_SIZE(smmu_debugfs_cache); j++) { + struct dentry *cache; + + cache = debugfs_create_file(smmu_debugfs_cache[j], + S_IWUGO | S_IRUGO, mc, + (void *)j, + &smmu_debugfs_stats_fops); + if (!cache) + goto err_out; + } + } + + return; + +err_out: + smmu_debugfs_delete(smmu); +} + static int tegra_smmu_suspend(struct device *dev) { struct smmu_device *smmu = dev_get_drvdata(dev); @@ -996,6 +1171,7 @@ static int tegra_smmu_probe(struct platform_device *pdev) if (!smmu->avp_vector_page) return -ENOMEM; + smmu_debugfs_create(smmu); smmu_handle = smmu; return 0; } @@ -1005,6 +1181,8 @@ static int tegra_smmu_remove(struct platform_device *pdev) struct smmu_device *smmu = platform_get_drvdata(pdev); int i; + smmu_debugfs_delete(smmu); + smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG); for (i = 0; i < smmu->num_as; i++) free_pdir(&smmu->as[i]); From e115676e042f4d9268c6b6d8cb7dc962aa6cfd7d Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Wed, 1 Aug 2012 17:01:42 +0300 Subject: [PATCH 0185/5375] KVM: x86: update KVM_SAVE_MSRS_BEGIN to correct value When MSR_KVM_PV_EOI_EN was added to msrs_to_save array KVM_SAVE_MSRS_BEGIN was not updated accordingly. Signed-off-by: Gleb Natapov Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3a53bcc24f20..a87c82aa3196 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -806,7 +806,7 @@ EXPORT_SYMBOL_GPL(kvm_rdpmc); * kvm-specific. Those are put in the beginning of the list. */ -#define KVM_SAVE_MSRS_BEGIN 9 +#define KVM_SAVE_MSRS_BEGIN 10 static u32 msrs_to_save[] = { MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW, From d77ae3329292baebfc6eced97d2e12b66349f83c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 23 Jul 2012 12:39:51 +0300 Subject: [PATCH 0186/5375] ASoC: omap-mcpdm: Convert to use devm_* Switch to use devm_* te make the probe/remove code more cleaner. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcpdm.c | 52 ++++++++++--------------------------- 1 file changed, 13 insertions(+), 39 deletions(-) diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 2c66e2498a45..f7babb374a37 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -445,9 +445,8 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev) { struct omap_mcpdm *mcpdm; struct resource *res; - int ret = 0; - mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL); + mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL); if (!mcpdm) return -ENOMEM; @@ -456,55 +455,30 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev) mutex_init(&mcpdm->mutex); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no resource\n"); - goto err_res; - } + if (res == NULL) + return -ENOMEM; - if (!request_mem_region(res->start, resource_size(res), "McPDM")) { - ret = -EBUSY; - goto err_res; - } + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), "McPDM")) + return -EBUSY; - mcpdm->io_base = ioremap(res->start, resource_size(res)); - if (!mcpdm->io_base) { - ret = -ENOMEM; - goto err_iomap; - } + mcpdm->io_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!mcpdm->io_base) + return -ENOMEM; mcpdm->irq = platform_get_irq(pdev, 0); - if (mcpdm->irq < 0) { - ret = mcpdm->irq; - goto err_irq; - } + if (mcpdm->irq < 0) + return mcpdm->irq; mcpdm->dev = &pdev->dev; - ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai); - if (!ret) - return 0; - -err_irq: - iounmap(mcpdm->io_base); -err_iomap: - release_mem_region(res->start, resource_size(res)); -err_res: - kfree(mcpdm); - return ret; + return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai); } static int __devexit asoc_mcpdm_remove(struct platform_device *pdev) { - struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev); - struct resource *res; - snd_soc_unregister_dai(&pdev->dev); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iounmap(mcpdm->io_base); - release_mem_region(res->start, resource_size(res)); - - kfree(mcpdm); return 0; } From 0651322bfcf3ca51802c6d8d161d6d1c9f3013eb Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 23 Jul 2012 17:25:15 +0530 Subject: [PATCH 0187/5375] ASoC: isabelle: Remove version.h header file inclusion version.h header file inclusion is no longer needed for this file. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/isabelle.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 5d8f39e32978..1bf55602c9eb 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -13,7 +13,6 @@ */ #include #include -#include #include #include #include From fbfe69836c088bcc0c5a0f32e788d3aef5f66aca Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Jul 2012 20:14:43 +0100 Subject: [PATCH 0188/5375] ASoC: wm8994: Implement support for self-oscillation mode in the FLL The FLLs in the WM8994 series devices can be started without any reference being supplied, mainly for use in analogue bypass cases. Implement support for this mode. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 21 +++++++++++++++------ sound/soc/codecs/wm8994.h | 9 +++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 04ef03175c51..2c9b8b7fdf3d 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2102,6 +2102,10 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, case WM8994_FLL_SRC_LRCLK: case WM8994_FLL_SRC_BCLK: break; + case WM8994_FLL_SRC_INTERNAL: + freq_in = 12000000; + freq_out = 12000000; + break; default: return -EINVAL; } @@ -2164,9 +2168,11 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, fll.n << WM8994_FLL1_N_SHIFT); snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, - WM8958_FLL1_BYP | + WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP | WM8994_FLL1_REFCLK_DIV_MASK | WM8994_FLL1_REFCLK_SRC_MASK, + ((src == WM8994_FLL_SRC_INTERNAL) + << WM8994_FLL1_FRC_NCO_SHIFT) | (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) | (src - 1)); @@ -2192,13 +2198,16 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, } } + reg = WM8994_FLL1_ENA; + if (fll.k) - reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC; - else - reg = WM8994_FLL1_ENA; + reg |= WM8994_FLL1_FRAC; + if (src == WM8994_FLL_SRC_INTERNAL) + reg |= WM8994_FLL1_OSC_ENA; + snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset, - WM8994_FLL1_ENA | WM8994_FLL1_FRAC, - reg); + WM8994_FLL1_ENA | WM8994_FLL1_OSC_ENA | + WM8994_FLL1_FRAC, reg); if (wm8994->fll_locked_irq) { timeout = wait_for_completion_timeout(&wm8994->fll_locked[id], diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index d77e06f0a675..19068d8fa301 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -28,10 +28,11 @@ #define WM8994_FLL1 1 #define WM8994_FLL2 2 -#define WM8994_FLL_SRC_MCLK1 1 -#define WM8994_FLL_SRC_MCLK2 2 -#define WM8994_FLL_SRC_LRCLK 3 -#define WM8994_FLL_SRC_BCLK 4 +#define WM8994_FLL_SRC_MCLK1 1 +#define WM8994_FLL_SRC_MCLK2 2 +#define WM8994_FLL_SRC_LRCLK 3 +#define WM8994_FLL_SRC_BCLK 4 +#define WM8994_FLL_SRC_INTERNAL 5 enum wm8994_vmid_mode { WM8994_VMID_NORMAL, From 0dcd47426abde223b2386165470ec45d9777478e Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 26 Jul 2012 11:28:37 +0100 Subject: [PATCH 0189/5375] ASoC: ux500: Strengthen error checking after memory allocation Currently there is no out-of-memory error checking after attempting to allocate memory for the ux500_msp or ux500_msp_i2s_drvdata data structures. Instead we go about populating them regardless. This patch applies the necessary error checking to prevent a panic. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_dai.c | 3 +++ sound/soc/ux500/ux500_msp_i2s.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 057e28ef770e..772cb19d2fb3 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -760,6 +760,9 @@ static int __devinit ux500_msp_drv_probe(struct platform_device *pdev) drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp_i2s_drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + drvdata->fmt = 0; drvdata->slots = 1; drvdata->tx_mask = 0x01; diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index 5c472f335a64..36be11e47ad6 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c @@ -673,6 +673,8 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL); msp = *msp_p; + if (!msp) + return -ENOMEM; msp->id = platform_data->id; msp->dev = &pdev->dev; From 5ef75e710b4950439f953c4897e4a871c2f9dc8f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 25 Jul 2012 16:09:11 +0300 Subject: [PATCH 0190/5375] ASoC: omap-abe-twl6040: Add device tree support When the board boots with device tree the driver will receive the name of the card, DAPM routing map, phandle for the audio components described in the dts file, mclk speed, and the possibility of detecting the jack detection. The card will be set up based on this information. Since the routing is provided via DT we can mark the card fully routed so core can take care of disconnecting the unused pins. Signed-off-by: Peter Ujfalusi Reviwed-by: Mark Brown Signed-off-by: Mark Brown --- .../bindings/sound/omap-abe-twl6040.txt | 91 +++++++++++ sound/soc/omap/omap-abe-twl6040.c | 145 ++++++++++++++---- 2 files changed, 206 insertions(+), 30 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt diff --git a/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt new file mode 100644 index 000000000000..65dec876cb2d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt @@ -0,0 +1,91 @@ +* Texas Instruments OMAP4+ and twl6040 based audio setups + +Required properties: +- compatible: "ti,abe-twl6040" +- ti,model: Name of the sound card ( for example "SDP4430") +- ti,mclk-freq: MCLK frequency for HPPLL operation +- ti,mcpdm: phandle for the McPDM node +- ti,twl6040: phandle for the twl6040 core node +- ti,audio-routing: List of connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. + +Optional properties: +- ti,dmic: phandle for the OMAP dmic node if the machine have it connected +- ti,jack_detection: Need to be set to <1> if the board capable to detect jack + insertion, removal. + +Available audio endpoints for the audio-routing table: + +Board connectors: + * Headset Stereophone + * Earphone Spk + * Ext Spk + * Line Out + * Vibrator + * Headset Mic + * Main Handset Mic + * Sub Handset Mic + * Line In + * Digital Mic + +twl6040 pins: + * HSOL + * HSOR + * EP + * HFL + * HFR + * AUXL + * AUXR + * VIBRAL + * VIBRAR + * HSMIC + * MAINMIC + * SUBMIC + * AFML + * AFMR + + * Headset Mic Bias + * Main Mic Bias + * Digital Mic1 Bias + * Digital Mic2 Bias + +Digital mic pins: + * DMic + +Example: + +sound { + compatible = "ti,abe-twl6040"; + ti,model = "SDP4430"; + + ti,jack-detection = <1>; + ti,mclk-freq = <38400000>; + + ti,mcpdm = <&mcpdm>; + ti,dmic = <&dmic>; + + ti,twl6040 = <&twl6040>; + + /* Audio routing */ + ti,audio-routing = + "Headset Stereophone", "HSOL", + "Headset Stereophone", "HSOR", + "Earphone Spk", "EP", + "Ext Spk", "HFL", + "Ext Spk", "HFR", + "Line Out", "AUXL", + "Line Out", "AUXR", + "Vibrator", "VIBRAL", + "Vibrator", "VIBRAR", + "HSMIC", "Headset Mic", + "Headset Mic", "Headset Mic Bias", + "MAINMIC", "Main Handset Mic", + "Main Handset Mic", "Main Mic Bias", + "SUBMIC", "Sub Handset Mic", + "Sub Handset Mic", "Main Mic Bias", + "AFML", "Line In", + "AFMR", "Line In", + "DMic", "Digital Mic", + "Digital Mic", "Digital Mic1 Bias"; +}; diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index 9d93793d3077..be525dfe9faa 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,8 @@ struct abe_twl6040 { int jack_detection; /* board can detect jack events */ int mclk_freq; /* MCLK frequency speed for twl6040 */ + + struct platform_device *dmic_codec_dev; }; static int omap_abe_hw_params(struct snd_pcm_substream *substream, @@ -185,17 +188,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) int hs_trim; int ret = 0; - /* Disable not connected paths if not used */ - twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); - twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); - twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); - twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); - twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); - twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); - twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); - twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); - twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); - /* * Configure McPDM offset cancellation based on the HSOTRIM value from * twl6040. @@ -216,6 +208,24 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET); } + /* + * NULL pdata means we booted with DT. In this case the routing is + * provided and the card is fully routed, no need to mark pins. + */ + if (!pdata) + return ret; + + /* Disable not connected paths if not used */ + twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone"); + twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); + twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); + twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); + twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); + twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); + twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In"); + return ret; } @@ -270,52 +280,116 @@ static struct snd_soc_card omap_abe_card = { static __devinit int omap_abe_probe(struct platform_device *pdev) { struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev); + struct device_node *node = pdev->dev.of_node; struct snd_soc_card *card = &omap_abe_card; struct abe_twl6040 *priv; int num_links = 0; - int ret; + int ret = 0; card->dev = &pdev->dev; - if (!pdata) { - dev_err(&pdev->dev, "Missing pdata\n"); - return -ENODEV; - } - priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL); if (priv == NULL) return -ENOMEM; - if (pdata->card_name) { - card->name = pdata->card_name; + priv->dmic_codec_dev = ERR_PTR(-EINVAL); + + if (node) { + struct device_node *dai_node; + + if (snd_soc_of_parse_card_name(card, "ti,model")) { + dev_err(&pdev->dev, "Card name is not provided\n"); + return -ENODEV; + } + + ret = snd_soc_of_parse_audio_routing(card, + "ti,audio-routing"); + if (ret) { + dev_err(&pdev->dev, + "Error while parsing DAPM routing\n"); + return ret; + } + + dai_node = of_parse_phandle(node, "ti,mcpdm", 0); + if (!dai_node) { + dev_err(&pdev->dev, "McPDM node is not provided\n"); + return -EINVAL; + } + abe_twl6040_dai_links[0].cpu_dai_name = NULL; + abe_twl6040_dai_links[0].cpu_of_node = dai_node; + + dai_node = of_parse_phandle(node, "ti,dmic", 0); + if (dai_node) { + num_links = 2; + abe_twl6040_dai_links[1].cpu_dai_name = NULL; + abe_twl6040_dai_links[1].cpu_of_node = dai_node; + + priv->dmic_codec_dev = platform_device_register_simple( + "dmic-codec", -1, NULL, 0); + if (IS_ERR(priv->dmic_codec_dev)) { + dev_err(&pdev->dev, + "Can't instantiate dmic-codec\n"); + return PTR_ERR(priv->dmic_codec_dev); + } + } else { + num_links = 1; + } + + of_property_read_u32(node, "ti,jack-detection", + &priv->jack_detection); + of_property_read_u32(node, "ti,mclk-freq", + &priv->mclk_freq); + if (!priv->mclk_freq) { + dev_err(&pdev->dev, "MCLK frequency not provided\n"); + ret = -EINVAL; + goto err_unregister; + } + + omap_abe_card.fully_routed = 1; + } else if (pdata) { + if (pdata->card_name) { + card->name = pdata->card_name; + } else { + dev_err(&pdev->dev, "Card name is not provided\n"); + return -ENODEV; + } + + if (pdata->has_dmic) + num_links = 2; + else + num_links = 1; + + priv->jack_detection = pdata->jack_detection; + priv->mclk_freq = pdata->mclk_freq; } else { - dev_err(&pdev->dev, "Card name is not provided\n"); + dev_err(&pdev->dev, "Missing pdata\n"); return -ENODEV; } - priv->jack_detection = pdata->jack_detection; - priv->mclk_freq = pdata->mclk_freq; - if (!priv->mclk_freq) { dev_err(&pdev->dev, "MCLK frequency missing\n"); - return -ENODEV; + ret = -ENODEV; + goto err_unregister; } - if (pdata->has_dmic) - num_links = 2; - else - num_links = 1; - card->dai_link = abe_twl6040_dai_links; card->num_links = num_links; snd_soc_card_set_drvdata(card, priv); ret = snd_soc_register_card(card); - if (ret) + if (ret) { dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); + goto err_unregister; + } + + return 0; + +err_unregister: + if (!IS_ERR(priv->dmic_codec_dev)) + platform_device_unregister(priv->dmic_codec_dev); return ret; } @@ -323,17 +397,28 @@ static __devinit int omap_abe_probe(struct platform_device *pdev) static int __devexit omap_abe_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); + struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); snd_soc_unregister_card(card); + if (!IS_ERR(priv->dmic_codec_dev)) + platform_device_unregister(priv->dmic_codec_dev); + return 0; } +static const struct of_device_id omap_abe_of_match[] = { + {.compatible = "ti,abe-twl6040", }, + { }, +}; +MODULE_DEVICE_TABLE(of, omap_abe_of_match); + static struct platform_driver omap_abe_driver = { .driver = { .name = "omap-abe-twl6040", .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, + .of_match_table = omap_abe_of_match, }, .probe = omap_abe_probe, .remove = __devexit_p(omap_abe_remove), From acaf24f015b2bdd34032188d26c3092d6ca749b3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 25 Jul 2012 22:57:35 +0100 Subject: [PATCH 0191/5375] ASoC: jack: Always update jack state even for noop changes Now that DAPM is very cheap for most updates we've no need to avoid trying to run it so always notify even if we don't think there are any changes. This avoids potential issues with bootstrapping state like the pin state or other notifiers when there's nothing in the jack. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-jack.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index 7f8b3b7428bb..2ca3c734a288 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c @@ -83,11 +83,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) jack->status &= ~mask; jack->status |= status & mask; - /* The DAPM sync is expensive enough to be worth skipping. - * However, empty mask means pin synchronization is desired. */ - if (mask && (jack->status == oldstatus)) - goto out; - trace_snd_soc_jack_notify(jack, status); list_for_each_entry(pin, &jack->pins, list) { @@ -109,7 +104,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) snd_jack_report(jack->jack, jack->status); -out: mutex_unlock(&jack->mutex); } EXPORT_SYMBOL_GPL(snd_soc_jack_report); From 8cb8e83bfa7cb63ad4b3c3b79410766da397124b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 25 Jul 2012 18:10:03 +0100 Subject: [PATCH 0192/5375] ASoC: wm_hubs: Move CODEC stored in private data into wm_hubs Further wm_hubs code will use this. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8958-dsp2.c | 28 ++++++++++++++++------------ sound/soc/codecs/wm8994.c | 28 +++++++++++++--------------- sound/soc/codecs/wm8994.h | 1 - sound/soc/codecs/wm_hubs.c | 2 ++ sound/soc/codecs/wm_hubs.h | 2 ++ 5 files changed, 33 insertions(+), 28 deletions(-) diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 1332692ef81b..00121ba36597 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -946,7 +946,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->mbc_texts = kmalloc(sizeof(char *) * pdata->num_mbc_cfgs, GFP_KERNEL); if (!wm8994->mbc_texts) { - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to allocate %d MBC config texts\n", pdata->num_mbc_cfgs); return; @@ -958,9 +958,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->mbc_enum.max = pdata->num_mbc_cfgs; wm8994->mbc_enum.texts = wm8994->mbc_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, + control, 1); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add MBC mode controls: %d\n", ret); } @@ -974,7 +975,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->vss_texts = kmalloc(sizeof(char *) * pdata->num_vss_cfgs, GFP_KERNEL); if (!wm8994->vss_texts) { - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to allocate %d VSS config texts\n", pdata->num_vss_cfgs); return; @@ -986,9 +987,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->vss_enum.max = pdata->num_vss_cfgs; wm8994->vss_enum.texts = wm8994->vss_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, + control, 1); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add VSS mode controls: %d\n", ret); } @@ -1003,7 +1005,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->vss_hpf_texts = kmalloc(sizeof(char *) * pdata->num_vss_hpf_cfgs, GFP_KERNEL); if (!wm8994->vss_hpf_texts) { - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to allocate %d VSS HPF config texts\n", pdata->num_vss_hpf_cfgs); return; @@ -1015,9 +1017,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs; wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, + control, 1); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add VSS HPFmode controls: %d\n", ret); } @@ -1033,7 +1036,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->enh_eq_texts = kmalloc(sizeof(char *) * pdata->num_enh_eq_cfgs, GFP_KERNEL); if (!wm8994->enh_eq_texts) { - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to allocate %d enhanced EQ config texts\n", pdata->num_enh_eq_cfgs); return; @@ -1045,9 +1048,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs; wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, control, 1); + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, + control, 1); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add enhanced EQ controls: %d\n", ret); } diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 2c9b8b7fdf3d..1237c11c8c35 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3036,7 +3036,7 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec) static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) { - struct snd_soc_codec *codec = wm8994->codec; + struct snd_soc_codec *codec = wm8994->hubs.codec; struct wm8994_pdata *pdata = wm8994->pdata; struct snd_kcontrol_new controls[] = { SOC_ENUM_EXT("AIF1.1 EQ Mode", @@ -3094,16 +3094,16 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts; wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, controls, + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, ARRAY_SIZE(controls)); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add ReTune Mobile controls: %d\n", ret); } static void wm8994_handle_pdata(struct wm8994_priv *wm8994) { - struct snd_soc_codec *codec = wm8994->codec; + struct snd_soc_codec *codec = wm8994->hubs.codec; struct wm8994_pdata *pdata = wm8994->pdata; int ret, i; @@ -3132,10 +3132,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) }; /* We need an array of texts for the enum API */ - wm8994->drc_texts = devm_kzalloc(wm8994->codec->dev, + wm8994->drc_texts = devm_kzalloc(wm8994->hubs.codec->dev, sizeof(char *) * pdata->num_drc_cfgs, GFP_KERNEL); if (!wm8994->drc_texts) { - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to allocate %d DRC config texts\n", pdata->num_drc_cfgs); return; @@ -3147,10 +3147,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) wm8994->drc_enum.max = pdata->num_drc_cfgs; wm8994->drc_enum.texts = wm8994->drc_texts; - ret = snd_soc_add_codec_controls(wm8994->codec, controls, + ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, ARRAY_SIZE(controls)); if (ret != 0) - dev_err(wm8994->codec->dev, + dev_err(wm8994->hubs.codec->dev, "Failed to add DRC mode controls: %d\n", ret); for (i = 0; i < WM8994_NUM_DRC; i++) @@ -3163,7 +3163,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) if (pdata->num_retune_mobile_cfgs) wm8994_handle_retune_mobile_pdata(wm8994); else - snd_soc_add_codec_controls(wm8994->codec, wm8994_eq_controls, + snd_soc_add_codec_controls(wm8994->hubs.codec, wm8994_eq_controls, ARRAY_SIZE(wm8994_eq_controls)); for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) { @@ -3318,7 +3318,7 @@ static void wm8994_mic_work(struct work_struct *work) static irqreturn_t wm8994_mic_irq(int irq, void *data) { struct wm8994_priv *priv = data; - struct snd_soc_codec *codec = priv->codec; + struct snd_soc_codec *codec = priv->hubs.codec; #ifndef CONFIG_SND_SOC_WM8994_MODULE trace_snd_soc_jack_irq(dev_name(codec->dev)); @@ -3431,7 +3431,7 @@ static void wm8958_default_micdet(u16 status, void *data) static irqreturn_t wm1811_jackdet_irq(int irq, void *data) { struct wm8994_priv *wm8994 = data; - struct snd_soc_codec *codec = wm8994->codec; + struct snd_soc_codec *codec = wm8994->hubs.codec; int reg; bool present; @@ -3609,7 +3609,7 @@ EXPORT_SYMBOL_GPL(wm8958_mic_detect); static irqreturn_t wm8958_mic_irq(int irq, void *data) { struct wm8994_priv *wm8994 = data; - struct snd_soc_codec *codec = wm8994->codec; + struct snd_soc_codec *codec = wm8994->hubs.codec; int reg, count; /* @@ -3699,13 +3699,11 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) unsigned int reg; int ret, i; - wm8994->codec = codec; + wm8994->hubs.codec = codec; codec->control_data = control->regmap; snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP); - wm8994->codec = codec; - mutex_init(&wm8994->accdet_lock); INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work); diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 19068d8fa301..e6d8209b8f29 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -73,7 +73,6 @@ struct wm8994; struct wm8994_priv { struct wm_hubs_data hubs; struct wm8994 *wm8994; - struct snd_soc_codec *codec; int sysclk[2]; int sysclk_rate[2]; int mclk[2]; diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 61baa48823cb..728a18010a49 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -1112,6 +1112,8 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec, struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = &codec->dapm; + hubs->codec = codec; + INIT_LIST_HEAD(&hubs->dcs_cache); init_completion(&hubs->dcs_done); diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index da2dc899ce6d..a5a09e6f87d5 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h @@ -46,6 +46,8 @@ struct wm_hubs_data { bool dcs_done_irq; struct completion dcs_done; + + struct snd_soc_codec *codec; }; extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); From 99af79dff5a609fe886d271bbc91e1a95eca3066 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 25 Jul 2012 23:03:36 +0100 Subject: [PATCH 0193/5375] ASoC: wm8994: Ensure we get a notification on startup for jackdet Since jackdet only reports deltas it won't generate an interrupt on startup when a jack is not present. This doesn't make a difference to userspace but does mean we don't generate a notification via the internal notifier chains. Fix that by scheduling a work to poll the chip after the clock is enabled. Use an extremely large timeout since there's no urgency and we don't want to report a false negative. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 37 ++++++++++++++++++++++++++++++++++++- sound/soc/codecs/wm8994.h | 2 ++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 1237c11c8c35..7bb0c2c824cc 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -789,11 +789,27 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_PRE_PMU: return configure_clock(codec); + case SND_SOC_DAPM_POST_PMU: + /* + * JACKDET won't run until we start the clock and it + * only reports deltas, make sure we notify the state + * up the stack on startup. Use a *very* generous + * timeout for paranoia, there's no urgency and we + * don't want false reports. + */ + if (wm8994->jackdet && !wm8994->clk_has_run) { + schedule_delayed_work(&wm8994->jackdet_bootstrap, + msecs_to_jiffies(1000)); + wm8994->clk_has_run = true; + } + break; + case SND_SOC_DAPM_POST_PMD: configure_clock(codec); break; @@ -1632,7 +1648,8 @@ SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, 3, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DSP2CLK", SND_SOC_NOPM, 2, 0, NULL, 0), @@ -3508,10 +3525,22 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) SND_JACK_MECHANICAL | SND_JACK_HEADSET | wm8994->btn_mask); + /* Since we only report deltas force an update, ensures we + * avoid bootstrapping issues with the core. */ + snd_soc_jack_report(wm8994->micdet[0].jack, 0, 0); + pm_runtime_put(codec->dev); return IRQ_HANDLED; } +static void wm1811_jackdet_bootstrap(struct work_struct *work) +{ + struct wm8994_priv *wm8994 = container_of(work, + struct wm8994_priv, + jackdet_bootstrap.work); + wm1811_jackdet_irq(0, wm8994); +} + /** * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ * @@ -3582,6 +3611,10 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, * otherwise jump straight to microphone detection. */ if (wm8994->jackdet) { + /* Disable debounce for the initial detect */ + snd_soc_update_bits(codec, WM1811_JACKDET_CTRL, + WM1811_JACKDET_DB, 0); + snd_soc_update_bits(codec, WM8958_MICBIAS2, WM8958_MICB2_DISCH, WM8958_MICB2_DISCH); @@ -3706,6 +3739,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) mutex_init(&wm8994->accdet_lock); INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work); + INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, + wm1811_jackdet_bootstrap); for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) init_completion(&wm8994->fll_locked[i]); diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index e6d8209b8f29..f142ec198db3 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -81,6 +81,7 @@ struct wm8994_priv { struct completion fll_locked[2]; bool fll_locked_irq; bool fll_byp; + bool clk_has_run; int vmid_refcount; int active_refcount; @@ -134,6 +135,7 @@ struct wm8994_priv { int btn_mask; bool jackdet; int jackdet_mode; + struct delayed_work jackdet_bootstrap; wm8958_micdet_cb jack_cb; void *jack_cb_data; From fae4efa23ac012a57d45682bc22d540271c54532 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Jul 2012 19:49:06 +0100 Subject: [PATCH 0194/5375] ASoC: wm_hubs: Factor out DC servo readback code It's currently only used in one place but another user will be added shortly and there's an argument it's clearer anyway. Also add support for readback in mode 1, though it's not currently used. Signed-off-by: Mark Brown --- sound/soc/codecs/wm_hubs.c | 65 +++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 728a18010a49..6ab69f32f249 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -199,6 +199,47 @@ static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg) list_add_tail(&cache->list, &hubs->dcs_cache); } +static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec, + u16 *reg_l, u16 *reg_r) +{ + struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); + u16 dcs_reg, reg; + + switch (hubs->dcs_readback_mode) { + case 2: + dcs_reg = WM8994_DC_SERVO_4E; + break; + case 1: + dcs_reg = WM8994_DC_SERVO_READBACK; + break; + default: + dcs_reg = WM8993_DC_SERVO_3; + break; + } + + /* Different chips in the family support different readback + * methods. + */ + switch (hubs->dcs_readback_mode) { + case 0: + *reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1) + & WM8993_DCS_INTEG_CHAN_0_MASK; + *reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) + & WM8993_DCS_INTEG_CHAN_1_MASK; + break; + case 2: + case 1: + reg = snd_soc_read(codec, dcs_reg); + *reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) + >> WM8993_DCS_DAC_WR_VAL_1_SHIFT; + *reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; + break; + default: + WARN(1, "Unknown DCS readback method\n"); + return; + } +} + /* * Startup calibration of the DC servo */ @@ -207,7 +248,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); struct wm_hubs_dcs_cache *cache; s8 offset; - u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg; + u16 reg_l, reg_r, dcs_cfg, dcs_reg; switch (hubs->dcs_readback_mode) { case 2: @@ -245,27 +286,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) WM8993_DCS_TRIG_STARTUP_1); } - /* Different chips in the family support different readback - * methods. - */ - switch (hubs->dcs_readback_mode) { - case 0: - reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1) - & WM8993_DCS_INTEG_CHAN_0_MASK; - reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) - & WM8993_DCS_INTEG_CHAN_1_MASK; - break; - case 2: - case 1: - reg = snd_soc_read(codec, dcs_reg); - reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) - >> WM8993_DCS_DAC_WR_VAL_1_SHIFT; - reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; - break; - default: - WARN(1, "Unknown DCS readback method\n"); - return; - } + wm_hubs_read_dc_servo(codec, ®_l, ®_r); dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r); From a7892c35cfad4d6c6ccf1242b55c1004b0d5d1d1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Jul 2012 19:50:45 +0100 Subject: [PATCH 0195/5375] ASoC: wm_hubs: Rename calibrate_dc_servo() Really we're enabling it here and the name will become very confusing shortly. Signed-off-by: Mark Brown --- sound/soc/codecs/wm_hubs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 6ab69f32f249..05a02e1b7e92 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -243,7 +243,7 @@ static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec, /* * Startup calibration of the DC servo */ -static void calibrate_dc_servo(struct snd_soc_codec *codec) +static void enable_dc_servo(struct snd_soc_codec *codec) { struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); struct wm_hubs_dcs_cache *cache; @@ -556,7 +556,7 @@ static int hp_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WM8993_DC_SERVO_1, WM8993_DCS_TIMER_PERIOD_01_MASK, 0); - calibrate_dc_servo(codec); + enable_dc_servo(codec); reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; From 7435d4eec76ee9debffb070f3e0d67615a828673 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 26 Jul 2012 14:49:11 +0100 Subject: [PATCH 0196/5375] ASoC: wm8994: Fix some indentation issues Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 7bb0c2c824cc..5fc31797994a 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2182,7 +2182,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset, WM8994_FLL1_N_MASK, - fll.n << WM8994_FLL1_N_SHIFT); + fll.n << WM8994_FLL1_N_SHIFT); snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP | @@ -3371,7 +3371,7 @@ static void wm8958_default_micdet(u16 status, void *data) snd_soc_jack_report(wm8994->micdet[0].jack, 0, wm8994->btn_mask | - SND_JACK_HEADSET); + SND_JACK_HEADSET); } return; } From d95e933730b3eb7b06bd778dc1d8f0ab3702b607 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 26 Jul 2012 15:25:48 +0100 Subject: [PATCH 0197/5375] ASoC: ab8500: Remove pointless cast There's never any need to cast away from void. Signed-off-by: Mark Brown Acked-by: Lee Jones --- sound/soc/codecs/ab8500-codec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 23b40186f9b8..b7836503dc69 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2404,12 +2404,12 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) dev_dbg(dev, "%s: Enter.\n", __func__); - /* Setup AB8500 according to board-settings */ - pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent); - /* Inform SoC Core that we have our own I/O arrangements. */ codec->control_data = (void *)true; + /* Setup AB8500 according to board-settings */ + pdata = dev_get_platdata(dev->parent); + status = ab8500_audio_setup_mics(codec, &pdata->codec->amics); if (status < 0) { pr_err("%s: Failed to setup mics (%d)!\n", __func__, status); From d9f34df782b2aa7d233cb08850c8b12fdb37d18a Mon Sep 17 00:00:00 2001 From: Chris Rattray Date: Tue, 31 Jul 2012 14:51:34 +0100 Subject: [PATCH 0198/5375] ASoC: wm8994: enable mic and short detect debounce. Signed-off-by: Chris Rattray Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 5fc31797994a..02080da8b451 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -3262,6 +3262,12 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg); + /* enable MICDET and MICSHRT deboune */ + snd_soc_update_bits(codec, WM8994_IRQ_DEBOUNCE, + WM8994_MIC1_DET_DB_MASK | WM8994_MIC1_SHRT_DB_MASK | + WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK, + WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB); + snd_soc_dapm_sync(&codec->dapm); return 0; From 85d07e4d625d6511934799f7df93e9111ac2c88b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 25 Jul 2012 15:28:34 +0200 Subject: [PATCH 0199/5375] ASoC: add DT bindings for cs4270 Signed-off-by: Daniel Mack Acked-by: Timur Tabi Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/cs4270.txt | 16 ++++++++++++++++ sound/soc/codecs/cs4270.c | 11 +++++++++++ 2 files changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cs4270.txt diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt new file mode 100644 index 000000000000..7f0bfd84d3fc --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs4270.txt @@ -0,0 +1,16 @@ +CS4270 audio CODEC + +The driver for this device currently only supports I2C. + +Required properties: + + - compatible : "cirrus,cs4270" + + - reg : the I2C address of the device for I2C + +Example: + +codec: cs4270@48 { + compatible = "cirrus,cs4270"; + reg = <0x48>; +}; diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 047917f0b8ae..4b71b01ecbcd 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -29,6 +29,7 @@ #include #include #include +#include /* * The codec isn't really big-endian or little-endian, since the I2S @@ -639,6 +640,15 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { .reg_cache_default = cs4270_default_reg_cache, }; +/* + * cs4270_of_match - the device tree bindings + */ +static const struct of_device_id cs4270_of_match[] = { + { .compatible = "cirrus,cs4270", }, + { } +}; +MODULE_DEVICE_TABLE(of, cs4270_of_match); + /** * cs4270_i2c_probe - initialize the I2C interface of the CS4270 * @i2c_client: the I2C client object @@ -718,6 +728,7 @@ static struct i2c_driver cs4270_i2c_driver = { .driver = { .name = "cs4270", .owner = THIS_MODULE, + .of_match_table = cs4270_of_match, }, .id_table = cs4270_id, .probe = cs4270_i2c_probe, From 02286190f3ec86f03025a60c4d3f747ff1047248 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 25 Jul 2012 15:28:35 +0200 Subject: [PATCH 0200/5375] ASoC: Add reset-gpio DT property to cs4270 driver In the process of moving over from static board files to the device tree, reset pins of peripheral reset pins should be handled by their corresponding drivers. Add a reset-gpio DT property to the cs4270 driver, and de-assert it before probing the chip. The logic could be augmented some day to re-assert it when codec is put to suspend. Signed-off-by: Daniel Mack Acked-by: Timur Tabi Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/cs4270.txt | 5 +++++ sound/soc/codecs/cs4270.c | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt index 7f0bfd84d3fc..6b222f9b8ef5 100644 --- a/Documentation/devicetree/bindings/sound/cs4270.txt +++ b/Documentation/devicetree/bindings/sound/cs4270.txt @@ -8,6 +8,11 @@ Required properties: - reg : the I2C address of the device for I2C +Optional properties: + + - reset-gpio : a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + Example: codec: cs4270@48 { diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 4b71b01ecbcd..fd11bb646d40 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -30,6 +30,7 @@ #include #include #include +#include /* * The codec isn't really big-endian or little-endian, since the I2S @@ -660,9 +661,25 @@ MODULE_DEVICE_TABLE(of, cs4270_of_match); static int cs4270_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { + struct device_node *np = i2c_client->dev.of_node; struct cs4270_private *cs4270; int ret; + /* See if we have a way to bring the codec out of reset */ + if (np) { + enum of_gpio_flags flags; + int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); + + if (gpio_is_valid(gpio)) { + ret = devm_gpio_request_one(&i2c_client->dev, gpio, + flags & OF_GPIO_ACTIVE_LOW ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, + "cs4270 reset"); + if (ret < 0) + return ret; + } + } + /* Verify that we have a CS4270 */ ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); From ad3ab1bba9bf3fcd13a4e3f868a438013174dcc1 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 27 Jul 2012 14:32:10 -0300 Subject: [PATCH 0201/5375] ASoC: imx-ssi: Use devm functions Using devm_ functions can make the code simpler and smaller. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-ssi.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 28dd76c7cb1c..e174c1767c2d 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -523,7 +523,7 @@ static int imx_ssi_probe(struct platform_device *pdev) int ret = 0; struct snd_soc_dai_driver *dai; - ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); + ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL); if (!ssi) return -ENOMEM; dev_set_drvdata(&pdev->dev, ssi); @@ -536,7 +536,7 @@ static int imx_ssi_probe(struct platform_device *pdev) ssi->irq = platform_get_irq(pdev, 0); - ssi->clk = clk_get(&pdev->dev, NULL); + ssi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ssi->clk)) { ret = PTR_ERR(ssi->clk); dev_err(&pdev->dev, "Cannot get the clock: %d\n", @@ -551,23 +551,17 @@ static int imx_ssi_probe(struct platform_device *pdev) goto failed_get_resource; } - if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - ret = -EBUSY; - goto failed_get_resource; - } - - ssi->base = ioremap(res->start, resource_size(res)); + ssi->base = devm_request_and_ioremap(&pdev->dev, res); if (!ssi->base) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENODEV; - goto failed_ioremap; + goto failed_register; } if (ssi->flags & IMX_SSI_USE_AC97) { if (ac97_ssi) { ret = -EBUSY; - goto failed_ac97; + goto failed_register; } ac97_ssi = ssi; setup_channel_to_ac97(ssi); @@ -636,15 +630,10 @@ failed_pdev_fiq_add: failed_pdev_fiq_alloc: snd_soc_unregister_dai(&pdev->dev); failed_register: -failed_ac97: - iounmap(ssi->base); -failed_ioremap: release_mem_region(res->start, resource_size(res)); failed_get_resource: clk_disable_unprepare(ssi->clk); - clk_put(ssi->clk); failed_clk: - kfree(ssi); return ret; } @@ -662,11 +651,8 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev) if (ssi->flags & IMX_SSI_USE_AC97) ac97_ssi = NULL; - iounmap(ssi->base); release_mem_region(res->start, resource_size(res)); clk_disable_unprepare(ssi->clk); - clk_put(ssi->clk); - kfree(ssi); return 0; } From 9a37eae230e7350ba803801404a022e098016e56 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 31 Jul 2012 18:37:30 +0100 Subject: [PATCH 0202/5375] ASoC: wm9712: Fix funky indentation Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index f16fb361a4eb..3fefa6e8e451 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -684,8 +684,8 @@ static int __devexit wm9712_remove(struct platform_device *pdev) static struct platform_driver wm9712_codec_driver = { .driver = { - .name = "wm9712-codec", - .owner = THIS_MODULE, + .name = "wm9712-codec", + .owner = THIS_MODULE, }, .probe = wm9712_probe, From 689185b78ba6fbe0042f662a468b5565909dff7a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 31 Jul 2012 18:37:29 +0100 Subject: [PATCH 0203/5375] ASoC: wm9712: Fix name of Capture Switch Help UIs associate it with the matching gain control. Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 3fefa6e8e451..c9c696ca76f7 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -146,7 +146,7 @@ SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0), SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1), SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1), -SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1), +SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1), SOC_ENUM("Capture Volume Steps", wm9712_enum[6]), SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1), SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0), From 1427cc37b6c073e83309565bfebad25fb6cd9182 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 1 Aug 2012 19:25:50 +0100 Subject: [PATCH 0204/5375] ASoC: sta529: Staticise non-exported codec driver struct Signed-off-by: Mark Brown --- sound/soc/codecs/sta529.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 0c225cd569d2..9e3144862386 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -358,7 +358,7 @@ static int sta529_resume(struct snd_soc_codec *codec) return 0; } -struct snd_soc_codec_driver sta529_codec_driver = { +static const struct snd_soc_codec_driver sta529_codec_driver = { .probe = sta529_probe, .remove = sta529_remove, .set_bias_level = sta529_set_bias_level, From c79b339f92921fe73ac32ac2ae49a5b549dfc1f2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 23 May 2012 10:06:09 -0300 Subject: [PATCH 0205/5375] [media] dvb_usb_v2: copy current dvb_usb as a starting point Use current implementation as a starting point for the new one. [mchehab@redhat.com: remove the new files from the build system, as the symbols there conflict with the existing ones] Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 485 +++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb_usb_common.h | 52 ++ drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 289 +++++++++++ drivers/media/dvb/dvb-usb/dvb_usb_firmware.c | 146 ++++++ drivers/media/dvb/dvb-usb/dvb_usb_i2c.c | 43 ++ drivers/media/dvb/dvb-usb/dvb_usb_init.c | 304 ++++++++++++ drivers/media/dvb/dvb-usb/dvb_usb_remote.c | 391 +++++++++++++++ drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 121 +++++ drivers/media/dvb/dvb-usb/usb_urb.c | 254 ++++++++++ 9 files changed, 2085 insertions(+) create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb.h create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_common.h create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_dvb.c create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_firmware.c create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_i2c.c create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_init.c create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_remote.c create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_urb.c create mode 100644 drivers/media/dvb/dvb-usb/usb_urb.c diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h new file mode 100644 index 000000000000..95caac116e8e --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -0,0 +1,485 @@ +/* dvb-usb.h is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * the headerfile, all dvb-usb-drivers have to include. + * + * TODO: clean-up the structures for unused fields and update the comments + */ +#ifndef DVB_USB_H +#define DVB_USB_H + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb_demux.h" +#include "dvb_net.h" +#include "dmxdev.h" + +#include "dvb-pll.h" + +#include "dvb-usb-ids.h" + +/* debug */ +#ifdef CONFIG_DVB_USB_DEBUG +#define dprintk(var,level,args...) \ + do { if ((var & level)) { printk(args); } } while (0) + +#define debug_dump(b,l,func) {\ + int loop_; \ + for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \ + func("\n");\ +} +#define DVB_USB_DEBUG_STATUS +#else +#define dprintk(args...) +#define debug_dump(b,l,func) + +#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" + +#endif + +/* generic log methods - taken from usb.h */ +#ifndef DVB_USB_LOG_PREFIX + #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)" +#endif + +#undef err +#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef info +#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) + +/** + * struct dvb_usb_device_description - name and its according USB IDs + * @name: real name of the box, regardless which DVB USB device class is in use + * @cold_ids: array of struct usb_device_id which describe the device in + * pre-firmware state + * @warm_ids: array of struct usb_device_id which describe the device in + * post-firmware state + * + * Each DVB USB device class can have one or more actual devices, this struct + * assigns a name to it. + */ +struct dvb_usb_device_description { + const char *name; + +#define DVB_USB_ID_MAX_NUM 15 + struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM]; + struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM]; +}; + +static inline u8 rc5_custom(struct rc_map_table *key) +{ + return (key->scancode >> 8) & 0xff; +} + +static inline u8 rc5_data(struct rc_map_table *key) +{ + return key->scancode & 0xff; +} + +static inline u16 rc5_scan(struct rc_map_table *key) +{ + return key->scancode & 0xffff; +} + +struct dvb_usb_device; +struct dvb_usb_adapter; +struct usb_data_stream; + +/** + * Properties of USB streaming - TODO this structure should be somewhere else + * describes the kind of USB transfer used for data-streaming. + * (BULK or ISOC) + */ +struct usb_data_stream_properties { +#define USB_BULK 1 +#define USB_ISOC 2 + int type; + int count; + int endpoint; + + union { + struct { + int buffersize; /* per URB */ + } bulk; + struct { + int framesperurb; + int framesize; + int interval; + } isoc; + } u; +}; + +/** + * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter. + * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device. + * @caps: capabilities of the DVB USB device. + * @pid_filter_count: number of PID filter position in the optional hardware + * PID-filter. + * @num_frontends: number of frontends of the DVB USB adapter. + * @frontend_ctrl: called to power on/off active frontend. + * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the + * device (not URB submitting/killing). + * @pid_filter_ctrl: called to en/disable the PID filter, if any. + * @pid_filter: called to set/unset a PID for filtering. + * @frontend_attach: called to attach the possible frontends (fill fe-field + * of struct dvb_usb_device). + * @tuner_attach: called to attach the correct tuner and to fill pll_addr, + * pll_desc and pll_init_buf of struct dvb_usb_device). + * @stream: configuration of the USB streaming + */ +struct dvb_usb_adapter_fe_properties { +#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 +#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 +#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 +#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 +#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD 0x10 + int caps; + int pid_filter_count; + + int (*streaming_ctrl) (struct dvb_usb_adapter *, int); + int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); + int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); + + int (*frontend_attach) (struct dvb_usb_adapter *); + int (*tuner_attach) (struct dvb_usb_adapter *); + + struct usb_data_stream_properties stream; + + int size_of_priv; +}; + +#define MAX_NO_OF_FE_PER_ADAP 3 +struct dvb_usb_adapter_properties { + int size_of_priv; + + int (*frontend_ctrl) (struct dvb_frontend *, int); + int (*fe_ioctl_override) (struct dvb_frontend *, + unsigned int, void *, unsigned int); + + int num_frontends; + struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP]; +}; + +/** + * struct dvb_rc_legacy - old properties of remote controller + * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable + * remote control handling). + * @rc_map_size: number of items in @rc_map_table. + * @rc_query: called to query an event event. + * @rc_interval: time in ms between two queries. + */ +struct dvb_rc_legacy { +/* remote control properties */ +#define REMOTE_NO_KEY_PRESSED 0x00 +#define REMOTE_KEY_PRESSED 0x01 +#define REMOTE_KEY_REPEAT 0x02 + struct rc_map_table *rc_map_table; + int rc_map_size; + int (*rc_query) (struct dvb_usb_device *, u32 *, int *); + int rc_interval; +}; + +/** + * struct dvb_rc properties of remote controller, using rc-core + * @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. + * @bulk_mode: device supports bulk mode for RC (disable polling mode) + */ +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); + int rc_interval; + bool bulk_mode; /* uses bulk mode */ +}; + +/** + * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one + * based on rc-core + * This is initialized/used only inside dvb-usb-remote.c. + * It shouldn't be set by the drivers. + */ +enum dvb_usb_mode { + DVB_RC_LEGACY, + DVB_RC_CORE, +}; + +/** + * struct dvb_usb_device_properties - properties of a dvb-usb-device + * @usb_ctrl: which USB device-side controller is in use. Needed for firmware + * download. + * @firmware: name of the firmware file. + * @download_firmware: called to download the firmware when the usb_ctrl is + * DEVICE_SPECIFIC. + * @no_reconnect: device doesn't do a reconnect after downloading the firmware, + * so do the warm initialization right after it + * + * @size_of_priv: how many bytes shall be allocated for the private field + * of struct dvb_usb_device. + * + * @power_ctrl: called to enable/disable power of the device. + * @read_mac_address: called to read the MAC address of the device. + * @identify_state: called to determine the state (cold or warm), when it + * is not distinguishable by the USB IDs. + * + * @rc: remote controller properties + * + * @i2c_algo: i2c_algorithm if the device has I2CoverUSB. + * + * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic + * endpoint which received control messages with bulk transfers. When this + * is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write- + * helper functions. + * + * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate + * endpoint for responses to control messages sent with bulk transfers via + * the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used + * instead of the generic_bulk_ctrl_endpoint when reading usb responses in + * the dvb_usb_generic_rw helper function. + * + * @num_device_descs: number of struct dvb_usb_device_description in @devices + * @devices: array of struct dvb_usb_device_description compatibles with these + * properties. + */ +#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 +struct dvb_usb_device_properties { + +#define DVB_USB_IS_AN_I2C_ADAPTER 0x01 + int caps; + +#define DEVICE_SPECIFIC 0 +#define CYPRESS_AN2135 1 +#define CYPRESS_AN2235 2 +#define CYPRESS_FX2 3 + int usb_ctrl; + int (*download_firmware) (struct usb_device *, const struct firmware *); + const char *firmware; + int no_reconnect; + + int size_of_priv; + + int num_adapters; + struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + + int (*power_ctrl) (struct dvb_usb_device *, int); + int (*read_mac_address) (struct dvb_usb_device *, u8 []); + int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *, + struct dvb_usb_device_description **, int *); + + struct { + enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */ + struct dvb_rc_legacy legacy; + struct dvb_rc core; + } rc; + + struct i2c_algorithm *i2c_algo; + + int generic_bulk_ctrl_endpoint; + int generic_bulk_ctrl_endpoint_response; + + int num_device_descs; + struct dvb_usb_device_description devices[12]; +}; + +/** + * struct usb_data_stream - generic object of an USB stream + * @buf_num: number of buffer allocated. + * @buf_size: size of each buffer in buf_list. + * @buf_list: array containing all allocate buffers for streaming. + * @dma_addr: list of dma_addr_t for each buffer in buf_list. + * + * @urbs_initialized: number of URBs initialized. + * @urbs_submitted: number of URBs submitted. + */ +#define MAX_NO_URBS_FOR_DATA_STREAM 10 +struct usb_data_stream { + struct usb_device *udev; + struct usb_data_stream_properties props; + +#define USB_STATE_INIT 0x00 +#define USB_STATE_URB_BUF 0x01 + int state; + + void (*complete) (struct usb_data_stream *, u8 *, size_t); + + struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM]; + int buf_num; + unsigned long buf_size; + u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM]; + dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM]; + + int urbs_initialized; + int urbs_submitted; + + void *user_priv; +}; + +/** + * struct dvb_usb_adapter - a DVB adapter on a USB device + * @id: index of this adapter (starting with 0). + * + * @feedcount: number of reqested feeds (used for streaming-activation) + * @pid_filtering: is hardware pid_filtering used or not. + * + * @pll_addr: I2C address of the tuner for programming + * @pll_init: array containing the initialization buffer + * @pll_desc: pointer to the appropriate struct dvb_pll_desc + * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board + * + * @dvb_adap: device's dvb_adapter. + * @dmxdev: device's dmxdev. + * @demux: device's software demuxer. + * @dvb_net: device's dvb_net interfaces. + * @dvb_frontend: device's frontend. + * @max_feed_count: how many feeds can be handled simultaneously by this + * device + * + * @fe_init: rerouted frontend-init (wakeup) function. + * @fe_sleep: rerouted frontend-sleep function. + * + * @stream: the usb data stream. + */ +struct dvb_usb_fe_adapter { + struct dvb_frontend *fe; + + int (*fe_init) (struct dvb_frontend *); + int (*fe_sleep) (struct dvb_frontend *); + + struct usb_data_stream stream; + + int pid_filtering; + int max_feed_count; + + void *priv; +}; + +struct dvb_usb_adapter { + struct dvb_usb_device *dev; + struct dvb_usb_adapter_properties props; + +#define DVB_USB_ADAP_STATE_INIT 0x000 +#define DVB_USB_ADAP_STATE_DVB 0x001 + int state; + + u8 id; + + int feedcount; + + /* dvb */ + struct dvb_adapter dvb_adap; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dvb_net dvb_net; + + struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP]; + int active_fe; + int num_frontends_initialized; + + void *priv; +}; + +/** + * struct dvb_usb_device - object of a DVB USB device + * @props: copy of the struct dvb_usb_properties this device belongs to. + * @desc: pointer to the device's struct dvb_usb_device_description. + * @state: initialization and runtime state of the device. + * + * @powered: indicated whether the device is power or not. + * Powered is in/decremented for each call to modify the state. + * @udev: pointer to the device's struct usb_device. + * + * @usb_mutex: semaphore of USB control messages (reading needs two messages) + * @i2c_mutex: semaphore for i2c-transfers + * + * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB + * + * @rc_dev: rc device for the remote control (rc-core mode) + * @input_dev: input device for the remote control (legacy mode) + * @rc_query_work: struct work_struct frequent rc queries + * @last_event: last triggered event + * @last_state: last state (no, pressed, repeat) + * @owner: owner of the dvb_adapter + * @priv: private data of the actual driver (allocate by dvb-usb, size defined + * in size_of_priv of dvb_usb_properties). + */ +struct dvb_usb_device { + struct dvb_usb_device_properties props; + struct dvb_usb_device_description *desc; + + struct usb_device *udev; + +#define DVB_USB_STATE_INIT 0x000 +#define DVB_USB_STATE_I2C 0x001 +#define DVB_USB_STATE_DVB 0x002 +#define DVB_USB_STATE_REMOTE 0x004 + int state; + + int powered; + + /* locking */ + struct mutex usb_mutex; + + /* i2c */ + struct mutex i2c_mutex; + struct i2c_adapter i2c_adap; + + int num_adapters_initialized; + struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + + /* remote control */ + struct rc_dev *rc_dev; + struct input_dev *input_dev; + char rc_phys[64]; + struct delayed_work rc_query_work; + u32 last_event; + int last_state; + + struct module *owner; + + void *priv; +}; + +extern int dvb_usbv2_device_init(struct usb_interface *, + struct dvb_usb_device_properties *, + struct module *, struct dvb_usb_device **, + short *adapter_nums); +extern void dvb_usbv2_device_exit(struct usb_interface *); + +/* the generic read/write method for device control */ +extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int); +extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16); + +/* commonly used remote control parsing */ +extern int dvb_usbv2_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); + +/* commonly used firmware download types and function */ +struct hexline { + u8 len; + u32 addr; + u8 type; + u8 data[255]; + u8 chk; +}; +extern int usbv2_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type); +extern int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos); + + +#endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h new file mode 100644 index 000000000000..29df53999a9c --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -0,0 +1,52 @@ +/* dvb-usb-common.h is part of the DVB USB library. + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * a header file containing prototypes and types for internal use of the dvb-usb-lib + */ +#ifndef DVB_USB_COMMON_H +#define DVB_USB_COMMON_H + +#define DVB_USB_LOG_PREFIX "dvb_usb" +#include "dvb_usb.h" + +extern int dvb_usb_debug; +extern int dvb_usb_disable_rc_polling; + +#define deb_info(args...) dprintk(dvb_usb_debug,0x001,args) +#define deb_xfer(args...) dprintk(dvb_usb_debug,0x002,args) +#define deb_pll(args...) dprintk(dvb_usb_debug,0x004,args) +#define deb_ts(args...) dprintk(dvb_usb_debug,0x008,args) +#define deb_err(args...) dprintk(dvb_usb_debug,0x010,args) +#define deb_rc(args...) dprintk(dvb_usb_debug,0x020,args) +#define deb_fw(args...) dprintk(dvb_usb_debug,0x040,args) +#define deb_mem(args...) dprintk(dvb_usb_debug,0x080,args) +#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args) + +/* commonly used methods */ +extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *); + +extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); + +extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props); +extern int usb_urb_exit(struct usb_data_stream *stream); +extern int usb_urb_submit(struct usb_data_stream *stream); +extern int usb_urb_kill(struct usb_data_stream *stream); + +extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap); + +extern int dvb_usb_i2c_init(struct dvb_usb_device *); +extern int dvb_usb_i2c_exit(struct dvb_usb_device *); + +extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, + short *adapter_nums); +extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap); +extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap); + +extern int dvb_usb_remote_init(struct dvb_usb_device *); +extern int dvb_usb_remote_exit(struct dvb_usb_device *); + +#endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c new file mode 100644 index 000000000000..59cc26cb24c5 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -0,0 +1,289 @@ +/* dvb-usb-dvb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for initializing and handling the + * linux-dvb API. + */ +#include "dvb_usb_common.h" + +/* does the complete input transfer handling */ +static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; + int newfeedcount, ret; + + if (adap == NULL) + return -ENODEV; + + if ((adap->active_fe < 0) || + (adap->active_fe >= adap->num_frontends_initialized)) { + return -EINVAL; + } + + newfeedcount = adap->feedcount + (onoff ? 1 : -1); + + /* stop feed before setting a new pid if there will be no pid anymore */ + if (newfeedcount == 0) { + deb_ts("stop feeding\n"); + usb_urb_kill(&adap->fe_adap[adap->active_fe].stream); + + if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { + ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0); + if (ret < 0) { + err("error while stopping stream."); + return ret; + } + } + } + + adap->feedcount = newfeedcount; + + /* activate the pid on the device specific pid_filter */ + deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n", + adap->fe_adap[adap->active_fe].pid_filtering ? + "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid, + dvbdmxfeed->index, onoff ? "on" : "off"); + if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->fe_adap[adap->active_fe].pid_filtering && + adap->props.fe[adap->active_fe].pid_filter != NULL) + adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); + + /* start the feed if this was the first feed and there is still a feed + * for reception. + */ + if (adap->feedcount == onoff && adap->feedcount > 0) { + deb_ts("submitting all URBs\n"); + usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); + + deb_ts("controlling pid parser\n"); + if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props.fe[adap->active_fe].caps & + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && + adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) { + ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap, + adap->fe_adap[adap->active_fe].pid_filtering); + if (ret < 0) { + err("could not handle pid_parser"); + return ret; + } + } + deb_ts("start feeding\n"); + if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { + ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1); + if (ret < 0) { + err("error while enabling fifo."); + return ret; + } + } + + } + return 0; +} + +static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type); + return dvb_usb_ctrl_feed(dvbdmxfeed,1); +} + +static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type); + return dvb_usb_ctrl_feed(dvbdmxfeed,0); +} + +int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) +{ + int i; + int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name, + adap->dev->owner, &adap->dev->udev->dev, + adapter_nums); + + if (ret < 0) { + deb_info("dvb_register_adapter failed: error %d", ret); + goto err; + } + adap->dvb_adap.priv = adap; + adap->dvb_adap.fe_ioctl_override = adap->props.fe_ioctl_override; + + if (adap->dev->props.read_mac_address) { + if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0) + info("MAC address: %pM",adap->dvb_adap.proposed_mac); + else + err("MAC address reading failed."); + } + + + adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + adap->demux.priv = adap; + + adap->demux.filternum = 0; + for (i = 0; i < adap->props.num_frontends; i++) { + if (adap->demux.filternum < adap->fe_adap[i].max_feed_count) + adap->demux.filternum = adap->fe_adap[i].max_feed_count; + } + adap->demux.feednum = adap->demux.filternum; + adap->demux.start_feed = dvb_usb_start_feed; + adap->demux.stop_feed = dvb_usb_stop_feed; + adap->demux.write_to_decoder = NULL; + if ((ret = dvb_dmx_init(&adap->demux)) < 0) { + err("dvb_dmx_init failed: error %d",ret); + goto err_dmx; + } + + adap->dmxdev.filternum = adap->demux.filternum; + adap->dmxdev.demux = &adap->demux.dmx; + adap->dmxdev.capabilities = 0; + if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) { + err("dvb_dmxdev_init failed: error %d",ret); + goto err_dmx_dev; + } + + if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, + &adap->demux.dmx)) < 0) { + err("dvb_net_init failed: error %d",ret); + goto err_net_init; + } + + adap->state |= DVB_USB_ADAP_STATE_DVB; + return 0; + +err_net_init: + dvb_dmxdev_release(&adap->dmxdev); +err_dmx_dev: + dvb_dmx_release(&adap->demux); +err_dmx: + dvb_unregister_adapter(&adap->dvb_adap); +err: + return ret; +} + +int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) +{ + if (adap->state & DVB_USB_ADAP_STATE_DVB) { + deb_info("unregistering DVB part\n"); + dvb_net_release(&adap->dvb_net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->dvb_adap); + adap->state &= ~DVB_USB_ADAP_STATE_DVB; + } + return 0; +} + +static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + int ret = (adap->props.frontend_ctrl) ? + adap->props.frontend_ctrl(fe, onoff) : 0; + + if (ret < 0) { + err("frontend_ctrl request failed"); + return ret; + } + if (onoff) + adap->active_fe = fe->id; + + return 0; +} + +static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + dvb_usb_device_power_ctrl(adap->dev, 1); + + dvb_usb_set_active_fe(fe, 1); + + if (adap->fe_adap[fe->id].fe_init) + adap->fe_adap[fe->id].fe_init(fe); + + return 0; +} + +static int dvb_usb_fe_sleep(struct dvb_frontend *fe) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + if (adap->fe_adap[fe->id].fe_sleep) + adap->fe_adap[fe->id].fe_sleep(fe); + + dvb_usb_set_active_fe(fe, 0); + + return dvb_usb_device_power_ctrl(adap->dev, 0); +} + +int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) +{ + int ret, i; + + /* register all given adapter frontends */ + for (i = 0; i < adap->props.num_frontends; i++) { + + if (adap->props.fe[i].frontend_attach == NULL) { + err("strange: '%s' #%d,%d " + "doesn't want to attach a frontend.", + adap->dev->desc->name, adap->id, i); + + return 0; + } + + ret = adap->props.fe[i].frontend_attach(adap); + if (ret || adap->fe_adap[i].fe == NULL) { + /* only print error when there is no FE at all */ + if (i == 0) + err("no frontend was attached by '%s'", + adap->dev->desc->name); + + return 0; + } + + adap->fe_adap[i].fe->id = i; + + /* re-assign sleep and wakeup functions */ + adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init; + adap->fe_adap[i].fe->ops.init = dvb_usb_fe_wakeup; + adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep; + adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep; + + if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) { + err("Frontend %d registration failed.", i); + dvb_frontend_detach(adap->fe_adap[i].fe); + adap->fe_adap[i].fe = NULL; + /* In error case, do not try register more FEs, + * still leaving already registered FEs alive. */ + if (i == 0) + return -ENODEV; + else + return 0; + } + + /* only attach the tuner if the demod is there */ + if (adap->props.fe[i].tuner_attach != NULL) + adap->props.fe[i].tuner_attach(adap); + + adap->num_frontends_initialized++; + } + + return 0; +} + +int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) +{ + int i = adap->num_frontends_initialized - 1; + + /* unregister all given adapter frontends */ + for (; i >= 0; i--) { + if (adap->fe_adap[i].fe != NULL) { + dvb_unregister_frontend(adap->fe_adap[i].fe); + dvb_frontend_detach(adap->fe_adap[i].fe); + } + } + adap->num_frontends_initialized = 0; + + return 0; +} diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c new file mode 100644 index 000000000000..20f2ed782dd7 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c @@ -0,0 +1,146 @@ +/* dvb-usb-firmware.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices. + * + * FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem. + */ +#include "dvb_usb_common.h" + +#include + +struct usb_cypress_controller { + int id; + const char *name; /* name of the usb controller */ + u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */ +}; + +static struct usb_cypress_controller cypress[] = { + { .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 }, + { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, +}; + +/* + * load a firmware packet to the device + */ +static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev,0), + 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); +} + +int usbv2_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) +{ + struct hexline hx; + u8 reset; + int ret,pos=0; + + /* stop the CPU */ + reset = 1; + if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) + err("could not stop the USB controller CPU."); + + while ((ret = dvb_usbv2_get_hexline(fw,&hx,&pos)) > 0) { + deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk); + ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len); + + if (ret != hx.len) { + err("error while transferring firmware " + "(transferred size: %d, block size: %d)", + ret,hx.len); + ret = -EINVAL; + break; + } + } + if (ret < 0) { + err("firmware download failed at %d with %d",pos,ret); + return ret; + } + + if (ret == 0) { + /* restart the CPU */ + reset = 0; + if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + } else + ret = -EIO; + + return ret; +} +EXPORT_SYMBOL(usbv2_cypress_load_firmware); + +int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props) +{ + int ret; + const struct firmware *fw = NULL; + + if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) { + err("did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", + props->firmware,ret); + return ret; + } + + info("downloading firmware from file '%s'",props->firmware); + + switch (props->usb_ctrl) { + case CYPRESS_AN2135: + case CYPRESS_AN2235: + case CYPRESS_FX2: + ret = usbv2_cypress_load_firmware(udev, fw, props->usb_ctrl); + break; + case DEVICE_SPECIFIC: + if (props->download_firmware) + ret = props->download_firmware(udev,fw); + else { + err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one."); + ret = -EINVAL; + } + break; + default: + ret = -EINVAL; + break; + } + + release_firmware(fw); + return ret; +} + +int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, + int *pos) +{ + u8 *b = (u8 *) &fw->data[*pos]; + int data_offs = 4; + if (*pos >= fw->size) + return 0; + + memset(hx,0,sizeof(struct hexline)); + + hx->len = b[0]; + + if ((*pos + hx->len + 4) >= fw->size) + return -EINVAL; + + hx->addr = b[1] | (b[2] << 8); + hx->type = b[3]; + + if (hx->type == 0x04) { + /* b[4] and b[5] are the Extended linear address record data field */ + hx->addr |= (b[4] << 24) | (b[5] << 16); +/* hx->len -= 2; + data_offs += 2; */ + } + memcpy(hx->data,&b[data_offs],hx->len); + hx->chk = b[hx->len + data_offs]; + + *pos += hx->len + 5; + + return *pos; +} +EXPORT_SYMBOL(dvb_usbv2_get_hexline); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c new file mode 100644 index 000000000000..273f4892da01 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c @@ -0,0 +1,43 @@ +/* dvb-usb-i2c.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for (de-)initializing an I2C adapter. + */ +#include "dvb_usb_common.h" + +int dvb_usb_i2c_init(struct dvb_usb_device *d) +{ + int ret = 0; + + if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER)) + return 0; + + if (d->props.i2c_algo == NULL) { + err("no i2c algorithm specified"); + return -EINVAL; + } + + strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); + d->i2c_adap.algo = d->props.i2c_algo; + d->i2c_adap.algo_data = NULL; + d->i2c_adap.dev.parent = &d->udev->dev; + + i2c_set_adapdata(&d->i2c_adap, d); + + if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0) + err("could not add i2c adapter"); + + d->state |= DVB_USB_STATE_I2C; + + return ret; +} + +int dvb_usb_i2c_exit(struct dvb_usb_device *d) +{ + if (d->state & DVB_USB_STATE_I2C) + i2c_del_adapter(&d->i2c_adap); + d->state &= ~DVB_USB_STATE_I2C; + return 0; +} diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c new file mode 100644 index 000000000000..4ae30451eb9e --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -0,0 +1,304 @@ +/* + * DVB USB library - provides a generic interface for a DVB USB device driver. + * + * dvb-usb-init.c + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "dvb_usb_common.h" + +/* debug */ +int dvb_usb_debug; +module_param_named(debug, dvb_usb_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." DVB_USB_DEBUG_STATUS); + +int dvb_usb_disable_rc_polling; +module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); +MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); + +static int dvb_usb_force_pid_filter_usage; +module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); +MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); + +static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) +{ + struct dvb_usb_adapter *adap; + int ret, n, o; + + for (n = 0; n < d->props.num_adapters; n++) { + adap = &d->adapter[n]; + adap->dev = d; + adap->id = n; + + memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties)); + + for (o = 0; o < adap->props.num_frontends; o++) { + struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o]; + /* speed - when running at FULL speed we need a HW PID filter */ + if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { + err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)"); + return -ENODEV; + } + + if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || + (props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { + info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count); + adap->fe_adap[o].pid_filtering = 1; + adap->fe_adap[o].max_feed_count = props->pid_filter_count; + } else { + info("will pass the complete MPEG2 transport stream to the software demuxer."); + adap->fe_adap[o].pid_filtering = 0; + adap->fe_adap[o].max_feed_count = 255; + } + + if (!adap->fe_adap[o].pid_filtering && + dvb_usb_force_pid_filter_usage && + props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { + info("pid filter enabled by module option."); + adap->fe_adap[o].pid_filtering = 1; + adap->fe_adap[o].max_feed_count = props->pid_filter_count; + } + + if (props->size_of_priv > 0) { + adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL); + if (adap->fe_adap[o].priv == NULL) { + err("no memory for priv for adapter %d fe %d.", n, o); + return -ENOMEM; + } + } + } + + if (adap->props.size_of_priv > 0) { + adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL); + if (adap->priv == NULL) { + err("no memory for priv for adapter %d.", n); + return -ENOMEM; + } + } + + if ((ret = dvb_usb_adapter_stream_init(adap)) || + (ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) || + (ret = dvb_usb_adapter_frontend_init(adap))) { + return ret; + } + + /* use exclusive FE lock if there is multiple shared FEs */ + if (adap->fe_adap[1].fe) + adap->dvb_adap.mfe_shared = 1; + + d->num_adapters_initialized++; + d->state |= DVB_USB_STATE_DVB; + } + + /* + * when reloading the driver w/o replugging the device + * sometimes a timeout occures, this helps + */ + if (d->props.generic_bulk_ctrl_endpoint != 0) { + usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + } + + return 0; +} + +static int dvb_usb_adapter_exit(struct dvb_usb_device *d) +{ + int n; + + for (n = 0; n < d->num_adapters_initialized; n++) { + dvb_usb_adapter_frontend_exit(&d->adapter[n]); + dvb_usb_adapter_dvb_exit(&d->adapter[n]); + dvb_usb_adapter_stream_exit(&d->adapter[n]); + kfree(d->adapter[n].priv); + } + d->num_adapters_initialized = 0; + d->state &= ~DVB_USB_STATE_DVB; + return 0; +} + + +/* general initialization functions */ +static int dvb_usb_exit(struct dvb_usb_device *d) +{ + deb_info("state before exiting everything: %x\n", d->state); + dvb_usb_remote_exit(d); + dvb_usb_adapter_exit(d); + dvb_usb_i2c_exit(d); + deb_info("state should be zero now: %x\n", d->state); + d->state = DVB_USB_STATE_INIT; + kfree(d->priv); + kfree(d); + return 0; +} + +static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) +{ + int ret = 0; + + mutex_init(&d->usb_mutex); + mutex_init(&d->i2c_mutex); + + d->state = DVB_USB_STATE_INIT; + + if (d->props.size_of_priv > 0) { + d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); + if (d->priv == NULL) { + err("no memory for priv in 'struct dvb_usb_device'"); + return -ENOMEM; + } + } + + /* check the capabilities and set appropriate variables */ + dvb_usb_device_power_ctrl(d, 1); + + if ((ret = dvb_usb_i2c_init(d)) || + (ret = dvb_usb_adapter_init(d, adapter_nums))) { + dvb_usb_exit(d); + return ret; + } + + if ((ret = dvb_usb_remote_init(d))) + err("could not initialize remote control."); + + dvb_usb_device_power_ctrl(d, 0); + + return 0; +} + +/* determine the name and the state of the just found USB device */ +static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold) +{ + int i, j; + struct dvb_usb_device_description *desc = NULL; + + *cold = -1; + + for (i = 0; i < props->num_device_descs; i++) { + + for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) { + deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct); + if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && + props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { + *cold = 1; + desc = &props->devices[i]; + break; + } + } + + if (desc != NULL) + break; + + for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) { + deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct); + if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && + props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { + *cold = 0; + desc = &props->devices[i]; + break; + } + } + } + + if (desc != NULL && props->identify_state != NULL) + props->identify_state(udev, props, &desc, cold); + + return desc; +} + +int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + if (onoff) + d->powered++; + else + d->powered--; + + if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */ + deb_info("power control: %d\n", onoff); + if (d->props.power_ctrl) + return d->props.power_ctrl(d, onoff); + } + return 0; +} + +/* + * USB + */ +int dvb_usbv2_device_init(struct usb_interface *intf, + struct dvb_usb_device_properties *props, + struct module *owner, struct dvb_usb_device **du, + short *adapter_nums) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct dvb_usb_device *d = NULL; + struct dvb_usb_device_description *desc = NULL; + + int ret = -ENOMEM, cold = 0; + + if (du != NULL) + *du = NULL; + + if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { + deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); + return -ENODEV; + } + + if (cold) { + info("found a '%s' in cold state, will try to load a firmware", desc->name); + ret = dvb_usb_download_firmware(udev, props); + if (!props->no_reconnect || ret != 0) + return ret; + } + + info("found a '%s' in warm state.", desc->name); + d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); + if (d == NULL) { + err("no memory for 'struct dvb_usb_device'"); + return -ENOMEM; + } + + d->udev = udev; + memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); + d->desc = desc; + d->owner = owner; + + usb_set_intfdata(intf, d); + + if (du != NULL) + *du = d; + + ret = dvb_usb_init(d, adapter_nums); + + if (ret == 0) + info("%s successfully initialized and connected.", desc->name); + else + info("%s error while loading driver (%d)", desc->name, ret); + return ret; +} +EXPORT_SYMBOL(dvb_usbv2_device_init); + +void dvb_usbv2_device_exit(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + const char *name = "generic DVB-USB module"; + + usb_set_intfdata(intf, NULL); + if (d != NULL && d->desc != NULL) { + name = d->desc->name; + dvb_usb_exit(d); + } + info("%s successfully deinitialized and disconnected.", name); + +} +EXPORT_SYMBOL(dvb_usbv2_device_exit); + +MODULE_VERSION("1.0"); +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c new file mode 100644 index 000000000000..1c6bef62473f --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c @@ -0,0 +1,391 @@ +/* dvb-usb-remote.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for initializing the input-device and for handling remote-control-queries. + */ +#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, + 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; + 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); + if (index >= keymap_size) + return -EINVAL; + + 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 0; +} + +static int legacy_dvb_usb_setkeycode(struct input_dev *dev, + 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; + 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 + * would be to allocate a table with key_map_size + 1, + * 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 0; +} + +/* Remote-control poll function - called every dib->rc_query_interval ms to see + * whether the remote control has received anything. + * + * TODO: Fix the repeat rate of the input device. + */ +static void legacy_dvb_usb_read_remote_control(struct work_struct *work) +{ + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, rc_query_work.work); + u32 event; + int state; + + /* TODO: need a lock here. We can simply skip checking for the remote control + if we're busy. */ + + /* when the parameter has been set to 1 via sysfs while the driver was running */ + if (dvb_usb_disable_rc_polling) + return; + + if (d->props.rc.legacy.rc_query(d,&event,&state)) { + err("error while querying for an remote control event."); + goto schedule; + } + + + switch (state) { + case REMOTE_NO_KEY_PRESSED: + break; + case REMOTE_KEY_PRESSED: + deb_rc("key pressed\n"); + d->last_event = event; + case REMOTE_KEY_REPEAT: + deb_rc("key repeated\n"); + input_event(d->input_dev, EV_KEY, event, 1); + input_sync(d->input_dev); + input_event(d->input_dev, EV_KEY, d->last_event, 0); + input_sync(d->input_dev); + break; + default: + break; + } + +/* improved repeat handling ??? + switch (state) { + case REMOTE_NO_KEY_PRESSED: + deb_rc("NO KEY PRESSED\n"); + if (d->last_state != REMOTE_NO_KEY_PRESSED) { + deb_rc("releasing event %d\n",d->last_event); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); + input_sync(d->rc_input_dev); + } + d->last_state = REMOTE_NO_KEY_PRESSED; + d->last_event = 0; + break; + case REMOTE_KEY_PRESSED: + deb_rc("KEY PRESSED\n"); + deb_rc("pressing event %d\n",event); + + input_event(d->rc_input_dev, EV_KEY, event, 1); + input_sync(d->rc_input_dev); + + d->last_event = event; + d->last_state = REMOTE_KEY_PRESSED; + break; + case REMOTE_KEY_REPEAT: + deb_rc("KEY_REPEAT\n"); + if (d->last_state != REMOTE_NO_KEY_PRESSED) { + deb_rc("repeating event %d\n",d->last_event); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 2); + input_sync(d->rc_input_dev); + d->last_state = REMOTE_KEY_REPEAT; + } + default: + break; + } +*/ + +schedule: + schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval)); +} + +static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) +{ + int i, err, rc_interval; + struct input_dev *input_dev; + + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->evbit[0] = BIT_MASK(EV_KEY); + input_dev->name = "IR-receiver inside an USB DVB receiver"; + input_dev->phys = d->rc_phys; + usb_to_input_id(d->udev, &input_dev->id); + input_dev->dev.parent = &d->udev->dev; + d->input_dev = input_dev; + d->rc_dev = NULL; + + 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); + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { + deb_rc("setting bit for event %d item %d\n", + d->props.rc.legacy.rc_map_table[i].keycode, i); + set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit); + } + + /* setting these two values to non-zero, we have to manage key repeats */ + input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval; + input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150; + + input_set_drvdata(input_dev, d); + + err = input_register_device(input_dev); + if (err) + input_free_device(input_dev); + + rc_interval = d->props.rc.legacy.rc_interval; + + INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control); + + info("schedule remote query interval to %d msecs.", rc_interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(rc_interval)); + + d->state |= DVB_USB_STATE_REMOTE; + + return err; +} + +/* Remote-control poll function - called every dib->rc_query_interval ms to see + * whether the remote control has received anything. + * + * TODO: Fix the repeat rate of the input device. + */ +static void dvb_usb_read_remote_control(struct work_struct *work) +{ + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, rc_query_work.work); + int err; + + /* TODO: need a lock here. We can simply skip checking for the remote control + if we're busy. */ + + /* when the parameter has been set to 1 via sysfs while the + * driver was running, or when bulk mode is enabled after IR init + */ + if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode) + return; + + err = d->props.rc.core.rc_query(d); + if (err) + err("error %d while querying for an remote control event.", err); + + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->props.rc.core.rc_interval)); +} + +static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) +{ + int err, rc_interval; + struct rc_dev *dev; + + dev = rc_allocate_device(); + if (!dev) + return -ENOMEM; + + dev->driver_name = d->props.rc.core.module_name; + 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 = 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; + dev->dev.parent = &d->udev->dev; + dev->priv = d; + + err = rc_register_device(dev); + if (err < 0) { + rc_free_device(dev); + return err; + } + + d->input_dev = NULL; + d->rc_dev = dev; + + if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode) + return 0; + + /* Polling mode - initialize a work queue for handling it */ + INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); + + rc_interval = d->props.rc.core.rc_interval; + + info("schedule remote query interval to %d msecs.", rc_interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(rc_interval)); + + return 0; +} + +int dvb_usb_remote_init(struct dvb_usb_device *d) +{ + int err; + + if (dvb_usb_disable_rc_polling) + return 0; + + if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query) + d->props.rc.mode = DVB_RC_LEGACY; + else if (d->props.rc.core.rc_codes) + d->props.rc.mode = DVB_RC_CORE; + else + return 0; + + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + + /* Start the remote-control polling. */ + if (d->props.rc.legacy.rc_interval < 40) + d->props.rc.legacy.rc_interval = 100; /* default */ + + if (d->props.rc.mode == DVB_RC_LEGACY) + err = legacy_dvb_usb_remote_init(d); + else + err = rc_core_dvb_usb_remote_init(d); + if (err) + return err; + + d->state |= DVB_USB_STATE_REMOTE; + + return 0; +} + +int dvb_usb_remote_exit(struct dvb_usb_device *d) +{ + if (d->state & DVB_USB_STATE_REMOTE) { + cancel_delayed_work_sync(&d->rc_query_work); + if (d->props.rc.mode == DVB_RC_LEGACY) + input_unregister_device(d->input_dev); + else + rc_unregister_device(d->rc_dev); + } + d->state &= ~DVB_USB_STATE_REMOTE; + return 0; +} + +#define DVB_USB_RC_NEC_EMPTY 0x00 +#define DVB_USB_RC_NEC_KEY_PRESSED 0x01 +#define DVB_USB_RC_NEC_KEY_REPEATED 0x02 +int dvb_usbv2_nec_rc_key_to_event(struct dvb_usb_device *d, + u8 keybuf[5], u32 *event, int *state) +{ + int i; + struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + switch (keybuf[0]) { + case DVB_USB_RC_NEC_EMPTY: + break; + case DVB_USB_RC_NEC_KEY_PRESSED: + if ((u8) ~keybuf[1] != keybuf[2] || + (u8) ~keybuf[3] != keybuf[4]) { + deb_err("remote control checksum failed.\n"); + break; + } + /* See if we can match the raw key code. */ + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) + if (rc5_custom(&keymap[i]) == keybuf[1] && + rc5_data(&keymap[i]) == keybuf[3]) { + *event = keymap[i].keycode; + *state = REMOTE_KEY_PRESSED; + return 0; + } + deb_err("key mapping failed - no appropriate key found in keymapping\n"); + break; + case DVB_USB_RC_NEC_KEY_REPEATED: + *state = REMOTE_KEY_REPEAT; + break; + default: + deb_err("unknown type of remote status: %d\n",keybuf[0]); + break; + } + return 0; +} +EXPORT_SYMBOL(dvb_usbv2_nec_rc_key_to_event); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c new file mode 100644 index 000000000000..c4b7845373e2 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -0,0 +1,121 @@ +/* dvb-usb-urb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file keeps functions for initializing and handling the + * USB and URB stuff. + */ +#include "dvb_usb_common.h" + +int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, + u16 rlen, int delay_ms) +{ + int actlen,ret = -ENOMEM; + + if (!d || wbuf == NULL || wlen == 0) + return -EINVAL; + + if (d->props.generic_bulk_ctrl_endpoint == 0) { + err("endpoint for generic control not specified."); + return -EINVAL; + } + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + deb_xfer(">>> "); + debug_dump(wbuf,wlen,deb_xfer); + + ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen, + 2000); + + if (ret) + err("bulk message failed: %d (%d/%d)",ret,wlen,actlen); + else + ret = actlen != wlen ? -1 : 0; + + /* an answer is expected, and no error before */ + if (!ret && rbuf && rlen) { + if (delay_ms) + msleep(delay_ms); + + ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint_response ? + d->props.generic_bulk_ctrl_endpoint_response : + d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen, + 2000); + + if (ret) + err("recv bulk message failed: %d",ret); + else { + deb_xfer("<<< "); + debug_dump(rbuf,actlen,deb_xfer); + } + } + + mutex_unlock(&d->usb_mutex); + return ret; +} +EXPORT_SYMBOL(dvb_usbv2_generic_rw); + +int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) +{ + return dvb_usbv2_generic_rw(d,buf,len,NULL,0,0); +} +EXPORT_SYMBOL(dvb_usbv2_generic_write); + +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter(&adap->demux, buffer, length); +} + +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter_204(&adap->demux, buffer, length); +} + +static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, + u8 *buffer, size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter_raw(&adap->demux, buffer, length); +} + +int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) +{ + int i, ret = 0; + for (i = 0; i < adap->props.num_frontends; i++) { + + adap->fe_adap[i].stream.udev = adap->dev->udev; + if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) + adap->fe_adap[i].stream.complete = + dvb_usb_data_complete_204; + else + if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD) + adap->fe_adap[i].stream.complete = + dvb_usb_data_complete_raw; + else + adap->fe_adap[i].stream.complete = dvb_usb_data_complete; + adap->fe_adap[i].stream.user_priv = adap; + ret = usb_urb_init(&adap->fe_adap[i].stream, + &adap->props.fe[i].stream); + if (ret < 0) + break; + } + return ret; +} + +int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) +{ + int i; + for (i = 0; i < adap->props.num_frontends; i++) + usb_urb_exit(&adap->fe_adap[i].stream); + return 0; +} diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c new file mode 100644 index 000000000000..bf1915367cb9 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -0,0 +1,254 @@ +/* usb-urb.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file keeps functions for initializing and handling the + * BULK and ISOC USB data transfers in a generic way. + * Can be used for DVB-only and also, that's the plan, for + * Hybrid USB devices (analog and DVB). + */ +#include "dvb_usb_common.h" + +/* URB stuff for streaming */ +static void usb_urb_complete(struct urb *urb) +{ + struct usb_data_stream *stream = urb->context; + int ptype = usb_pipetype(urb->pipe); + int i; + u8 *b; + + deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n", + ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", + urb->status,urb->actual_length,urb->transfer_buffer_length, + urb->number_of_packets,urb->error_count); + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + deb_ts("urb completition error %d.\n", urb->status); + break; + } + + b = (u8 *) urb->transfer_buffer; + switch (ptype) { + case PIPE_ISOCHRONOUS: + for (i = 0; i < urb->number_of_packets; i++) { + + if (urb->iso_frame_desc[i].status != 0) + deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status); + else if (urb->iso_frame_desc[i].actual_length > 0) + stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); + + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + debug_dump(b,20,deb_uxfer); + break; + case PIPE_BULK: + if (urb->actual_length > 0) + stream->complete(stream, b, urb->actual_length); + break; + default: + err("unknown endpoint type in completition handler."); + return; + } + usb_submit_urb(urb,GFP_ATOMIC); +} + +int usb_urb_kill(struct usb_data_stream *stream) +{ + int i; + for (i = 0; i < stream->urbs_submitted; i++) { + deb_ts("killing URB no. %d.\n",i); + + /* stop the URB */ + usb_kill_urb(stream->urb_list[i]); + } + stream->urbs_submitted = 0; + return 0; +} + +int usb_urb_submit(struct usb_data_stream *stream) +{ + int i,ret; + for (i = 0; i < stream->urbs_initialized; i++) { + deb_ts("submitting URB no. %d\n",i); + if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) { + err("could not submit URB no. %d - get them all back",i); + usb_urb_kill(stream); + return ret; + } + stream->urbs_submitted++; + } + return 0; +} + +static int usb_free_stream_buffers(struct usb_data_stream *stream) +{ + if (stream->state & USB_STATE_URB_BUF) { + while (stream->buf_num) { + stream->buf_num--; + deb_mem("freeing buffer %d\n",stream->buf_num); + usb_free_coherent(stream->udev, stream->buf_size, + stream->buf_list[stream->buf_num], + stream->dma_addr[stream->buf_num]); + } + } + + stream->state &= ~USB_STATE_URB_BUF; + + return 0; +} + +static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size) +{ + stream->buf_num = 0; + stream->buf_size = size; + + deb_mem("all in all I will use %lu bytes for streaming\n",num*size); + + for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { + deb_mem("allocating buffer %d\n",stream->buf_num); + if (( stream->buf_list[stream->buf_num] = + usb_alloc_coherent(stream->udev, size, GFP_ATOMIC, + &stream->dma_addr[stream->buf_num]) ) == NULL) { + deb_mem("not enough memory for urb-buffer allocation.\n"); + usb_free_stream_buffers(stream); + return -ENOMEM; + } + deb_mem("buffer %d: %p (dma: %Lu)\n", + stream->buf_num, +stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); + memset(stream->buf_list[stream->buf_num],0,size); + stream->state |= USB_STATE_URB_BUF; + } + deb_mem("allocation successful\n"); + + return 0; +} + +static int usb_bulk_urb_init(struct usb_data_stream *stream) +{ + int i, j; + + if ((i = usb_allocate_stream_buffers(stream,stream->props.count, + stream->props.u.bulk.buffersize)) < 0) + return i; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!.\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[j]); + return -ENOMEM; + } + usb_fill_bulk_urb( stream->urb_list[i], stream->udev, + usb_rcvbulkpipe(stream->udev,stream->props.endpoint), + stream->buf_list[i], + stream->props.u.bulk.buffersize, + usb_urb_complete, stream); + + stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; + stream->urbs_initialized++; + } + return 0; +} + +static int usb_isoc_urb_init(struct usb_data_stream *stream) +{ + int i,j; + + if ((i = usb_allocate_stream_buffers(stream,stream->props.count, + stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0) + return i; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + struct urb *urb; + int frame_offset = 0; + + stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[j]); + return -ENOMEM; + } + + urb = stream->urb_list[i]; + + urb->dev = stream->udev; + urb->context = stream; + urb->complete = usb_urb_complete; + urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->interval = stream->props.u.isoc.interval; + urb->number_of_packets = stream->props.u.isoc.framesperurb; + urb->transfer_buffer_length = stream->buf_size; + urb->transfer_buffer = stream->buf_list[i]; + urb->transfer_dma = stream->dma_addr[i]; + + for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize; + frame_offset += stream->props.u.isoc.framesize; + } + + stream->urbs_initialized++; + } + return 0; +} + +int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props) +{ + if (stream == NULL || props == NULL) + return -EINVAL; + + memcpy(&stream->props, props, sizeof(*props)); + + usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint)); + + if (stream->complete == NULL) { + err("there is no data callback - this doesn't make sense."); + return -EINVAL; + } + + switch (stream->props.type) { + case USB_BULK: + return usb_bulk_urb_init(stream); + case USB_ISOC: + return usb_isoc_urb_init(stream); + default: + err("unknown URB-type for data transfer."); + return -EINVAL; + } +} + +int usb_urb_exit(struct usb_data_stream *stream) +{ + int i; + + usb_urb_kill(stream); + + for (i = 0; i < stream->urbs_initialized; i++) { + if (stream->urb_list[i] != NULL) { + deb_mem("freeing URB no. %d.\n",i); + /* free the URBs */ + usb_free_urb(stream->urb_list[i]); + } + } + stream->urbs_initialized = 0; + + usb_free_stream_buffers(stream); + return 0; +} From dc78693706b3efc7e1f7647a35d29736e6d2be3f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 23 May 2012 10:44:15 -0300 Subject: [PATCH 0206/5375] [media] dvb_usb_v2: add .init() callback Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 3 +++ drivers/media/dvb/dvb-usb/dvb_usb_init.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 95caac116e8e..15b08b777e6d 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -239,6 +239,8 @@ enum dvb_usb_mode { * @read_mac_address: called to read the MAC address of the device. * @identify_state: called to determine the state (cold or warm), when it * is not distinguishable by the USB IDs. + * @init: called after adapters are created in order to finalize device + * configuration. * * @rc: remote controller properties * @@ -283,6 +285,7 @@ struct dvb_usb_device_properties { int (*read_mac_address) (struct dvb_usb_device *, u8 []); int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *, struct dvb_usb_device_description **, int *); + int (*init) (struct dvb_usb_device *); struct { enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */ diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 4ae30451eb9e..0d769a1c1807 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -164,6 +164,9 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) return ret; } + if (d->props.init) + d->props.init(d); + if ((ret = dvb_usb_remote_init(d))) err("could not initialize remote control."); From 1bf325db6b668dcdb51753159c008da89f715411 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 23 May 2012 12:34:45 -0300 Subject: [PATCH 0207/5375] [media] dvb_usb_v2: remove one parameter from dvb_usbv2_device_init() Users should use new .init() callback instead. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 15b08b777e6d..1ee95c1f93e5 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -462,7 +462,7 @@ struct dvb_usb_device { extern int dvb_usbv2_device_init(struct usb_interface *, struct dvb_usb_device_properties *, - struct module *, struct dvb_usb_device **, + struct module *, short *adapter_nums); extern void dvb_usbv2_device_exit(struct usb_interface *); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 0d769a1c1807..367d1600fb7b 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -235,7 +235,7 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) */ int dvb_usbv2_device_init(struct usb_interface *intf, struct dvb_usb_device_properties *props, - struct module *owner, struct dvb_usb_device **du, + struct module *owner, short *adapter_nums) { struct usb_device *udev = interface_to_usbdev(intf); @@ -244,9 +244,6 @@ int dvb_usbv2_device_init(struct usb_interface *intf, int ret = -ENOMEM, cold = 0; - if (du != NULL) - *du = NULL; - if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); return -ENODEV; @@ -273,9 +270,6 @@ int dvb_usbv2_device_init(struct usb_interface *intf, usb_set_intfdata(intf, d); - if (du != NULL) - *du = d; - ret = dvb_usb_init(d, adapter_nums); if (ret == 0) From 65871deb7d61e4da681fdefe13d04d3702544448 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 23 May 2012 13:40:57 -0300 Subject: [PATCH 0208/5375] [media] dvb_usb_v2: use .driver_info to pass struct dvb_usb_device_properties Use struct usb_device_id .driver_info to pass struct dvb_usb_device_properties pointer for the DVB USB. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 1ee95c1f93e5..7f1f10989de4 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -461,7 +461,7 @@ struct dvb_usb_device { }; extern int dvb_usbv2_device_init(struct usb_interface *, - struct dvb_usb_device_properties *, + const struct usb_device_id *, struct module *, short *adapter_nums); extern void dvb_usbv2_device_exit(struct usb_interface *); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 367d1600fb7b..93b45546181a 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -234,13 +234,15 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) * USB */ int dvb_usbv2_device_init(struct usb_interface *intf, - struct dvb_usb_device_properties *props, + const struct usb_device_id *id, struct module *owner, short *adapter_nums) { struct usb_device *udev = interface_to_usbdev(intf); struct dvb_usb_device *d = NULL; struct dvb_usb_device_description *desc = NULL; + struct dvb_usb_device_properties *props = + (struct dvb_usb_device_properties *) id->driver_info; int ret = -ENOMEM, cold = 0; From 654e62dc208aedbdc72c4e59cd5f83347e85419e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 23 May 2012 15:03:56 -0300 Subject: [PATCH 0209/5375] [media] dvb_usb_v2: remove owner parameter from dvb_usbv2_device_init() Pass that parameter via configuration structure. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 6 ++---- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 3 ++- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 2 -- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 7f1f10989de4..db9a7ddd039d 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -224,6 +224,7 @@ enum dvb_usb_mode { /** * struct dvb_usb_device_properties - properties of a dvb-usb-device + * @owner: owner of the dvb_adapter * @usb_ctrl: which USB device-side controller is in use. Needed for firmware * download. * @firmware: name of the firmware file. @@ -263,6 +264,7 @@ enum dvb_usb_mode { */ #define MAX_NO_OF_ADAPTER_PER_DEVICE 2 struct dvb_usb_device_properties { + struct module *owner; #define DVB_USB_IS_AN_I2C_ADAPTER 0x01 int caps; @@ -419,7 +421,6 @@ struct dvb_usb_adapter { * @rc_query_work: struct work_struct frequent rc queries * @last_event: last triggered event * @last_state: last state (no, pressed, repeat) - * @owner: owner of the dvb_adapter * @priv: private data of the actual driver (allocate by dvb-usb, size defined * in size_of_priv of dvb_usb_properties). */ @@ -455,14 +456,11 @@ struct dvb_usb_device { u32 last_event; int last_state; - struct module *owner; - void *priv; }; extern int dvb_usbv2_device_init(struct usb_interface *, const struct usb_device_id *, - struct module *, short *adapter_nums); extern void dvb_usbv2_device_exit(struct usb_interface *); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 59cc26cb24c5..0795c2436cc8 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -98,7 +98,8 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) { int i; int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name, - adap->dev->owner, &adap->dev->udev->dev, + adap->dev->props.owner, + &adap->dev->udev->dev, adapter_nums); if (ret < 0) { diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 93b45546181a..7334ce6d0379 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -235,7 +235,6 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) */ int dvb_usbv2_device_init(struct usb_interface *intf, const struct usb_device_id *id, - struct module *owner, short *adapter_nums) { struct usb_device *udev = interface_to_usbdev(intf); @@ -268,7 +267,6 @@ int dvb_usbv2_device_init(struct usb_interface *intf, d->udev = udev; memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); d->desc = desc; - d->owner = owner; usb_set_intfdata(intf, d); From 55b1f7040484f6bebaa3407bb0b27e87bbc33e70 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 23 May 2012 16:23:44 -0300 Subject: [PATCH 0210/5375] [media] dvb_usb_v2: remove adapter_nums parameter from dvb_usbv2_device_init() Pass that parameter via configuration structure. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 4 ++-- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 3 +-- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 5 ++--- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 14 ++++++-------- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index db9a7ddd039d..101191e73661 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -265,6 +265,7 @@ enum dvb_usb_mode { #define MAX_NO_OF_ADAPTER_PER_DEVICE 2 struct dvb_usb_device_properties { struct module *owner; + short *adapter_nr; #define DVB_USB_IS_AN_I2C_ADAPTER 0x01 int caps; @@ -460,8 +461,7 @@ struct dvb_usb_device { }; extern int dvb_usbv2_device_init(struct usb_interface *, - const struct usb_device_id *, - short *adapter_nums); + const struct usb_device_id *); extern void dvb_usbv2_device_exit(struct usb_interface *); /* the generic read/write method for device control */ diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index 29df53999a9c..24341bde02d8 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -40,8 +40,7 @@ extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap); extern int dvb_usb_i2c_init(struct dvb_usb_device *); extern int dvb_usb_i2c_exit(struct dvb_usb_device *); -extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, - short *adapter_nums); +extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap); extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap); extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap); extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 0795c2436cc8..41e3194b971e 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -94,14 +94,13 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) return dvb_usb_ctrl_feed(dvbdmxfeed,0); } -int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) +int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) { int i; int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name, adap->dev->props.owner, &adap->dev->udev->dev, - adapter_nums); - + adap->dev->props.adapter_nr); if (ret < 0) { deb_info("dvb_register_adapter failed: error %d", ret); goto err; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 7334ce6d0379..662c25840f3c 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -26,7 +26,7 @@ static int dvb_usb_force_pid_filter_usage; module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); -static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) +static int dvb_usb_adapter_init(struct dvb_usb_device *d) { struct dvb_usb_adapter *adap; int ret, n, o; @@ -83,7 +83,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) } if ((ret = dvb_usb_adapter_stream_init(adap)) || - (ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) || + (ret = dvb_usb_adapter_dvb_init(adap)) || (ret = dvb_usb_adapter_frontend_init(adap))) { return ret; } @@ -138,7 +138,7 @@ static int dvb_usb_exit(struct dvb_usb_device *d) return 0; } -static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) +static int dvb_usb_init(struct dvb_usb_device *d) { int ret = 0; @@ -158,8 +158,7 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) /* check the capabilities and set appropriate variables */ dvb_usb_device_power_ctrl(d, 1); - if ((ret = dvb_usb_i2c_init(d)) || - (ret = dvb_usb_adapter_init(d, adapter_nums))) { + if ((ret = dvb_usb_i2c_init(d)) || (ret = dvb_usb_adapter_init(d))) { dvb_usb_exit(d); return ret; } @@ -234,8 +233,7 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) * USB */ int dvb_usbv2_device_init(struct usb_interface *intf, - const struct usb_device_id *id, - short *adapter_nums) + const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); struct dvb_usb_device *d = NULL; @@ -270,7 +268,7 @@ int dvb_usbv2_device_init(struct usb_interface *intf, usb_set_intfdata(intf, d); - ret = dvb_usb_init(d, adapter_nums); + ret = dvb_usb_init(d); if (ret == 0) info("%s successfully initialized and connected.", desc->name); From 496e82789935df7a9b13ce58807973004e443847 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 23 May 2012 20:45:05 -0300 Subject: [PATCH 0211/5375] [media] dvb_usb_v2: pass (struct dvb_usb_device *) as a parameter for fw download Change parameter (struct usb_device *) => (struct dvb_usb_device *) for .identify_state() and .download_firmware() callbacks. struct usb_device * did not provide handle for the DVB USB driver state. Change DVB USB framework to alloc space for the priv earlier and pass that pointer to the device driver using (struct dvb_usb_device *) as a callback parameter. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 11 ++- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_firmware.c | 16 ++-- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 88 +++++++++++++------- 4 files changed, 73 insertions(+), 44 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 101191e73661..e3d55525dec5 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -275,9 +275,10 @@ struct dvb_usb_device_properties { #define CYPRESS_AN2235 2 #define CYPRESS_FX2 3 int usb_ctrl; - int (*download_firmware) (struct usb_device *, const struct firmware *); + +#define RECONNECTS_USB 1 + int (*download_firmware) (struct dvb_usb_device *, const struct firmware *); const char *firmware; - int no_reconnect; int size_of_priv; @@ -286,8 +287,10 @@ struct dvb_usb_device_properties { int (*power_ctrl) (struct dvb_usb_device *, int); int (*read_mac_address) (struct dvb_usb_device *, u8 []); - int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *, - struct dvb_usb_device_description **, int *); + +#define WARM 0 +#define COLD 1 + int (*identify_state) (struct dvb_usb_device *); int (*init) (struct dvb_usb_device *); struct { diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index 24341bde02d8..dd275cdc1082 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -25,7 +25,7 @@ extern int dvb_usb_disable_rc_polling; #define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args) /* commonly used methods */ -extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *); +extern int dvb_usb_download_firmware(struct dvb_usb_device *); extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c index 20f2ed782dd7..dd9f8220adea 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c @@ -75,29 +75,29 @@ int usbv2_cypress_load_firmware(struct usb_device *udev, const struct firmware * } EXPORT_SYMBOL(usbv2_cypress_load_firmware); -int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props) +int dvb_usb_download_firmware(struct dvb_usb_device *d) { int ret; const struct firmware *fw = NULL; - if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) { + if ((ret = request_firmware(&fw, d->props.firmware, &d->udev->dev)) != 0) { err("did not find the firmware file. (%s) " "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", - props->firmware,ret); + d->props.firmware,ret); return ret; } - info("downloading firmware from file '%s'",props->firmware); + info("downloading firmware from file '%s'", d->props.firmware); - switch (props->usb_ctrl) { + switch (d->props.usb_ctrl) { case CYPRESS_AN2135: case CYPRESS_AN2235: case CYPRESS_FX2: - ret = usbv2_cypress_load_firmware(udev, fw, props->usb_ctrl); + ret = usbv2_cypress_load_firmware(d->udev, fw, d->props.usb_ctrl); break; case DEVICE_SPECIFIC: - if (props->download_firmware) - ret = props->download_firmware(udev,fw); + if (d->props.download_firmware) + ret = d->props.download_firmware(d, fw); else { err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one."); ret = -EINVAL; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 662c25840f3c..9c03a3266be2 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -147,14 +147,6 @@ static int dvb_usb_init(struct dvb_usb_device *d) d->state = DVB_USB_STATE_INIT; - if (d->props.size_of_priv > 0) { - d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); - if (d->priv == NULL) { - err("no memory for priv in 'struct dvb_usb_device'"); - return -ENOMEM; - } - } - /* check the capabilities and set appropriate variables */ dvb_usb_device_power_ctrl(d, 1); @@ -175,12 +167,12 @@ static int dvb_usb_init(struct dvb_usb_device *d) } /* determine the name and the state of the just found USB device */ -static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold) +static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, bool *cold) { int i, j; struct dvb_usb_device_description *desc = NULL; - *cold = -1; + *cold = true; for (i = 0; i < props->num_device_descs; i++) { @@ -188,7 +180,7 @@ static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct); if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { - *cold = 1; + *cold = true; desc = &props->devices[i]; break; } @@ -201,16 +193,13 @@ static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct); if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { - *cold = 0; + *cold = false; desc = &props->devices[i]; break; } } } - if (desc != NULL && props->identify_state != NULL) - props->identify_state(udev, props, &desc, cold); - return desc; } @@ -233,29 +222,16 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) * USB */ int dvb_usbv2_device_init(struct usb_interface *intf, - const struct usb_device_id *id) + const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); struct dvb_usb_device *d = NULL; struct dvb_usb_device_description *desc = NULL; struct dvb_usb_device_properties *props = (struct dvb_usb_device_properties *) id->driver_info; + int ret = -ENOMEM; + bool cold; - int ret = -ENOMEM, cold = 0; - - if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { - deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); - return -ENODEV; - } - - if (cold) { - info("found a '%s' in cold state, will try to load a firmware", desc->name); - ret = dvb_usb_download_firmware(udev, props); - if (!props->no_reconnect || ret != 0) - return ret; - } - - info("found a '%s' in warm state.", desc->name); d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); if (d == NULL) { err("no memory for 'struct dvb_usb_device'"); @@ -264,8 +240,51 @@ int dvb_usbv2_device_init(struct usb_interface *intf, d->udev = udev; memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); + + if (d->props.size_of_priv > 0) { + d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); + if (d->priv == NULL) { + err("no memory for priv in 'struct dvb_usb_device'"); + ret = -ENOMEM; + goto err_kfree; + } + } + + if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { + deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); + ret = -ENODEV; + goto err_kfree; + } + d->desc = desc; + if (d->props.identify_state) { + ret = d->props.identify_state(d); + if (ret == 0) { + ; + } else if (ret == COLD) { + cold = true; + ret = 0; + } else { + goto err_kfree; + } + } + + if (cold) { + info("found a '%s' in cold state, will try to load a firmware", desc->name); + ret = dvb_usb_download_firmware(d); + if (ret == 0) { + ; + } else if (ret == RECONNECTS_USB) { + ret = 0; + goto err_kfree; + } else { + goto err_kfree; + } + } + + info("found a '%s' in warm state.", desc->name); + usb_set_intfdata(intf, d); ret = dvb_usb_init(d); @@ -274,6 +293,13 @@ int dvb_usbv2_device_init(struct usb_interface *intf, info("%s successfully initialized and connected.", desc->name); else info("%s error while loading driver (%d)", desc->name, ret); + + return 0; + +err_kfree: + kfree(d->priv); + kfree(d); + return ret; } EXPORT_SYMBOL(dvb_usbv2_device_init); From 8b9dff5828cc91abddf8f4a44c8a38b1012052af Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 24 May 2012 09:31:45 -0300 Subject: [PATCH 0212/5375] [media] dvb_usb_v2: implement .get_firmware_name() Use callback to return firmware name instead of static firmware name. There is some chips that needs to select firmware name according to chip revision. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_firmware.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index e3d55525dec5..c538e113bd58 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -278,7 +278,7 @@ struct dvb_usb_device_properties { #define RECONNECTS_USB 1 int (*download_firmware) (struct dvb_usb_device *, const struct firmware *); - const char *firmware; + int (*get_firmware_name) (struct dvb_usb_device *, const char **); int size_of_priv; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c index dd9f8220adea..b9b169c8f0da 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c @@ -79,15 +79,20 @@ int dvb_usb_download_firmware(struct dvb_usb_device *d) { int ret; const struct firmware *fw = NULL; + const char *name; - if ((ret = request_firmware(&fw, d->props.firmware, &d->udev->dev)) != 0) { + ret = d->props.get_firmware_name(d, &name); + if (ret < 0) + return ret; + + if ((ret = request_firmware(&fw, name, &d->udev->dev)) != 0) { err("did not find the firmware file. (%s) " "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", - d->props.firmware,ret); + name,ret); return ret; } - info("downloading firmware from file '%s'", d->props.firmware); + info("downloading firmware from file '%s'", name); switch (d->props.usb_ctrl) { case CYPRESS_AN2135: From 4e60d951eaea98d400df5915429b7c78da2ec4c3 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 24 May 2012 14:44:21 -0300 Subject: [PATCH 0213/5375] [media] dvb_usb_v2: fix issues raised by checkpatch.pl Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 42 +++-- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 24 +-- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 48 +++--- drivers/media/dvb/dvb-usb/dvb_usb_firmware.c | 105 +++++++----- drivers/media/dvb/dvb-usb/dvb_usb_i2c.c | 3 +- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 158 +++++++++++------- drivers/media/dvb/dvb-usb/dvb_usb_remote.c | 139 +++++++--------- drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 33 ++-- drivers/media/dvb/dvb-usb/usb_urb.c | 159 +++++++++++-------- 9 files changed, 397 insertions(+), 314 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index c538e113bd58..149e45f034f8 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -27,18 +27,19 @@ /* debug */ #ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var,level,args...) \ - do { if ((var & level)) { printk(args); } } while (0) +#define dprintk(var, level, args...) \ + do { if ((var & level)) { printk(args); } } while (0) -#define debug_dump(b,l,func) {\ +#define debug_dump(b, l, func) {\ int loop_; \ - for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \ + for (loop_ = 0; loop_ < l; loop_++) \ + func("%02x ", b[loop_]); \ func("\n");\ } #define DVB_USB_DEBUG_STATUS #else #define dprintk(args...) -#define debug_dump(b,l,func) +#define debug_dump(b, l, func) #define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" @@ -50,11 +51,14 @@ #endif #undef err -#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#define err(format, arg...) \ + printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) #undef info -#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) #undef warn -#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) /** * struct dvb_usb_device_description - name and its according USB IDs @@ -120,7 +124,8 @@ struct usb_data_stream_properties { /** * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter. - * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device. + * A DVB-USB-Adapter is basically a dvb_adapter which is present on a + * USB-device. * @caps: capabilities of the DVB USB device. * @pid_filter_count: number of PID filter position in the optional hardware * PID-filter. @@ -277,7 +282,8 @@ struct dvb_usb_device_properties { int usb_ctrl; #define RECONNECTS_USB 1 - int (*download_firmware) (struct dvb_usb_device *, const struct firmware *); + int (*download_firmware) (struct dvb_usb_device *, + const struct firmware *); int (*get_firmware_name) (struct dvb_usb_device *, const char **); int size_of_priv; @@ -351,7 +357,8 @@ struct usb_data_stream { * @pll_addr: I2C address of the tuner for programming * @pll_init: array containing the initialization buffer * @pll_desc: pointer to the appropriate struct dvb_pll_desc - * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board + * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or + * the board * * @dvb_adap: device's dvb_adapter. * @dmxdev: device's dmxdev. @@ -468,11 +475,13 @@ extern int dvb_usbv2_device_init(struct usb_interface *, extern void dvb_usbv2_device_exit(struct usb_interface *); /* the generic read/write method for device control */ -extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int); +extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16, + int); extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16); /* commonly used remote control parsing */ -extern int dvb_usbv2_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); +extern int dvb_usbv2_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, + int *); /* commonly used firmware download types and function */ struct hexline { @@ -482,8 +491,9 @@ struct hexline { u8 data[255]; u8 chk; }; -extern int usbv2_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type); -extern int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos); - +extern int usbv2_cypress_load_firmware(struct usb_device *udev, + const struct firmware *fw, int type); +extern int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, + int *pos); #endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index dd275cdc1082..60f8ccba8dcd 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -3,7 +3,8 @@ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * see dvb-usb-init.c for copyright information. * - * a header file containing prototypes and types for internal use of the dvb-usb-lib + * a header file containing prototypes and types for internal use of the + * dvb-usb-lib */ #ifndef DVB_USB_COMMON_H #define DVB_USB_COMMON_H @@ -14,22 +15,23 @@ extern int dvb_usb_debug; extern int dvb_usb_disable_rc_polling; -#define deb_info(args...) dprintk(dvb_usb_debug,0x001,args) -#define deb_xfer(args...) dprintk(dvb_usb_debug,0x002,args) -#define deb_pll(args...) dprintk(dvb_usb_debug,0x004,args) -#define deb_ts(args...) dprintk(dvb_usb_debug,0x008,args) -#define deb_err(args...) dprintk(dvb_usb_debug,0x010,args) -#define deb_rc(args...) dprintk(dvb_usb_debug,0x020,args) -#define deb_fw(args...) dprintk(dvb_usb_debug,0x040,args) -#define deb_mem(args...) dprintk(dvb_usb_debug,0x080,args) -#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args) +#define deb_info(args...) dprintk(dvb_usb_debug, 0x001, args) +#define deb_xfer(args...) dprintk(dvb_usb_debug, 0x002, args) +#define deb_pll(args...) dprintk(dvb_usb_debug, 0x004, args) +#define deb_ts(args...) dprintk(dvb_usb_debug, 0x008, args) +#define deb_err(args...) dprintk(dvb_usb_debug, 0x010, args) +#define deb_rc(args...) dprintk(dvb_usb_debug, 0x020, args) +#define deb_fw(args...) dprintk(dvb_usb_debug, 0x040, args) +#define deb_mem(args...) dprintk(dvb_usb_debug, 0x080, args) +#define deb_uxfer(args...) dprintk(dvb_usb_debug, 0x100, args) /* commonly used methods */ extern int dvb_usb_download_firmware(struct dvb_usb_device *); extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); -extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props); +extern int usb_urb_init(struct usb_data_stream *stream, + struct usb_data_stream_properties *props); extern int usb_urb_exit(struct usb_data_stream *stream); extern int usb_urb_submit(struct usb_data_stream *stream); extern int usb_urb_kill(struct usb_data_stream *stream); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 41e3194b971e..832ef88ab248 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -30,7 +30,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) usb_urb_kill(&adap->fe_adap[adap->active_fe].stream); if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { - ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 0); + ret = adap->props.fe[adap->active_fe].streaming_ctrl( + adap, 0); if (ret < 0) { err("error while stopping stream."); return ret; @@ -48,7 +49,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && adap->fe_adap[adap->active_fe].pid_filtering && adap->props.fe[adap->active_fe].pid_filter != NULL) - adap->props.fe[adap->active_fe].pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); + adap->props.fe[adap->active_fe].pid_filter(adap, + dvbdmxfeed->index, dvbdmxfeed->pid, onoff); /* start the feed if this was the first feed and there is still a feed * for reception. @@ -62,7 +64,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) { - ret = adap->props.fe[adap->active_fe].pid_filter_ctrl(adap, + ret = adap->props.fe[adap->active_fe].pid_filter_ctrl( + adap, adap->fe_adap[adap->active_fe].pid_filtering); if (ret < 0) { err("could not handle pid_parser"); @@ -71,7 +74,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } deb_ts("start feeding\n"); if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { - ret = adap->props.fe[adap->active_fe].streaming_ctrl(adap, 1); + ret = adap->props.fe[adap->active_fe].streaming_ctrl( + adap, 1); if (ret < 0) { err("error while enabling fifo."); return ret; @@ -84,14 +88,16 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { - deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type); - return dvb_usb_ctrl_feed(dvbdmxfeed,1); + deb_ts("start pid: 0x%04x, feedtype: %d\n", + dvbdmxfeed->pid, dvbdmxfeed->type); + return dvb_usb_ctrl_feed(dvbdmxfeed, 1); } static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { - deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type); - return dvb_usb_ctrl_feed(dvbdmxfeed,0); + deb_ts("stop pid: 0x%04x, feedtype: %d\n", + dvbdmxfeed->pid, dvbdmxfeed->type); + return dvb_usb_ctrl_feed(dvbdmxfeed, 0); } int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) @@ -109,8 +115,9 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->dvb_adap.fe_ioctl_override = adap->props.fe_ioctl_override; if (adap->dev->props.read_mac_address) { - if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0) - info("MAC address: %pM",adap->dvb_adap.proposed_mac); + if (adap->dev->props.read_mac_address(adap->dev, + adap->dvb_adap.proposed_mac) == 0) + info("MAC address: %pM", adap->dvb_adap.proposed_mac); else err("MAC address reading failed."); } @@ -128,22 +135,24 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->demux.start_feed = dvb_usb_start_feed; adap->demux.stop_feed = dvb_usb_stop_feed; adap->demux.write_to_decoder = NULL; - if ((ret = dvb_dmx_init(&adap->demux)) < 0) { - err("dvb_dmx_init failed: error %d",ret); + ret = dvb_dmx_init(&adap->demux); + if (ret < 0) { + err("dvb_dmx_init failed: error %d", ret); goto err_dmx; } adap->dmxdev.filternum = adap->demux.filternum; adap->dmxdev.demux = &adap->demux.dmx; adap->dmxdev.capabilities = 0; - if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) { - err("dvb_dmxdev_init failed: error %d",ret); + ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); + if (ret < 0) { + err("dvb_dmxdev_init failed: error %d", ret); goto err_dmx_dev; } - if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, - &adap->demux.dmx)) < 0) { - err("dvb_net_init failed: error %d",ret); + ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); + if (ret < 0) { + err("dvb_net_init failed: error %d", ret); goto err_net_init; } @@ -225,7 +234,7 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) for (i = 0; i < adap->props.num_frontends; i++) { if (adap->props.fe[i].frontend_attach == NULL) { - err("strange: '%s' #%d,%d " + err("strange: '%s' #%d,%d " \ "doesn't want to attach a frontend.", adap->dev->desc->name, adap->id, i); @@ -250,7 +259,8 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep; adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep; - if (dvb_register_frontend(&adap->dvb_adap, adap->fe_adap[i].fe)) { + if (dvb_register_frontend(&adap->dvb_adap, + adap->fe_adap[i].fe)) { err("Frontend %d registration failed.", i); dvb_frontend_detach(adap->fe_adap[i].fe); adap->fe_adap[i].fe = NULL; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c index b9b169c8f0da..62bd865a6462 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c @@ -3,9 +3,11 @@ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) * see dvb-usb-init.c for copyright information. * - * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices. + * This file contains functions for downloading the firmware to Cypress FX 1 + * and 2 based devices. * - * FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem. + * FIXME: This part does actually not belong to dvb-usb, but to the + * usb-subsystem. */ #include "dvb_usb_common.h" @@ -13,58 +15,71 @@ struct usb_cypress_controller { int id; - const char *name; /* name of the usb controller */ - u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */ + /* name of the usb controller */ + const char *name; + /* needs to be restarted, when the firmware has been downloaded. */ + u16 cpu_cs_register; }; static struct usb_cypress_controller cypress[] = { - { .id = DEVICE_SPECIFIC, .name = "Device specific", .cpu_cs_register = 0 }, - { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, + { .id = DEVICE_SPECIFIC, .name = "Device specific", + .cpu_cs_register = 0 }, + { .id = CYPRESS_AN2135, .name = "Cypress AN2135", + .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_AN2235, .name = "Cypress AN2235", + .cpu_cs_register = 0x7f92 }, + { .id = CYPRESS_FX2, .name = "Cypress FX2", + .cpu_cs_register = 0xe600 }, }; /* * load a firmware packet to the device */ -static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len) +static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data, + u8 len) { - return usb_control_msg(udev, usb_sndctrlpipe(udev,0), + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); } -int usbv2_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) +int usbv2_cypress_load_firmware(struct usb_device *udev, + const struct firmware *fw, int type) { struct hexline hx; u8 reset; - int ret,pos=0; + int ret, pos = 0; /* stop the CPU */ reset = 1; - if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1) + ret = usb_cypress_writemem(udev, cypress[type].cpu_cs_register, + &reset, 1); + if (ret != 1) err("could not stop the USB controller CPU."); - while ((ret = dvb_usbv2_get_hexline(fw,&hx,&pos)) > 0) { - deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk); - ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len); + while ((ret = dvb_usbv2_get_hexline(fw, &hx, &pos)) > 0) { + deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n", + hx.addr, hx.len, hx.chk); + ret = usb_cypress_writemem(udev, hx.addr, hx.data, hx.len); if (ret != hx.len) { - err("error while transferring firmware " + err("error while transferring firmware " \ "(transferred size: %d, block size: %d)", - ret,hx.len); + ret, hx.len); ret = -EINVAL; break; } } if (ret < 0) { - err("firmware download failed at %d with %d",pos,ret); + err("firmware download failed at %d with %d", pos, ret); return ret; } if (ret == 0) { /* restart the CPU */ reset = 0; - if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) { + if (ret || usb_cypress_writemem(udev, + cypress[type].cpu_cs_register, + &reset, 1) != 1) { err("could not restart the USB controller CPU."); ret = -EINVAL; } @@ -85,32 +100,37 @@ int dvb_usb_download_firmware(struct dvb_usb_device *d) if (ret < 0) return ret; - if ((ret = request_firmware(&fw, name, &d->udev->dev)) != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", - name,ret); + ret = request_firmware(&fw, name, &d->udev->dev); + if (ret != 0) { + err("did not find the firmware file. (%s) " \ + "Please see linux/Documentation/dvb/ for more" \ + " details on firmware-problems. (%d)", + name, ret); return ret; } info("downloading firmware from file '%s'", name); switch (d->props.usb_ctrl) { - case CYPRESS_AN2135: - case CYPRESS_AN2235: - case CYPRESS_FX2: - ret = usbv2_cypress_load_firmware(d->udev, fw, d->props.usb_ctrl); - break; - case DEVICE_SPECIFIC: - if (d->props.download_firmware) - ret = d->props.download_firmware(d, fw); - else { - err("BUG: driver didn't specified a download_firmware-callback, although it claims to have a DEVICE_SPECIFIC one."); - ret = -EINVAL; - } - break; - default: + case CYPRESS_AN2135: + case CYPRESS_AN2235: + case CYPRESS_FX2: + ret = usbv2_cypress_load_firmware(d->udev, fw, + d->props.usb_ctrl); + break; + case DEVICE_SPECIFIC: + if (d->props.download_firmware) + ret = d->props.download_firmware(d, fw); + else { + err("BUG: driver didn't specified a download_firmware" \ + "-callback, although it claims to have a" \ + " DEVICE_SPECIFIC one."); ret = -EINVAL; - break; + } + break; + default: + ret = -EINVAL; + break; } release_firmware(fw); @@ -125,7 +145,7 @@ int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, if (*pos >= fw->size) return 0; - memset(hx,0,sizeof(struct hexline)); + memset(hx, 0, sizeof(struct hexline)); hx->len = b[0]; @@ -136,12 +156,13 @@ int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, hx->type = b[3]; if (hx->type == 0x04) { - /* b[4] and b[5] are the Extended linear address record data field */ + /* b[4] and b[5] are the Extended linear address record data + * field */ hx->addr |= (b[4] << 24) | (b[5] << 16); /* hx->len -= 2; data_offs += 2; */ } - memcpy(hx->data,&b[data_offs],hx->len); + memcpy(hx->data, &b[data_offs], hx->len); hx->chk = b[hx->len + data_offs]; *pos += hx->len + 5; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c index 273f4892da01..58e5a4182245 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c @@ -26,7 +26,8 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) i2c_set_adapdata(&d->i2c_adap, d); - if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0) + ret = i2c_add_adapter(&d->i2c_adap); + if (ret < 0) err("could not add i2c adapter"); d->state |= DVB_USB_STATE_I2C; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 9c03a3266be2..14cfc1e35144 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -6,8 +6,8 @@ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.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, version 2. + * 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 */ @@ -16,15 +16,20 @@ /* debug */ int dvb_usb_debug; module_param_named(debug, dvb_usb_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." DVB_USB_DEBUG_STATUS); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8"\ + ",err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." + DVB_USB_DEBUG_STATUS); int dvb_usb_disable_rc_polling; module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); -MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); +MODULE_PARM_DESC(disable_rc_polling, + "disable remote control polling (default: 0)."); static int dvb_usb_force_pid_filter_usage; -module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); -MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0)."); +module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, + int, 0444); +MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a" \ + " PID filter, if any (default: 0)."); static int dvb_usb_adapter_init(struct dvb_usb_device *d) { @@ -36,57 +41,77 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d) adap->dev = d; adap->id = n; - memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties)); + memcpy(&adap->props, &d->props.adapter[n], + sizeof(struct dvb_usb_adapter_properties)); - for (o = 0; o < adap->props.num_frontends; o++) { - struct dvb_usb_adapter_fe_properties *props = &adap->props.fe[o]; - /* speed - when running at FULL speed we need a HW PID filter */ - if (d->udev->speed == USB_SPEED_FULL && !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { - err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)"); - return -ENODEV; - } + for (o = 0; o < adap->props.num_frontends; o++) { + struct dvb_usb_adapter_fe_properties *props = + &adap->props.fe[o]; + /* speed - when running at FULL speed we need a HW + * PID filter */ + if (d->udev->speed == USB_SPEED_FULL && + !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { + err("This USB2.0 device cannot be run on a" \ + " USB1.1 port. (it lacks a" \ + " hardware PID filter)"); + return -ENODEV; + } - if ((d->udev->speed == USB_SPEED_FULL && props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || - (props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { - info("will use the device's hardware PID filter (table count: %d).", props->pid_filter_count); - adap->fe_adap[o].pid_filtering = 1; - adap->fe_adap[o].max_feed_count = props->pid_filter_count; - } else { - info("will pass the complete MPEG2 transport stream to the software demuxer."); - adap->fe_adap[o].pid_filtering = 0; - adap->fe_adap[o].max_feed_count = 255; - } + if ((d->udev->speed == USB_SPEED_FULL && + props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || + (props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { + info("will use the device's hardware PID" \ + " filter (table count: %d).", + props->pid_filter_count); + adap->fe_adap[o].pid_filtering = 1; + adap->fe_adap[o].max_feed_count = + props->pid_filter_count; + } else { + info("will pass the complete MPEG2 transport" \ + " stream to the software demuxer."); + adap->fe_adap[o].pid_filtering = 0; + adap->fe_adap[o].max_feed_count = 255; + } - if (!adap->fe_adap[o].pid_filtering && - dvb_usb_force_pid_filter_usage && - props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { - info("pid filter enabled by module option."); - adap->fe_adap[o].pid_filtering = 1; - adap->fe_adap[o].max_feed_count = props->pid_filter_count; - } + if (!adap->fe_adap[o].pid_filtering && + dvb_usb_force_pid_filter_usage && + props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { + info("pid filter enabled by module option."); + adap->fe_adap[o].pid_filtering = 1; + adap->fe_adap[o].max_feed_count = + props->pid_filter_count; + } - if (props->size_of_priv > 0) { - adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL); - if (adap->fe_adap[o].priv == NULL) { - err("no memory for priv for adapter %d fe %d.", n, o); - return -ENOMEM; + if (props->size_of_priv > 0) { + adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL); + if (adap->fe_adap[o].priv == NULL) { + err("no memory for priv for adapter" \ + " %d fe %d.", n, o); + return -ENOMEM; + } } } - } if (adap->props.size_of_priv > 0) { - adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL); + adap->priv = kzalloc(adap->props.size_of_priv, + GFP_KERNEL); if (adap->priv == NULL) { err("no memory for priv for adapter %d.", n); return -ENOMEM; } } - if ((ret = dvb_usb_adapter_stream_init(adap)) || - (ret = dvb_usb_adapter_dvb_init(adap)) || - (ret = dvb_usb_adapter_frontend_init(adap))) { + ret = dvb_usb_adapter_stream_init(adap); + if (ret) + return ret; + + ret = dvb_usb_adapter_dvb_init(adap); + if (ret) + return ret; + + ret = dvb_usb_adapter_frontend_init(adap); + if (ret) return ret; - } /* use exclusive FE lock if there is multiple shared FEs */ if (adap->fe_adap[1].fe) @@ -101,8 +126,10 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d) * sometimes a timeout occures, this helps */ if (d->props.generic_bulk_ctrl_endpoint != 0) { - usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); } return 0; @@ -150,7 +177,11 @@ static int dvb_usb_init(struct dvb_usb_device *d) /* check the capabilities and set appropriate variables */ dvb_usb_device_power_ctrl(d, 1); - if ((ret = dvb_usb_i2c_init(d)) || (ret = dvb_usb_adapter_init(d))) { + ret = dvb_usb_i2c_init(d); + if (ret == 0) + ret = dvb_usb_adapter_init(d); + + if (ret) { dvb_usb_exit(d); return ret; } @@ -158,7 +189,8 @@ static int dvb_usb_init(struct dvb_usb_device *d) if (d->props.init) d->props.init(d); - if ((ret = dvb_usb_remote_init(d))) + ret = dvb_usb_remote_init(d); + if (ret) err("could not initialize remote control."); dvb_usb_device_power_ctrl(d, 0); @@ -167,7 +199,9 @@ static int dvb_usb_init(struct dvb_usb_device *d) } /* determine the name and the state of the just found USB device */ -static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, bool *cold) +static struct dvb_usb_device_description *dvb_usb_find_device( + struct usb_device *udev, + struct dvb_usb_device_properties *props, bool *cold) { int i, j; struct dvb_usb_device_description *desc = NULL; @@ -175,11 +209,12 @@ static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *cold = true; for (i = 0; i < props->num_device_descs; i++) { - for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) { - deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct); - if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && - props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { + deb_info("check for cold %x %x\n", + props->devices[i].cold_ids[j]->idVendor, + props->devices[i].cold_ids[j]->idProduct); + if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && + props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { *cold = true; desc = &props->devices[i]; break; @@ -190,9 +225,12 @@ static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device break; for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) { - deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct); + deb_info("check for warm %x %x\n", + props->devices[i].warm_ids[j]->idVendor, + props->devices[i].warm_ids[j]->idProduct); + if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && - props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { + props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { *cold = false; desc = &props->devices[i]; break; @@ -210,7 +248,8 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) else d->powered--; - if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */ + if (d->powered == 0 || (onoff && d->powered == 1)) { + /* when switching from 1 to 0 or from 0 to 1 */ deb_info("power control: %d\n", onoff); if (d->props.power_ctrl) return d->props.power_ctrl(d, onoff); @@ -250,8 +289,12 @@ int dvb_usbv2_device_init(struct usb_interface *intf, } } - if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { - deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); + desc = dvb_usb_find_device(udev, props, &cold); + + if (desc == NULL) { + deb_err("something went very wrong, device was not found in" \ + " current device list - let's see what" \ + " comes next.\n"); ret = -ENODEV; goto err_kfree; } @@ -271,7 +314,8 @@ int dvb_usbv2_device_init(struct usb_interface *intf, } if (cold) { - info("found a '%s' in cold state, will try to load a firmware", desc->name); + info("found a '%s' in cold state, will try to load a firmware", + desc->name); ret = dvb_usb_download_firmware(d); if (ret == 0) { ; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c index 1c6bef62473f..b445990644ae 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c @@ -3,7 +3,8 @@ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) * see dvb-usb-init.c for copyright information. * - * This file contains functions for initializing the input-device and for handling remote-control-queries. + * This file contains functions for initializing the input-device and for + * handling remote-control-queries. */ #include "dvb_usb_common.h" #include @@ -112,73 +113,40 @@ static void legacy_dvb_usb_read_remote_control(struct work_struct *work) u32 event; int state; - /* TODO: need a lock here. We can simply skip checking for the remote control - if we're busy. */ + /* TODO: need a lock here. We can simply skip checking for the remote + control if we're busy. */ - /* when the parameter has been set to 1 via sysfs while the driver was running */ + /* when the parameter has been set to 1 via sysfs while the driver + was running */ if (dvb_usb_disable_rc_polling) return; - if (d->props.rc.legacy.rc_query(d,&event,&state)) { + if (d->props.rc.legacy.rc_query(d, &event, &state)) { err("error while querying for an remote control event."); goto schedule; } switch (state) { - case REMOTE_NO_KEY_PRESSED: - break; - case REMOTE_KEY_PRESSED: - deb_rc("key pressed\n"); - d->last_event = event; - case REMOTE_KEY_REPEAT: - deb_rc("key repeated\n"); - input_event(d->input_dev, EV_KEY, event, 1); - input_sync(d->input_dev); - input_event(d->input_dev, EV_KEY, d->last_event, 0); - input_sync(d->input_dev); - break; - default: - break; + case REMOTE_NO_KEY_PRESSED: + break; + case REMOTE_KEY_PRESSED: + deb_rc("key pressed\n"); + d->last_event = event; + case REMOTE_KEY_REPEAT: + deb_rc("key repeated\n"); + input_event(d->input_dev, EV_KEY, event, 1); + input_sync(d->input_dev); + input_event(d->input_dev, EV_KEY, d->last_event, 0); + input_sync(d->input_dev); + break; + default: + break; } -/* improved repeat handling ??? - switch (state) { - case REMOTE_NO_KEY_PRESSED: - deb_rc("NO KEY PRESSED\n"); - if (d->last_state != REMOTE_NO_KEY_PRESSED) { - deb_rc("releasing event %d\n",d->last_event); - input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); - input_sync(d->rc_input_dev); - } - d->last_state = REMOTE_NO_KEY_PRESSED; - d->last_event = 0; - break; - case REMOTE_KEY_PRESSED: - deb_rc("KEY PRESSED\n"); - deb_rc("pressing event %d\n",event); - - input_event(d->rc_input_dev, EV_KEY, event, 1); - input_sync(d->rc_input_dev); - - d->last_event = event; - d->last_state = REMOTE_KEY_PRESSED; - break; - case REMOTE_KEY_REPEAT: - deb_rc("KEY_REPEAT\n"); - if (d->last_state != REMOTE_NO_KEY_PRESSED) { - deb_rc("repeating event %d\n",d->last_event); - input_event(d->rc_input_dev, EV_KEY, d->last_event, 2); - input_sync(d->rc_input_dev); - d->last_state = REMOTE_KEY_REPEAT; - } - default: - break; - } -*/ - schedule: - schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval)); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->props.rc.legacy.rc_interval)); } static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) @@ -206,10 +174,12 @@ static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { deb_rc("setting bit for event %d item %d\n", d->props.rc.legacy.rc_map_table[i].keycode, i); - set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit); + set_bit(d->props.rc.legacy.rc_map_table[i].keycode, + input_dev->keybit); } - /* setting these two values to non-zero, we have to manage key repeats */ + /* setting these two values to non-zero, we have to manage key + repeats */ input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval; input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150; @@ -221,7 +191,8 @@ static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) rc_interval = d->props.rc.legacy.rc_interval; - INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control); + INIT_DELAYED_WORK(&d->rc_query_work, + legacy_dvb_usb_read_remote_control); info("schedule remote query interval to %d msecs.", rc_interval); schedule_delayed_work(&d->rc_query_work, @@ -243,8 +214,8 @@ static void dvb_usb_read_remote_control(struct work_struct *work) container_of(work, struct dvb_usb_device, rc_query_work.work); int err; - /* TODO: need a lock here. We can simply skip checking for the remote control - if we're busy. */ + /* TODO: need a lock here. We can simply skip checking for the remote + control if we're busy. */ /* when the parameter has been set to 1 via sysfs while the * driver was running, or when bulk mode is enabled after IR init @@ -254,7 +225,8 @@ static void dvb_usb_read_remote_control(struct work_struct *work) err = d->props.rc.core.rc_query(d); if (err) - err("error %d while querying for an remote control event.", err); + err("error %d while querying for an remote control event.", + err); schedule_delayed_work(&d->rc_query_work, msecs_to_jiffies(d->props.rc.core.rc_interval)); @@ -361,30 +333,31 @@ int dvb_usbv2_nec_rc_key_to_event(struct dvb_usb_device *d, *event = 0; *state = REMOTE_NO_KEY_PRESSED; switch (keybuf[0]) { - case DVB_USB_RC_NEC_EMPTY: + case DVB_USB_RC_NEC_EMPTY: + break; + case DVB_USB_RC_NEC_KEY_PRESSED: + if ((u8) ~keybuf[1] != keybuf[2] || + (u8) ~keybuf[3] != keybuf[4]) { + deb_err("remote control checksum failed.\n"); break; - case DVB_USB_RC_NEC_KEY_PRESSED: - if ((u8) ~keybuf[1] != keybuf[2] || - (u8) ~keybuf[3] != keybuf[4]) { - deb_err("remote control checksum failed.\n"); - break; + } + /* See if we can match the raw key code. */ + for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) + if (rc5_custom(&keymap[i]) == keybuf[1] && + rc5_data(&keymap[i]) == keybuf[3]) { + *event = keymap[i].keycode; + *state = REMOTE_KEY_PRESSED; + return 0; } - /* See if we can match the raw key code. */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (rc5_custom(&keymap[i]) == keybuf[1] && - rc5_data(&keymap[i]) == keybuf[3]) { - *event = keymap[i].keycode; - *state = REMOTE_KEY_PRESSED; - return 0; - } - deb_err("key mapping failed - no appropriate key found in keymapping\n"); - break; - case DVB_USB_RC_NEC_KEY_REPEATED: - *state = REMOTE_KEY_REPEAT; - break; - default: - deb_err("unknown type of remote status: %d\n",keybuf[0]); - break; + deb_err("key mapping failed - no appropriate key found in" \ + " keymapping\n"); + break; + case DVB_USB_RC_NEC_KEY_REPEATED: + *state = REMOTE_KEY_REPEAT; + break; + default: + deb_err("unknown type of remote status: %d\n", keybuf[0]); + break; } return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index c4b7845373e2..8c98924a625a 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -11,7 +11,7 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen, int delay_ms) { - int actlen,ret = -ENOMEM; + int actlen, ret = -ENOMEM; if (!d || wbuf == NULL || wlen == 0) return -EINVAL; @@ -21,18 +21,19 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, return -EINVAL; } - if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + ret = mutex_lock_interruptible(&d->usb_mutex); + if (ret) return ret; deb_xfer(">>> "); - debug_dump(wbuf,wlen,deb_xfer); + debug_dump(wbuf, wlen, deb_xfer); - ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen, - 2000); + ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint), wbuf, wlen, + &actlen, 2000); if (ret) - err("bulk message failed: %d (%d/%d)",ret,wlen,actlen); + err("bulk message failed: %d (%d/%d)", ret, wlen, actlen); else ret = actlen != wlen ? -1 : 0; @@ -41,17 +42,17 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, if (delay_ms) msleep(delay_ms); - ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev, + ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint_response ? d->props.generic_bulk_ctrl_endpoint_response : - d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen, - 2000); + d->props.generic_bulk_ctrl_endpoint), + rbuf, rlen, &actlen, 2000); if (ret) - err("recv bulk message failed: %d",ret); + err("recv bulk message failed: %d", ret); else { deb_xfer("<<< "); - debug_dump(rbuf,actlen,deb_xfer); + debug_dump(rbuf, actlen, deb_xfer); } } @@ -62,18 +63,20 @@ EXPORT_SYMBOL(dvb_usbv2_generic_rw); int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) { - return dvb_usbv2_generic_rw(d,buf,len,NULL,0,0); + return dvb_usbv2_generic_rw(d, buf, len, NULL, 0, 0); } EXPORT_SYMBOL(dvb_usbv2_generic_write); -static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length) +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, + size_t length) { struct dvb_usb_adapter *adap = stream->user_priv; if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) dvb_dmx_swfilter(&adap->demux, buffer, length); } -static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length) +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, + u8 *buffer, size_t length) { struct dvb_usb_adapter *adap = stream->user_priv; if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c index bf1915367cb9..065f67c67538 100644 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -18,55 +18,59 @@ static void usb_urb_complete(struct urb *urb) int i; u8 *b; - deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n", + deb_uxfer("'%s' urb completed. status: %d, length: %d/%d," \ + " pack_num: %d, errors: %d\n", ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", - urb->status,urb->actual_length,urb->transfer_buffer_length, - urb->number_of_packets,urb->error_count); + urb->status, urb->actual_length, urb->transfer_buffer_length, + urb->number_of_packets, urb->error_count); switch (urb->status) { - case 0: /* success */ - case -ETIMEDOUT: /* NAK */ - break; - case -ECONNRESET: /* kill */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - deb_ts("urb completition error %d.\n", urb->status); - break; + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + deb_ts("urb completition error %d.\n", urb->status); + break; } b = (u8 *) urb->transfer_buffer; switch (ptype) { - case PIPE_ISOCHRONOUS: - for (i = 0; i < urb->number_of_packets; i++) { + case PIPE_ISOCHRONOUS: + for (i = 0; i < urb->number_of_packets; i++) { + if (urb->iso_frame_desc[i].status != 0) + deb_ts("iso frame descriptor has an" \ + " error: %d\n", + urb->iso_frame_desc[i].status); + else if (urb->iso_frame_desc[i].actual_length > 0) + stream->complete(stream, + b + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); - if (urb->iso_frame_desc[i].status != 0) - deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status); - else if (urb->iso_frame_desc[i].actual_length > 0) - stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); - - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - debug_dump(b,20,deb_uxfer); - break; - case PIPE_BULK: - if (urb->actual_length > 0) - stream->complete(stream, b, urb->actual_length); - break; - default: - err("unknown endpoint type in completition handler."); - return; + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + debug_dump(b, 20, deb_uxfer); + break; + case PIPE_BULK: + if (urb->actual_length > 0) + stream->complete(stream, b, urb->actual_length); + break; + default: + err("unknown endpoint type in completition handler."); + return; } - usb_submit_urb(urb,GFP_ATOMIC); + usb_submit_urb(urb, GFP_ATOMIC); } int usb_urb_kill(struct usb_data_stream *stream) { int i; for (i = 0; i < stream->urbs_submitted; i++) { - deb_ts("killing URB no. %d.\n",i); + deb_ts("killing URB no. %d.\n", i); /* stop the URB */ usb_kill_urb(stream->urb_list[i]); @@ -77,11 +81,13 @@ int usb_urb_kill(struct usb_data_stream *stream) int usb_urb_submit(struct usb_data_stream *stream) { - int i,ret; + int i, ret; for (i = 0; i < stream->urbs_initialized; i++) { - deb_ts("submitting URB no. %d\n",i); - if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) { - err("could not submit URB no. %d - get them all back",i); + deb_ts("submitting URB no. %d\n", i); + ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); + if (ret) { + err("could not submit URB no. %d - get them all back", + i); usb_urb_kill(stream); return ret; } @@ -95,7 +101,7 @@ static int usb_free_stream_buffers(struct usb_data_stream *stream) if (stream->state & USB_STATE_URB_BUF) { while (stream->buf_num) { stream->buf_num--; - deb_mem("freeing buffer %d\n",stream->buf_num); + deb_mem("freeing buffer %d\n", stream->buf_num); usb_free_coherent(stream->udev, stream->buf_size, stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]); @@ -107,26 +113,30 @@ static int usb_free_stream_buffers(struct usb_data_stream *stream) return 0; } -static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size) +static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, + unsigned long size) { stream->buf_num = 0; stream->buf_size = size; - deb_mem("all in all I will use %lu bytes for streaming\n",num*size); + deb_mem("all in all I will use %lu bytes for streaming\n", num * size); for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { - deb_mem("allocating buffer %d\n",stream->buf_num); - if (( stream->buf_list[stream->buf_num] = - usb_alloc_coherent(stream->udev, size, GFP_ATOMIC, - &stream->dma_addr[stream->buf_num]) ) == NULL) { - deb_mem("not enough memory for urb-buffer allocation.\n"); + deb_mem("allocating buffer %d\n", stream->buf_num); + stream->buf_list[stream->buf_num] = usb_alloc_coherent( + stream->udev, size, GFP_ATOMIC, + &stream->dma_addr[stream->buf_num]); + if (stream->buf_list[stream->buf_num] == NULL) { + deb_mem("not enough memory for urb-buffer" \ + " allocation.\n"); usb_free_stream_buffers(stream); return -ENOMEM; } - deb_mem("buffer %d: %p (dma: %Lu)\n", - stream->buf_num, -stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); - memset(stream->buf_list[stream->buf_num],0,size); + deb_mem("buffer %d: %p (dma: %llu)\n", + stream->buf_num, + stream->buf_list[stream->buf_num], + (long long)stream->dma_addr[stream->buf_num]); + memset(stream->buf_list[stream->buf_num], 0, size); stream->state |= USB_STATE_URB_BUF; } deb_mem("allocation successful\n"); @@ -138,8 +148,9 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream) { int i, j; - if ((i = usb_allocate_stream_buffers(stream,stream->props.count, - stream->props.u.bulk.buffersize)) < 0) + i = usb_allocate_stream_buffers(stream, stream->props.count, + stream->props.u.bulk.buffersize); + if (i < 0) return i; /* allocate the URBs */ @@ -151,8 +162,9 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream) usb_free_urb(stream->urb_list[j]); return -ENOMEM; } - usb_fill_bulk_urb( stream->urb_list[i], stream->udev, - usb_rcvbulkpipe(stream->udev,stream->props.endpoint), + usb_fill_bulk_urb(stream->urb_list[i], stream->udev, + usb_rcvbulkpipe(stream->udev, + stream->props.endpoint), stream->buf_list[i], stream->props.u.bulk.buffersize, usb_urb_complete, stream); @@ -166,10 +178,12 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream) static int usb_isoc_urb_init(struct usb_data_stream *stream) { - int i,j; + int i, j; - if ((i = usb_allocate_stream_buffers(stream,stream->props.count, - stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0) + i = usb_allocate_stream_buffers(stream, stream->props.count, + stream->props.u.isoc.framesize * + stream->props.u.isoc.framesperurb); + if (i < 0) return i; /* allocate the URBs */ @@ -177,7 +191,8 @@ static int usb_isoc_urb_init(struct usb_data_stream *stream) struct urb *urb; int frame_offset = 0; - stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC); + stream->urb_list[i] = usb_alloc_urb( + stream->props.u.isoc.framesperurb, GFP_ATOMIC); if (!stream->urb_list[i]) { deb_mem("not enough memory for urb_alloc_urb!\n"); for (j = 0; j < i; j++) @@ -190,7 +205,8 @@ static int usb_isoc_urb_init(struct usb_data_stream *stream) urb->dev = stream->udev; urb->context = stream; urb->complete = usb_urb_complete; - urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint); + urb->pipe = usb_rcvisocpipe(stream->udev, + stream->props.endpoint); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->interval = stream->props.u.isoc.interval; urb->number_of_packets = stream->props.u.isoc.framesperurb; @@ -200,7 +216,8 @@ static int usb_isoc_urb_init(struct usb_data_stream *stream) for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize; + urb->iso_frame_desc[j].length = + stream->props.u.isoc.framesize; frame_offset += stream->props.u.isoc.framesize; } @@ -209,14 +226,16 @@ static int usb_isoc_urb_init(struct usb_data_stream *stream) return 0; } -int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props) +int usb_urb_init(struct usb_data_stream *stream, + struct usb_data_stream_properties *props) { if (stream == NULL || props == NULL) return -EINVAL; memcpy(&stream->props, props, sizeof(*props)); - usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint)); + usb_clear_halt(stream->udev, usb_rcvbulkpipe(stream->udev, + stream->props.endpoint)); if (stream->complete == NULL) { err("there is no data callback - this doesn't make sense."); @@ -224,13 +243,13 @@ int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properti } switch (stream->props.type) { - case USB_BULK: - return usb_bulk_urb_init(stream); - case USB_ISOC: - return usb_isoc_urb_init(stream); - default: - err("unknown URB-type for data transfer."); - return -EINVAL; + case USB_BULK: + return usb_bulk_urb_init(stream); + case USB_ISOC: + return usb_isoc_urb_init(stream); + default: + err("unknown URB-type for data transfer."); + return -EINVAL; } } @@ -242,7 +261,7 @@ int usb_urb_exit(struct usb_data_stream *stream) for (i = 0; i < stream->urbs_initialized; i++) { if (stream->urb_list[i] != NULL) { - deb_mem("freeing URB no. %d.\n",i); + deb_mem("freeing URB no. %d.\n", i); /* free the URBs */ usb_free_urb(stream->urb_list[i]); } From 7dfd1242aa54f3246cf6f87158e2e14f0336b73d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 24 May 2012 20:00:28 -0300 Subject: [PATCH 0214/5375] [media] dvb_usb_v2: pass device name too using (struct usb_device_id) Pass all the needed data to the DVB USB core using (struct usb_device_id) .driver_info. That simplifies old code a lot and saves memory as all device IDs and names are not defined inside (struct dvb_usb_device_properties) as earlier. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 27 +------- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 6 +- drivers/media/dvb/dvb-usb/dvb_usb_i2c.c | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 79 ++++-------------------- 4 files changed, 19 insertions(+), 95 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 149e45f034f8..dc9d09bce107 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -60,23 +60,9 @@ #define warn(format, arg...) \ printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -/** - * struct dvb_usb_device_description - name and its according USB IDs - * @name: real name of the box, regardless which DVB USB device class is in use - * @cold_ids: array of struct usb_device_id which describe the device in - * pre-firmware state - * @warm_ids: array of struct usb_device_id which describe the device in - * post-firmware state - * - * Each DVB USB device class can have one or more actual devices, this struct - * assigns a name to it. - */ -struct dvb_usb_device_description { +struct dvb_usb_driver_info { const char *name; - -#define DVB_USB_ID_MAX_NUM 15 - struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM]; - struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM]; + const struct dvb_usb_device_properties *props; }; static inline u8 rc5_custom(struct rc_map_table *key) @@ -262,10 +248,6 @@ enum dvb_usb_mode { * the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used * instead of the generic_bulk_ctrl_endpoint when reading usb responses in * the dvb_usb_generic_rw helper function. - * - * @num_device_descs: number of struct dvb_usb_device_description in @devices - * @devices: array of struct dvb_usb_device_description compatibles with these - * properties. */ #define MAX_NO_OF_ADAPTER_PER_DEVICE 2 struct dvb_usb_device_properties { @@ -309,9 +291,6 @@ struct dvb_usb_device_properties { int generic_bulk_ctrl_endpoint; int generic_bulk_ctrl_endpoint_response; - - int num_device_descs; - struct dvb_usb_device_description devices[12]; }; /** @@ -437,7 +416,7 @@ struct dvb_usb_adapter { */ struct dvb_usb_device { struct dvb_usb_device_properties props; - struct dvb_usb_device_description *desc; + const char *name; struct usb_device *udev; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 832ef88ab248..85db3f46e77d 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -103,7 +103,7 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) { int i; - int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name, + int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->name, adap->dev->props.owner, &adap->dev->udev->dev, adap->dev->props.adapter_nr); @@ -236,7 +236,7 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) if (adap->props.fe[i].frontend_attach == NULL) { err("strange: '%s' #%d,%d " \ "doesn't want to attach a frontend.", - adap->dev->desc->name, adap->id, i); + adap->dev->name, adap->id, i); return 0; } @@ -246,7 +246,7 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) /* only print error when there is no FE at all */ if (i == 0) err("no frontend was attached by '%s'", - adap->dev->desc->name); + adap->dev->name); return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c index 58e5a4182245..6b272c861b4a 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c @@ -19,7 +19,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) return -EINVAL; } - strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); + strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); d->i2c_adap.algo = d->props.i2c_algo; d->i2c_adap.algo_data = NULL; d->i2c_adap.dev.parent = &d->udev->dev; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 14cfc1e35144..3314f36208ff 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -198,49 +198,6 @@ static int dvb_usb_init(struct dvb_usb_device *d) return 0; } -/* determine the name and the state of the just found USB device */ -static struct dvb_usb_device_description *dvb_usb_find_device( - struct usb_device *udev, - struct dvb_usb_device_properties *props, bool *cold) -{ - int i, j; - struct dvb_usb_device_description *desc = NULL; - - *cold = true; - - for (i = 0; i < props->num_device_descs; i++) { - for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) { - deb_info("check for cold %x %x\n", - props->devices[i].cold_ids[j]->idVendor, - props->devices[i].cold_ids[j]->idProduct); - if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && - props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { - *cold = true; - desc = &props->devices[i]; - break; - } - } - - if (desc != NULL) - break; - - for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) { - deb_info("check for warm %x %x\n", - props->devices[i].warm_ids[j]->idVendor, - props->devices[i].warm_ids[j]->idProduct); - - if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) && - props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) { - *cold = false; - desc = &props->devices[i]; - break; - } - } - } - - return desc; -} - int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) { if (onoff) @@ -265,11 +222,11 @@ int dvb_usbv2_device_init(struct usb_interface *intf, { struct usb_device *udev = interface_to_usbdev(intf); struct dvb_usb_device *d = NULL; - struct dvb_usb_device_description *desc = NULL; - struct dvb_usb_device_properties *props = - (struct dvb_usb_device_properties *) id->driver_info; + struct dvb_usb_driver_info *driver_info = + (struct dvb_usb_driver_info *) id->driver_info; + const struct dvb_usb_device_properties *props = driver_info->props; int ret = -ENOMEM; - bool cold; + bool cold = false; d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); if (d == NULL) { @@ -278,6 +235,7 @@ int dvb_usbv2_device_init(struct usb_interface *intf, } d->udev = udev; + d->name = driver_info->name; memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); if (d->props.size_of_priv > 0) { @@ -289,18 +247,6 @@ int dvb_usbv2_device_init(struct usb_interface *intf, } } - desc = dvb_usb_find_device(udev, props, &cold); - - if (desc == NULL) { - deb_err("something went very wrong, device was not found in" \ - " current device list - let's see what" \ - " comes next.\n"); - ret = -ENODEV; - goto err_kfree; - } - - d->desc = desc; - if (d->props.identify_state) { ret = d->props.identify_state(d); if (ret == 0) { @@ -315,7 +261,7 @@ int dvb_usbv2_device_init(struct usb_interface *intf, if (cold) { info("found a '%s' in cold state, will try to load a firmware", - desc->name); + d->name); ret = dvb_usb_download_firmware(d); if (ret == 0) { ; @@ -327,16 +273,16 @@ int dvb_usbv2_device_init(struct usb_interface *intf, } } - info("found a '%s' in warm state.", desc->name); + info("found a '%s' in warm state.", d->name); usb_set_intfdata(intf, d); ret = dvb_usb_init(d); if (ret == 0) - info("%s successfully initialized and connected.", desc->name); + info("%s successfully initialized and connected.", d->name); else - info("%s error while loading driver (%d)", desc->name, ret); + info("%s error while loading driver (%d)", d->name, ret); return 0; @@ -351,15 +297,14 @@ EXPORT_SYMBOL(dvb_usbv2_device_init); void dvb_usbv2_device_exit(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name = "generic DVB-USB module"; + const char *name; usb_set_intfdata(intf, NULL); - if (d != NULL && d->desc != NULL) { - name = d->desc->name; + if (d) { + name = d->name; dvb_usb_exit(d); } info("%s successfully deinitialized and disconnected.", name); - } EXPORT_SYMBOL(dvb_usbv2_device_exit); From 5b8530041358bd1f316ed793cc46b73c038172a7 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 24 May 2012 21:11:42 -0300 Subject: [PATCH 0215/5375] [media] dvb_usb_v2: implement .get_adapter_count() Callback to resolve adapter count of current device. Old static .num_adapters field can be still used but the new .get_adapter_count() has priority if both offered by the driver. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 1 + drivers/media/dvb/dvb-usb/dvb_usb_init.c | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index dc9d09bce107..a3cc557298b4 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -271,6 +271,7 @@ struct dvb_usb_device_properties { int size_of_priv; int num_adapters; + int (*get_adapter_count) (struct dvb_usb_device *); struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; int (*power_ctrl) (struct dvb_usb_device *, int); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 3314f36208ff..11d5c96a4600 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -34,9 +34,19 @@ MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a" \ static int dvb_usb_adapter_init(struct dvb_usb_device *d) { struct dvb_usb_adapter *adap; - int ret, n, o; + int ret, n, o, adapter_count; - for (n = 0; n < d->props.num_adapters; n++) { + /* resolve adapter count */ + adapter_count = d->props.num_adapters; + if (d->props.get_adapter_count) { + ret = d->props.get_adapter_count(d); + if (ret < 0) + goto err; + + adapter_count = ret; + } + + for (n = 0; n < adapter_count; n++) { adap = &d->adapter[n]; adap->dev = d; adap->id = n; @@ -133,6 +143,9 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d) } return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; } static int dvb_usb_adapter_exit(struct dvb_usb_device *d) @@ -297,7 +310,7 @@ EXPORT_SYMBOL(dvb_usbv2_device_init); void dvb_usbv2_device_exit(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name; + const char *name = NULL; usb_set_intfdata(intf, NULL); if (d) { From 43402bbde52e96f950994bc55700814db8d5bc81 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 24 May 2012 22:18:37 -0300 Subject: [PATCH 0216/5375] [media] dvb_usb_v2: implement .read_config() That callback is called only once when device is connected. Call is done after the possible firmware is downloaded to the device, just after the .power_ctrl() and before adapters are created. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 1 + drivers/media/dvb/dvb-usb/dvb_usb_init.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index a3cc557298b4..8ddae58e8e72 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -275,6 +275,7 @@ struct dvb_usb_device_properties { struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; int (*power_ctrl) (struct dvb_usb_device *, int); + int (*read_config) (struct dvb_usb_device *d); int (*read_mac_address) (struct dvb_usb_device *, u8 []); #define WARM 0 diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 11d5c96a4600..d694ea9ecc91 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -190,6 +190,13 @@ static int dvb_usb_init(struct dvb_usb_device *d) /* check the capabilities and set appropriate variables */ dvb_usb_device_power_ctrl(d, 1); + /* read config */ + if (d->props.read_config) { + ret = d->props.read_config(d); + if (ret < 0) + goto err; + } + ret = dvb_usb_i2c_init(d); if (ret == 0) ret = dvb_usb_adapter_init(d); @@ -209,6 +216,9 @@ static int dvb_usb_init(struct dvb_usb_device *d) dvb_usb_device_power_ctrl(d, 0); return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; } int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) From 649216704aaa1148c638346ec4c0dc71b164f521 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 25 May 2012 10:19:03 -0300 Subject: [PATCH 0217/5375] [media] dvb_usb_v2: remote controller * remove old legacy code totally * move default RC keymap definition the the (struct dvb_usb_driver_info) Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 60 +---- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 1 + drivers/media/dvb/dvb-usb/dvb_usb_remote.c | 278 ++------------------- 3 files changed, 22 insertions(+), 317 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 8ddae58e8e72..974337ddc5c4 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -62,24 +62,10 @@ struct dvb_usb_driver_info { const char *name; + const char *rc_map; const struct dvb_usb_device_properties *props; }; -static inline u8 rc5_custom(struct rc_map_table *key) -{ - return (key->scancode >> 8) & 0xff; -} - -static inline u8 rc5_data(struct rc_map_table *key) -{ - return key->scancode & 0xff; -} - -static inline u16 rc5_scan(struct rc_map_table *key) -{ - return key->scancode & 0xffff; -} - struct dvb_usb_device; struct dvb_usb_adapter; struct usb_data_stream; @@ -160,25 +146,6 @@ struct dvb_usb_adapter_properties { struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP]; }; -/** - * struct dvb_rc_legacy - old properties of remote controller - * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable - * remote control handling). - * @rc_map_size: number of items in @rc_map_table. - * @rc_query: called to query an event event. - * @rc_interval: time in ms between two queries. - */ -struct dvb_rc_legacy { -/* remote control properties */ -#define REMOTE_NO_KEY_PRESSED 0x00 -#define REMOTE_KEY_PRESSED 0x01 -#define REMOTE_KEY_REPEAT 0x02 - struct rc_map_table *rc_map_table; - int rc_map_size; - int (*rc_query) (struct dvb_usb_device *, u32 *, int *); - int rc_interval; -}; - /** * struct dvb_rc properties of remote controller, using rc-core * @rc_codes: name of rc codes table @@ -202,17 +169,6 @@ struct dvb_rc { bool bulk_mode; /* uses bulk mode */ }; -/** - * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one - * based on rc-core - * This is initialized/used only inside dvb-usb-remote.c. - * It shouldn't be set by the drivers. - */ -enum dvb_usb_mode { - DVB_RC_LEGACY, - DVB_RC_CORE, -}; - /** * struct dvb_usb_device_properties - properties of a dvb-usb-device * @owner: owner of the dvb_adapter @@ -283,16 +239,12 @@ struct dvb_usb_device_properties { int (*identify_state) (struct dvb_usb_device *); int (*init) (struct dvb_usb_device *); - struct { - enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */ - struct dvb_rc_legacy legacy; - struct dvb_rc core; - } rc; - struct i2c_algorithm *i2c_algo; int generic_bulk_ctrl_endpoint; int generic_bulk_ctrl_endpoint_response; + + struct dvb_rc rc; }; /** @@ -419,7 +371,7 @@ struct dvb_usb_adapter { struct dvb_usb_device { struct dvb_usb_device_properties props; const char *name; - + const char *rc_map; struct usb_device *udev; #define DVB_USB_STATE_INIT 0x000 @@ -460,10 +412,6 @@ extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16, int); extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16); -/* commonly used remote control parsing */ -extern int dvb_usbv2_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, - int *); - /* commonly used firmware download types and function */ struct hexline { u8 len; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index d694ea9ecc91..e1a3ed65cfb2 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -259,6 +259,7 @@ int dvb_usbv2_device_init(struct usb_interface *intf, d->udev = udev; d->name = driver_info->name; + d->rc_map = driver_info->rc_map; memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); if (d->props.size_of_priv > 0) { diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c index b445990644ae..b8d2cb193bb1 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c @@ -9,200 +9,6 @@ #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, - 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; - 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); - if (index >= keymap_size) - return -EINVAL; - - 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 0; -} - -static int legacy_dvb_usb_setkeycode(struct input_dev *dev, - 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; - 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 - * would be to allocate a table with key_map_size + 1, - * 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 0; -} - -/* Remote-control poll function - called every dib->rc_query_interval ms to see - * whether the remote control has received anything. - * - * TODO: Fix the repeat rate of the input device. - */ -static void legacy_dvb_usb_read_remote_control(struct work_struct *work) -{ - struct dvb_usb_device *d = - container_of(work, struct dvb_usb_device, rc_query_work.work); - u32 event; - int state; - - /* TODO: need a lock here. We can simply skip checking for the remote - control if we're busy. */ - - /* when the parameter has been set to 1 via sysfs while the driver - was running */ - if (dvb_usb_disable_rc_polling) - return; - - if (d->props.rc.legacy.rc_query(d, &event, &state)) { - err("error while querying for an remote control event."); - goto schedule; - } - - - switch (state) { - case REMOTE_NO_KEY_PRESSED: - break; - case REMOTE_KEY_PRESSED: - deb_rc("key pressed\n"); - d->last_event = event; - case REMOTE_KEY_REPEAT: - deb_rc("key repeated\n"); - input_event(d->input_dev, EV_KEY, event, 1); - input_sync(d->input_dev); - input_event(d->input_dev, EV_KEY, d->last_event, 0); - input_sync(d->input_dev); - break; - default: - break; - } - -schedule: - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->props.rc.legacy.rc_interval)); -} - -static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) -{ - int i, err, rc_interval; - struct input_dev *input_dev; - - input_dev = input_allocate_device(); - if (!input_dev) - return -ENOMEM; - - input_dev->evbit[0] = BIT_MASK(EV_KEY); - input_dev->name = "IR-receiver inside an USB DVB receiver"; - input_dev->phys = d->rc_phys; - usb_to_input_id(d->udev, &input_dev->id); - input_dev->dev.parent = &d->udev->dev; - d->input_dev = input_dev; - d->rc_dev = NULL; - - 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); - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { - deb_rc("setting bit for event %d item %d\n", - d->props.rc.legacy.rc_map_table[i].keycode, i); - set_bit(d->props.rc.legacy.rc_map_table[i].keycode, - input_dev->keybit); - } - - /* setting these two values to non-zero, we have to manage key - repeats */ - input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval; - input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150; - - input_set_drvdata(input_dev, d); - - err = input_register_device(input_dev); - if (err) - input_free_device(input_dev); - - rc_interval = d->props.rc.legacy.rc_interval; - - INIT_DELAYED_WORK(&d->rc_query_work, - legacy_dvb_usb_read_remote_control); - - info("schedule remote query interval to %d msecs.", rc_interval); - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(rc_interval)); - - d->state |= DVB_USB_STATE_REMOTE; - - return err; -} - /* Remote-control poll function - called every dib->rc_query_interval ms to see * whether the remote control has received anything. * @@ -220,16 +26,16 @@ static void dvb_usb_read_remote_control(struct work_struct *work) /* when the parameter has been set to 1 via sysfs while the * driver was running, or when bulk mode is enabled after IR init */ - if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode) + if (dvb_usb_disable_rc_polling || d->props.rc.bulk_mode) return; - err = d->props.rc.core.rc_query(d); + err = d->props.rc.rc_query(d); if (err) err("error %d while querying for an remote control event.", err); schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->props.rc.core.rc_interval)); + msecs_to_jiffies(d->props.rc.rc_interval)); } static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) @@ -241,17 +47,21 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) if (!dev) return -ENOMEM; - dev->driver_name = d->props.rc.core.module_name; - 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 = d->props.rc.core.driver_type; + dev->driver_name = d->props.rc.module_name; + dev->map_name = d->rc_map; + dev->change_protocol = d->props.rc.change_protocol; + dev->allowed_protos = d->props.rc.allowed_protos; + dev->driver_type = d->props.rc.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; dev->dev.parent = &d->udev->dev; dev->priv = d; + /* leave remote controller enabled even there is no default map */ + if (dev->map_name == NULL) + dev->map_name = RC_MAP_EMPTY; + err = rc_register_device(dev); if (err < 0) { rc_free_device(dev); @@ -261,13 +71,13 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) d->input_dev = NULL; d->rc_dev = dev; - if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode) + if (!d->props.rc.rc_query || d->props.rc.bulk_mode) return 0; /* Polling mode - initialize a work queue for handling it */ INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); - rc_interval = d->props.rc.core.rc_interval; + rc_interval = d->props.rc.rc_interval; info("schedule remote query interval to %d msecs.", rc_interval); schedule_delayed_work(&d->rc_query_work, @@ -283,24 +93,14 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) if (dvb_usb_disable_rc_polling) return 0; - if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query) - d->props.rc.mode = DVB_RC_LEGACY; - else if (d->props.rc.core.rc_codes) - d->props.rc.mode = DVB_RC_CORE; - else + if (d->props.rc.module_name == NULL) return 0; usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); /* Start the remote-control polling. */ - if (d->props.rc.legacy.rc_interval < 40) - d->props.rc.legacy.rc_interval = 100; /* default */ - - if (d->props.rc.mode == DVB_RC_LEGACY) - err = legacy_dvb_usb_remote_init(d); - else - err = rc_core_dvb_usb_remote_init(d); + err = rc_core_dvb_usb_remote_init(d); if (err) return err; @@ -313,52 +113,8 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d) { if (d->state & DVB_USB_STATE_REMOTE) { cancel_delayed_work_sync(&d->rc_query_work); - if (d->props.rc.mode == DVB_RC_LEGACY) - input_unregister_device(d->input_dev); - else - rc_unregister_device(d->rc_dev); + rc_unregister_device(d->rc_dev); } d->state &= ~DVB_USB_STATE_REMOTE; return 0; } - -#define DVB_USB_RC_NEC_EMPTY 0x00 -#define DVB_USB_RC_NEC_KEY_PRESSED 0x01 -#define DVB_USB_RC_NEC_KEY_REPEATED 0x02 -int dvb_usbv2_nec_rc_key_to_event(struct dvb_usb_device *d, - u8 keybuf[5], u32 *event, int *state) -{ - int i; - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - switch (keybuf[0]) { - case DVB_USB_RC_NEC_EMPTY: - break; - case DVB_USB_RC_NEC_KEY_PRESSED: - if ((u8) ~keybuf[1] != keybuf[2] || - (u8) ~keybuf[3] != keybuf[4]) { - deb_err("remote control checksum failed.\n"); - break; - } - /* See if we can match the raw key code. */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (rc5_custom(&keymap[i]) == keybuf[1] && - rc5_data(&keymap[i]) == keybuf[3]) { - *event = keymap[i].keycode; - *state = REMOTE_KEY_PRESSED; - return 0; - } - deb_err("key mapping failed - no appropriate key found in" \ - " keymapping\n"); - break; - case DVB_USB_RC_NEC_KEY_REPEATED: - *state = REMOTE_KEY_REPEAT; - break; - default: - deb_err("unknown type of remote status: %d\n", keybuf[0]); - break; - } - return 0; -} -EXPORT_SYMBOL(dvb_usbv2_nec_rc_key_to_event); From 005bc3fce76b3bd7c0a583cf3e89ce11c87077cd Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 25 May 2012 12:28:43 -0300 Subject: [PATCH 0218/5375] [media] dvb_usb_v2: restore .firmware - pointer to name Most commonly only one firmware is used by the driver and it is not needed to selected run time. So restore old functionality but allow .get_firmware_name() callback to override it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 7 ++++--- drivers/media/dvb/dvb-usb/dvb_usb_firmware.c | 10 +++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 974337ddc5c4..716f17455669 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -219,12 +219,13 @@ struct dvb_usb_device_properties { #define CYPRESS_FX2 3 int usb_ctrl; + int size_of_priv; + + const char *firmware; + int (*get_firmware_name) (struct dvb_usb_device *, const char **); #define RECONNECTS_USB 1 int (*download_firmware) (struct dvb_usb_device *, const struct firmware *); - int (*get_firmware_name) (struct dvb_usb_device *, const char **); - - int size_of_priv; int num_adapters; int (*get_adapter_count) (struct dvb_usb_device *); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c index 62bd865a6462..e0b43139c0c4 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c @@ -96,9 +96,13 @@ int dvb_usb_download_firmware(struct dvb_usb_device *d) const struct firmware *fw = NULL; const char *name; - ret = d->props.get_firmware_name(d, &name); - if (ret < 0) - return ret; + /* resolve firmware name */ + name = d->props.firmware; + if (d->props.get_firmware_name) { + ret = d->props.get_firmware_name(d, &name); + if (ret < 0) + return ret; + } ret = request_firmware(&fw, name, &d->udev->dev); if (ret != 0) { From 19b308c035b4d65cc32a67d9e020377e6bf9c852 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 25 May 2012 12:58:34 -0300 Subject: [PATCH 0219/5375] [media] dvb_usb_v2: init I2C and USB mutex earlier Those must be initialized earlier as we now pass (struct dvb_usb_device *) to the firmware download callbacks too. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index e1a3ed65cfb2..1441324a9115 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -182,9 +182,6 @@ static int dvb_usb_init(struct dvb_usb_device *d) { int ret = 0; - mutex_init(&d->usb_mutex); - mutex_init(&d->i2c_mutex); - d->state = DVB_USB_STATE_INIT; /* check the capabilities and set appropriate variables */ @@ -261,6 +258,8 @@ int dvb_usbv2_device_init(struct usb_interface *intf, d->name = driver_info->name; d->rc_map = driver_info->rc_map; memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); + mutex_init(&d->usb_mutex); + mutex_init(&d->i2c_mutex); if (d->props.size_of_priv > 0) { d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); From 05752890411cee29464f4edc5e2f1bb904679f5b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 26 May 2012 11:43:24 -0300 Subject: [PATCH 0220/5375] [media] dvb_usb_v2: remote controller changes Add .get_rc_config() callback and remove old static configs. Refactor remote controller routines. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 20 ++-- drivers/media/dvb/dvb-usb/dvb_usb_remote.c | 115 ++++++++++----------- 2 files changed, 66 insertions(+), 69 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 716f17455669..0715e72259f6 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -157,16 +157,14 @@ struct dvb_usb_adapter_properties { * @rc_interval: time in ms between two queries. * @bulk_mode: device supports bulk mode for RC (disable polling mode) */ -struct dvb_rc { - char *rc_codes; - u64 protocol; +struct dvb_usb_rc { + char *map_name; 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); - int rc_interval; - bool bulk_mode; /* uses bulk mode */ + int (*query) (struct dvb_usb_device *d); + int interval; + const enum rc_driver_type driver_type; + bool bulk_mode; }; /** @@ -207,6 +205,7 @@ struct dvb_rc { */ #define MAX_NO_OF_ADAPTER_PER_DEVICE 2 struct dvb_usb_device_properties { + const char *driver_name; struct module *owner; short *adapter_nr; @@ -234,18 +233,18 @@ struct dvb_usb_device_properties { int (*power_ctrl) (struct dvb_usb_device *, int); int (*read_config) (struct dvb_usb_device *d); int (*read_mac_address) (struct dvb_usb_device *, u8 []); + int (*tuner_attach) (struct dvb_frontend *); #define WARM 0 #define COLD 1 int (*identify_state) (struct dvb_usb_device *); int (*init) (struct dvb_usb_device *); + int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *); struct i2c_algorithm *i2c_algo; int generic_bulk_ctrl_endpoint; int generic_bulk_ctrl_endpoint_response; - - struct dvb_rc rc; }; /** @@ -373,6 +372,7 @@ struct dvb_usb_device { struct dvb_usb_device_properties props; const char *name; const char *rc_map; + struct dvb_usb_rc rc; struct usb_device *udev; #define DVB_USB_STATE_INIT 0x000 diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c index b8d2cb193bb1..22d7790e7c42 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c @@ -16,9 +16,9 @@ */ static void dvb_usb_read_remote_control(struct work_struct *work) { - struct dvb_usb_device *d = - container_of(work, struct dvb_usb_device, rc_query_work.work); - int err; + struct dvb_usb_device *d = container_of(work, + struct dvb_usb_device, rc_query_work.work); + int ret; /* TODO: need a lock here. We can simply skip checking for the remote control if we're busy. */ @@ -26,87 +26,82 @@ static void dvb_usb_read_remote_control(struct work_struct *work) /* when the parameter has been set to 1 via sysfs while the * driver was running, or when bulk mode is enabled after IR init */ - if (dvb_usb_disable_rc_polling || d->props.rc.bulk_mode) + if (dvb_usb_disable_rc_polling || d->rc.bulk_mode) return; - err = d->props.rc.rc_query(d); - if (err) - err("error %d while querying for an remote control event.", - err); + ret = d->rc.query(d); + if (ret < 0) + err("error %d while querying for an remote control event", ret); schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->props.rc.rc_interval)); + msecs_to_jiffies(d->rc.interval)); } -static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) +int dvb_usb_remote_init(struct dvb_usb_device *d) { - int err, rc_interval; + int ret; struct rc_dev *dev; + if (dvb_usb_disable_rc_polling || !d->props.get_rc_config) + return 0; + + ret = d->props.get_rc_config(d, &d->rc); + if (ret < 0) + goto err; + dev = rc_allocate_device(); - if (!dev) - return -ENOMEM; + if (!dev) { + ret = -ENOMEM; + goto err; + } - dev->driver_name = d->props.rc.module_name; - dev->map_name = d->rc_map; - dev->change_protocol = d->props.rc.change_protocol; - dev->allowed_protos = d->props.rc.allowed_protos; - dev->driver_type = d->props.rc.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; dev->dev.parent = &d->udev->dev; + dev->input_name = "IR-receiver inside an USB DVB receiver"; + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + dev->input_phys = d->rc_phys; + usb_to_input_id(d->udev, &dev->input_id); + /* TODO: likely RC-core should took const char * */ + dev->driver_name = (char *) d->props.driver_name; + dev->driver_type = d->rc.driver_type; + dev->allowed_protos = d->rc.allowed_protos; + dev->change_protocol = d->rc.change_protocol; dev->priv = d; + /* select used keymap */ + if (d->rc.map_name) + dev->map_name = d->rc.map_name; + else if (d->rc_map) + dev->map_name = d->rc_map; + else + dev->map_name = RC_MAP_EMPTY; /* keep rc enabled */ - /* leave remote controller enabled even there is no default map */ - if (dev->map_name == NULL) - dev->map_name = RC_MAP_EMPTY; - - err = rc_register_device(dev); - if (err < 0) { + ret = rc_register_device(dev); + if (ret < 0) { rc_free_device(dev); - return err; + goto err; } d->input_dev = NULL; d->rc_dev = dev; - if (!d->props.rc.rc_query || d->props.rc.bulk_mode) - return 0; + /* start polling if needed */ + if (d->rc.query && !d->rc.bulk_mode) { + /* initialize a work queue for handling polling */ + INIT_DELAYED_WORK(&d->rc_query_work, + dvb_usb_read_remote_control); - /* Polling mode - initialize a work queue for handling it */ - INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); - - rc_interval = d->props.rc.rc_interval; - - info("schedule remote query interval to %d msecs.", rc_interval); - schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(rc_interval)); - - return 0; -} - -int dvb_usb_remote_init(struct dvb_usb_device *d) -{ - int err; - - if (dvb_usb_disable_rc_polling) - return 0; - - if (d->props.rc.module_name == NULL) - return 0; - - usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); - strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); - - /* Start the remote-control polling. */ - err = rc_core_dvb_usb_remote_init(d); - if (err) - return err; + info("schedule remote query interval to %d msecs", + d->rc.interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); + } d->state |= DVB_USB_STATE_REMOTE; return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; } int dvb_usb_remote_exit(struct dvb_usb_device *d) @@ -115,6 +110,8 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d) cancel_delayed_work_sync(&d->rc_query_work); rc_unregister_device(d->rc_dev); } + d->state &= ~DVB_USB_STATE_REMOTE; + return 0; } From bce1c0290270fbc8c18414de4cbdb035521230d6 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 28 May 2012 17:25:40 -0300 Subject: [PATCH 0221/5375] [media] dvb_usb_v2: dynamic USB stream URB configuration Change URB count, buffer size and type [BULK/ISOC] dynamically when needed if existing URB buffers are big enough. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 3 +- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 2 +- drivers/media/dvb/dvb-usb/usb_urb.c | 256 +++++++++++++-------- 3 files changed, 169 insertions(+), 92 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index 60f8ccba8dcd..2c73829f2764 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -33,7 +33,8 @@ extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props); extern int usb_urb_exit(struct usb_data_stream *stream); -extern int usb_urb_submit(struct usb_data_stream *stream); +extern int usb_urb_submit(struct usb_data_stream *stream, + struct usb_data_stream_properties *props); extern int usb_urb_kill(struct usb_data_stream *stream); extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 85db3f46e77d..fd02be30b532 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -57,7 +57,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) */ if (adap->feedcount == onoff && adap->feedcount > 0) { deb_ts("submitting all URBs\n"); - usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); + usb_urb_submit(&adap->fe_adap[adap->active_fe].stream, NULL); deb_ts("controlling pid parser\n"); if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c index 065f67c67538..8792334642a2 100644 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -11,6 +11,10 @@ #include "dvb_usb_common.h" /* URB stuff for streaming */ + +int usb_urb_reconfig(struct usb_data_stream *stream, + struct usb_data_stream_properties *props); + static void usb_urb_complete(struct urb *urb) { struct usb_data_stream *stream = urb->context; @@ -79,9 +83,17 @@ int usb_urb_kill(struct usb_data_stream *stream) return 0; } -int usb_urb_submit(struct usb_data_stream *stream) +int usb_urb_submit(struct usb_data_stream *stream, + struct usb_data_stream_properties *props) { int i, ret; + + if (props) { + ret = usb_urb_reconfig(stream, props); + if (ret < 0) + return ret; + } + for (i = 0; i < stream->urbs_initialized; i++) { deb_ts("submitting URB no. %d\n", i); ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); @@ -96,7 +108,100 @@ int usb_urb_submit(struct usb_data_stream *stream) return 0; } -static int usb_free_stream_buffers(struct usb_data_stream *stream) +int usb_urb_free_urbs(struct usb_data_stream *stream) +{ + int i; + + usb_urb_kill(stream); + + for (i = 0; i < stream->urbs_initialized; i++) { + if (stream->urb_list[i] != NULL) { + deb_mem("freeing URB no. %d.\n", i); + pr_debug("%s: free URB=%d\n", __func__, i); + /* free the URBs */ + usb_free_urb(stream->urb_list[i]); + } + } + stream->urbs_initialized = 0; + + return 0; +} + +static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream) +{ + int i, j; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + pr_debug("%s: alloc URB=%d\n", __func__, i); + stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!.\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[j]); + return -ENOMEM; + } + usb_fill_bulk_urb(stream->urb_list[i], + stream->udev, + usb_rcvbulkpipe(stream->udev, + stream->props.endpoint), + stream->buf_list[i], + stream->props.u.bulk.buffersize, + usb_urb_complete, stream); + + stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; + stream->urbs_initialized++; + } + return 0; +} + +static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) +{ + int i, j; + + /* allocate the URBs */ + for (i = 0; i < stream->props.count; i++) { + struct urb *urb; + int frame_offset = 0; + pr_debug("%s: alloc URB=%d\n", __func__, i); + stream->urb_list[i] = usb_alloc_urb( + stream->props.u.isoc.framesperurb, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[j]); + return -ENOMEM; + } + + urb = stream->urb_list[i]; + + urb->dev = stream->udev; + urb->context = stream; + urb->complete = usb_urb_complete; + urb->pipe = usb_rcvisocpipe(stream->udev, + stream->props.endpoint); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->interval = stream->props.u.isoc.interval; + urb->number_of_packets = stream->props.u.isoc.framesperurb; + urb->transfer_buffer_length = stream->props.u.isoc.framesize * + stream->props.u.isoc.framesperurb; + urb->transfer_buffer = stream->buf_list[i]; + urb->transfer_dma = stream->dma_addr[i]; + + for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = + stream->props.u.isoc.framesize; + frame_offset += stream->props.u.isoc.framesize; + } + + stream->urbs_initialized++; + } + return 0; +} + +int usb_free_stream_buffers(struct usb_data_stream *stream) { if (stream->state & USB_STATE_URB_BUF) { while (stream->buf_num) { @@ -113,7 +218,7 @@ static int usb_free_stream_buffers(struct usb_data_stream *stream) return 0; } -static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, +int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size) { stream->buf_num = 0; @@ -144,91 +249,62 @@ static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, return 0; } -static int usb_bulk_urb_init(struct usb_data_stream *stream) +int usb_urb_reconfig(struct usb_data_stream *stream, + struct usb_data_stream_properties *props) { - int i, j; + int buf_size; - i = usb_allocate_stream_buffers(stream, stream->props.count, - stream->props.u.bulk.buffersize); - if (i < 0) - return i; + if (props == NULL) + return 0; - /* allocate the URBs */ - for (i = 0; i < stream->props.count; i++) { - stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); - if (!stream->urb_list[i]) { - deb_mem("not enough memory for urb_alloc_urb!.\n"); - for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[j]); - return -ENOMEM; - } - usb_fill_bulk_urb(stream->urb_list[i], stream->udev, - usb_rcvbulkpipe(stream->udev, - stream->props.endpoint), - stream->buf_list[i], - stream->props.u.bulk.buffersize, - usb_urb_complete, stream); + /* check allocated buffers are large enough for the request */ + if (props->type == USB_BULK) + buf_size = stream->props.u.bulk.buffersize; + else if (props->type == USB_ISOC) + buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb; + else + return -EINVAL; - stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; - stream->urbs_initialized++; + if (stream->buf_num < props->count || stream->buf_size < buf_size) { + err("cannot reconfigure as allocated buffers are too small"); + return -EINVAL; } - return 0; -} -static int usb_isoc_urb_init(struct usb_data_stream *stream) -{ - int i, j; - - i = usb_allocate_stream_buffers(stream, stream->props.count, - stream->props.u.isoc.framesize * - stream->props.u.isoc.framesperurb); - if (i < 0) - return i; - - /* allocate the URBs */ - for (i = 0; i < stream->props.count; i++) { - struct urb *urb; - int frame_offset = 0; - - stream->urb_list[i] = usb_alloc_urb( - stream->props.u.isoc.framesperurb, GFP_ATOMIC); - if (!stream->urb_list[i]) { - deb_mem("not enough memory for urb_alloc_urb!\n"); - for (j = 0; j < i; j++) - usb_free_urb(stream->urb_list[j]); - return -ENOMEM; - } - - urb = stream->urb_list[i]; - - urb->dev = stream->udev; - urb->context = stream; - urb->complete = usb_urb_complete; - urb->pipe = usb_rcvisocpipe(stream->udev, - stream->props.endpoint); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->interval = stream->props.u.isoc.interval; - urb->number_of_packets = stream->props.u.isoc.framesperurb; - urb->transfer_buffer_length = stream->buf_size; - urb->transfer_buffer = stream->buf_list[i]; - urb->transfer_dma = stream->dma_addr[i]; - - for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { - urb->iso_frame_desc[j].offset = frame_offset; - urb->iso_frame_desc[j].length = - stream->props.u.isoc.framesize; - frame_offset += stream->props.u.isoc.framesize; - } - - stream->urbs_initialized++; + /* check if all fields are same */ + if (stream->props.type == props->type && + stream->props.count == props->count && + stream->props.endpoint == props->endpoint) { + if (props->type == USB_BULK && + props->u.bulk.buffersize == + stream->props.u.bulk.buffersize) + return 0; + else if (props->type == USB_ISOC && + props->u.isoc.framesperurb == + stream->props.u.isoc.framesperurb && + props->u.isoc.framesize == + stream->props.u.isoc.framesize && + props->u.isoc.interval == + stream->props.u.isoc.interval) + return 0; } + + pr_debug("%s: re-alloc URBs\n", __func__); + + usb_urb_free_urbs(stream); + memcpy(&stream->props, props, sizeof(*props)); + if (props->type == USB_BULK) + return usb_urb_alloc_bulk_urbs(stream); + else if (props->type == USB_ISOC) + return usb_urb_alloc_isoc_urbs(stream); + return 0; } int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props) { + int ret; + if (stream == NULL || props == NULL) return -EINVAL; @@ -244,9 +320,20 @@ int usb_urb_init(struct usb_data_stream *stream, switch (stream->props.type) { case USB_BULK: - return usb_bulk_urb_init(stream); + ret = usb_alloc_stream_buffers(stream, stream->props.count, + stream->props.u.bulk.buffersize); + if (ret < 0) + return ret; + + return usb_urb_alloc_bulk_urbs(stream); case USB_ISOC: - return usb_isoc_urb_init(stream); + ret = usb_alloc_stream_buffers(stream, stream->props.count, + stream->props.u.isoc.framesize * + stream->props.u.isoc.framesperurb); + if (ret < 0) + return ret; + + return usb_urb_alloc_isoc_urbs(stream); default: err("unknown URB-type for data transfer."); return -EINVAL; @@ -255,19 +342,8 @@ int usb_urb_init(struct usb_data_stream *stream, int usb_urb_exit(struct usb_data_stream *stream) { - int i; - - usb_urb_kill(stream); - - for (i = 0; i < stream->urbs_initialized; i++) { - if (stream->urb_list[i] != NULL) { - deb_mem("freeing URB no. %d.\n", i); - /* free the URBs */ - usb_free_urb(stream->urb_list[i]); - } - } - stream->urbs_initialized = 0; - + usb_urb_free_urbs(stream); usb_free_stream_buffers(stream); + return 0; } From 15072bba796d5b0039ccaa86aba0d5632c58c9b4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 28 May 2012 18:23:17 -0300 Subject: [PATCH 0222/5375] [media] dvb_usb_v2: usb_urb.c use dynamic debugs Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/usb_urb.c | 42 +++++++++++++++-------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c index 8792334642a2..bf987c09b0cd 100644 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -37,7 +37,8 @@ static void usb_urb_complete(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - deb_ts("urb completition error %d.\n", urb->status); + pr_debug("%s: URB completition failed=%d\n", __func__, + urb->status); break; } @@ -46,9 +47,9 @@ static void usb_urb_complete(struct urb *urb) case PIPE_ISOCHRONOUS: for (i = 0; i < urb->number_of_packets; i++) { if (urb->iso_frame_desc[i].status != 0) - deb_ts("iso frame descriptor has an" \ - " error: %d\n", - urb->iso_frame_desc[i].status); + pr_debug("%s: iso frame descriptor has an" \ + " error=%d\n", __func__, + urb->iso_frame_desc[i].status); else if (urb->iso_frame_desc[i].actual_length > 0) stream->complete(stream, b + urb->iso_frame_desc[i].offset, @@ -74,8 +75,7 @@ int usb_urb_kill(struct usb_data_stream *stream) { int i; for (i = 0; i < stream->urbs_submitted; i++) { - deb_ts("killing URB no. %d.\n", i); - + pr_debug("%s: kill URB=%d\n", __func__, i); /* stop the URB */ usb_kill_urb(stream->urb_list[i]); } @@ -95,7 +95,7 @@ int usb_urb_submit(struct usb_data_stream *stream, } for (i = 0; i < stream->urbs_initialized; i++) { - deb_ts("submitting URB no. %d\n", i); + pr_debug("%s: submit URB=%d\n", __func__, i); ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); if (ret) { err("could not submit URB no. %d - get them all back", @@ -116,7 +116,6 @@ int usb_urb_free_urbs(struct usb_data_stream *stream) for (i = 0; i < stream->urbs_initialized; i++) { if (stream->urb_list[i] != NULL) { - deb_mem("freeing URB no. %d.\n", i); pr_debug("%s: free URB=%d\n", __func__, i); /* free the URBs */ usb_free_urb(stream->urb_list[i]); @@ -136,7 +135,7 @@ static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream) pr_debug("%s: alloc URB=%d\n", __func__, i); stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); if (!stream->urb_list[i]) { - deb_mem("not enough memory for urb_alloc_urb!.\n"); + pr_debug("%s: failed\n", __func__); for (j = 0; j < i; j++) usb_free_urb(stream->urb_list[j]); return -ENOMEM; @@ -168,7 +167,7 @@ static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) stream->urb_list[i] = usb_alloc_urb( stream->props.u.isoc.framesperurb, GFP_ATOMIC); if (!stream->urb_list[i]) { - deb_mem("not enough memory for urb_alloc_urb!\n"); + pr_debug("%s: failed\n", __func__); for (j = 0; j < i; j++) usb_free_urb(stream->urb_list[j]); return -ENOMEM; @@ -206,7 +205,8 @@ int usb_free_stream_buffers(struct usb_data_stream *stream) if (stream->state & USB_STATE_URB_BUF) { while (stream->buf_num) { stream->buf_num--; - deb_mem("freeing buffer %d\n", stream->buf_num); + pr_debug("%s: free buf=%d\n", __func__, + stream->buf_num); usb_free_coherent(stream->udev, stream->buf_size, stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]); @@ -224,27 +224,27 @@ int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, stream->buf_num = 0; stream->buf_size = size; - deb_mem("all in all I will use %lu bytes for streaming\n", num * size); + pr_debug("%s: all in all I will use %lu bytes for streaming\n", + __func__, num * size); for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { - deb_mem("allocating buffer %d\n", stream->buf_num); + pr_debug("%s: alloc buf=%d\n", __func__, stream->buf_num); stream->buf_list[stream->buf_num] = usb_alloc_coherent( stream->udev, size, GFP_ATOMIC, &stream->dma_addr[stream->buf_num]); if (stream->buf_list[stream->buf_num] == NULL) { - deb_mem("not enough memory for urb-buffer" \ - " allocation.\n"); + pr_debug("%s: failed\n", __func__); usb_free_stream_buffers(stream); return -ENOMEM; } - deb_mem("buffer %d: %p (dma: %llu)\n", + + pr_debug("%s: buf %d: %p (dma %llu)\n", __func__, stream->buf_num, stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); memset(stream->buf_list[stream->buf_num], 0, size); stream->state |= USB_STATE_URB_BUF; } - deb_mem("allocation successful\n"); return 0; } @@ -258,12 +258,14 @@ int usb_urb_reconfig(struct usb_data_stream *stream, return 0; /* check allocated buffers are large enough for the request */ - if (props->type == USB_BULK) + if (props->type == USB_BULK) { buf_size = stream->props.u.bulk.buffersize; - else if (props->type == USB_ISOC) + } else if (props->type == USB_ISOC) { buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb; - else + } else { + err("invalid endpoint type=%d", props->type); return -EINVAL; + } if (stream->buf_num < props->count || stream->buf_size < buf_size) { err("cannot reconfigure as allocated buffers are too small"); From 39831f094fb703412c23a1178d28e1d8d1aa4d18 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 28 May 2012 21:28:01 -0300 Subject: [PATCH 0223/5375] [media] dvb_usb_v2: add .get_usb_stream_config() New callback to resolve current USB stream configuration. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 2 ++ drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 16 +++++++++++++++- drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 17 ++++++++++++++--- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 0715e72259f6..49df6fbeb1ad 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -240,6 +240,8 @@ struct dvb_usb_device_properties { int (*identify_state) (struct dvb_usb_device *); int (*init) (struct dvb_usb_device *); int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *); + int (*get_usb_stream_config) (struct dvb_frontend *, + struct usb_data_stream_properties *); struct i2c_algorithm *i2c_algo; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index fd02be30b532..9ada473773d5 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -56,8 +56,22 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) * for reception. */ if (adap->feedcount == onoff && adap->feedcount > 0) { + struct usb_data_stream_properties stream_props; + + /* resolve USB stream configuration */ + if (adap->dev->props.get_usb_stream_config) { + ret = adap->dev->props.get_usb_stream_config( + adap->fe_adap[adap->active_fe].fe, + &stream_props); + if (ret < 0) + return ret; + } else { + stream_props = adap->props.fe[adap->active_fe].stream; + } + deb_ts("submitting all URBs\n"); - usb_urb_submit(&adap->fe_adap[adap->active_fe].stream, NULL); + usb_urb_submit(&adap->fe_adap[adap->active_fe].stream, + &stream_props); deb_ts("controlling pid parser\n"); if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index 8c98924a625a..903f77afb142 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -94,8 +94,9 @@ static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) { int i, ret = 0; - for (i = 0; i < adap->props.num_frontends; i++) { + struct usb_data_stream_properties stream_props; + for (i = 0; i < adap->props.num_frontends; i++) { adap->fe_adap[i].stream.udev = adap->dev->udev; if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) adap->fe_adap[i].stream.complete = @@ -107,8 +108,18 @@ int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) else adap->fe_adap[i].stream.complete = dvb_usb_data_complete; adap->fe_adap[i].stream.user_priv = adap; - ret = usb_urb_init(&adap->fe_adap[i].stream, - &adap->props.fe[i].stream); + + /* resolve USB stream configuration */ + if (adap->dev->props.get_usb_stream_config) { + ret = adap->dev->props.get_usb_stream_config(NULL, + &stream_props); + if (ret < 0) + break; + } else { + stream_props = adap->props.fe[i].stream; + } + + ret = usb_urb_init(&adap->fe_adap[i].stream, &stream_props); if (ret < 0) break; } From 3256cdef6ea09776e587b23240b74ead733fb11c Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 28 May 2012 21:34:15 -0300 Subject: [PATCH 0224/5375] [media] dvb_usb_v2: move (struct usb_data_stream) to one level up Move stream from the frontend to adapter. There could be only one stream per adapter. One adapter can has multiple frontends but only one can stream at the time. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 3 +- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 5 +-- drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 52 ++++++++++++------------- 3 files changed, 27 insertions(+), 33 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 49df6fbeb1ad..08d148b23c71 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -314,8 +314,6 @@ struct dvb_usb_fe_adapter { int (*fe_init) (struct dvb_frontend *); int (*fe_sleep) (struct dvb_frontend *); - struct usb_data_stream stream; - int pid_filtering; int max_feed_count; @@ -325,6 +323,7 @@ struct dvb_usb_fe_adapter { struct dvb_usb_adapter { struct dvb_usb_device *dev; struct dvb_usb_adapter_properties props; + struct usb_data_stream stream; #define DVB_USB_ADAP_STATE_INIT 0x000 #define DVB_USB_ADAP_STATE_DVB 0x001 diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 9ada473773d5..841b2d9a4058 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -27,7 +27,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) /* stop feed before setting a new pid if there will be no pid anymore */ if (newfeedcount == 0) { deb_ts("stop feeding\n"); - usb_urb_kill(&adap->fe_adap[adap->active_fe].stream); + usb_urb_kill(&adap->stream); if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { ret = adap->props.fe[adap->active_fe].streaming_ctrl( @@ -70,8 +70,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } deb_ts("submitting all URBs\n"); - usb_urb_submit(&adap->fe_adap[adap->active_fe].stream, - &stream_props); + usb_urb_submit(&adap->stream, &stream_props); deb_ts("controlling pid parser\n"); if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index 903f77afb142..8200e0983f07 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -93,43 +93,39 @@ static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) { - int i, ret = 0; + int ret; struct usb_data_stream_properties stream_props; - for (i = 0; i < adap->props.num_frontends; i++) { - adap->fe_adap[i].stream.udev = adap->dev->udev; - if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) - adap->fe_adap[i].stream.complete = - dvb_usb_data_complete_204; - else - if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD) - adap->fe_adap[i].stream.complete = - dvb_usb_data_complete_raw; - else - adap->fe_adap[i].stream.complete = dvb_usb_data_complete; - adap->fe_adap[i].stream.user_priv = adap; + /* + * FIXME: We should config demux callback for each time streaming is + * started. Same for the USB data stream config. + */ - /* resolve USB stream configuration */ - if (adap->dev->props.get_usb_stream_config) { - ret = adap->dev->props.get_usb_stream_config(NULL, - &stream_props); - if (ret < 0) - break; - } else { - stream_props = adap->props.fe[i].stream; - } + adap->stream.udev = adap->dev->udev; + if (adap->props.fe[0].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) + adap->stream.complete = dvb_usb_data_complete_204; + else if (adap->props.fe[0].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD) + adap->stream.complete = dvb_usb_data_complete_raw; + else + adap->stream.complete = dvb_usb_data_complete; - ret = usb_urb_init(&adap->fe_adap[i].stream, &stream_props); + adap->stream.user_priv = adap; + + /* resolve USB stream configuration */ + if (adap->dev->props.get_usb_stream_config) { + ret = adap->dev->props.get_usb_stream_config(NULL, + &stream_props); if (ret < 0) - break; + return ret; + } else { + stream_props = adap->props.fe[0].stream; } - return ret; + + return usb_urb_init(&adap->stream, &stream_props); } int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) { - int i; - for (i = 0; i < adap->props.num_frontends; i++) - usb_urb_exit(&adap->fe_adap[i].stream); + usb_urb_exit(&adap->stream); return 0; } From b6ecf8bb4e0fbda10f41770187e2120c282770f4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 29 May 2012 12:17:20 -0300 Subject: [PATCH 0225/5375] [media] dvb_usb_v2: add .get_ts_config() callback Add new callback in order to resolve used TS (MPEG transport stream) configuration. Normal TS is 188 byte payload only but there is currently 204 byte TS and raw TS supported too. Traditionally TS type was mapped as a frontend property but it does not work no longer after we changed from MFE (multi-frontend) to SFE (single-frontend). So it is not possible to map TS for the given FE as there could be only one FE instead of multiple. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 1 + drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 73 +++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 63 --------------------- 3 files changed, 74 insertions(+), 63 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 08d148b23c71..51cb388f928c 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -242,6 +242,7 @@ struct dvb_usb_device_properties { int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *); int (*get_usb_stream_config) (struct dvb_frontend *, struct usb_data_stream_properties *); + int (*get_ts_config) (struct dvb_frontend *, unsigned int *); struct i2c_algorithm *i2c_algo; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 841b2d9a4058..f196c0dc420e 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -8,6 +8,60 @@ */ #include "dvb_usb_common.h" +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, + size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter(&adap->demux, buffer, length); +} + +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, + u8 *buffer, size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter_204(&adap->demux, buffer, length); +} + +static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, + u8 *buffer, size_t length) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) + dvb_dmx_swfilter_raw(&adap->demux, buffer, length); +} + +int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) +{ + int ret; + struct usb_data_stream_properties stream_props; + + adap->stream.udev = adap->dev->udev; + adap->stream.user_priv = adap; + + /* resolve USB stream configuration for buffer alloc */ + if (adap->dev->props.get_usb_stream_config) { + ret = adap->dev->props.get_usb_stream_config(NULL, + &stream_props); + if (ret < 0) + return ret; + } else { + stream_props = adap->props.fe[0].stream; + } + + /* FIXME: can be removed as set later in anyway */ + adap->stream.complete = dvb_usb_data_complete; + + return usb_urb_init(&adap->stream, &stream_props); +} + +int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) +{ + usb_urb_exit(&adap->stream); + return 0; +} + /* does the complete input transfer handling */ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) { @@ -57,6 +111,25 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) */ if (adap->feedcount == onoff && adap->feedcount > 0) { struct usb_data_stream_properties stream_props; + unsigned int ts_props; + + /* resolve TS configuration */ + if (adap->dev->props.get_ts_config) { + ret = adap->dev->props.get_ts_config( + adap->fe_adap[adap->active_fe].fe, + &ts_props); + if (ret < 0) + return ret; + } else { + ts_props = 0; /* normal 188 payload only TS */ + } + + if (ts_props & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) + adap->stream.complete = dvb_usb_data_complete_204; + else if (ts_props & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD) + adap->stream.complete = dvb_usb_data_complete_raw; + else + adap->stream.complete = dvb_usb_data_complete; /* resolve USB stream configuration */ if (adap->dev->props.get_usb_stream_config) { diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index 8200e0983f07..43563b341b80 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -66,66 +66,3 @@ int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) return dvb_usbv2_generic_rw(d, buf, len, NULL, 0, 0); } EXPORT_SYMBOL(dvb_usbv2_generic_write); - -static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, - size_t length) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) - dvb_dmx_swfilter(&adap->demux, buffer, length); -} - -static void dvb_usb_data_complete_204(struct usb_data_stream *stream, - u8 *buffer, size_t length) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) - dvb_dmx_swfilter_204(&adap->demux, buffer, length); -} - -static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, - u8 *buffer, size_t length) -{ - struct dvb_usb_adapter *adap = stream->user_priv; - if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) - dvb_dmx_swfilter_raw(&adap->demux, buffer, length); -} - -int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) -{ - int ret; - struct usb_data_stream_properties stream_props; - - /* - * FIXME: We should config demux callback for each time streaming is - * started. Same for the USB data stream config. - */ - - adap->stream.udev = adap->dev->udev; - if (adap->props.fe[0].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) - adap->stream.complete = dvb_usb_data_complete_204; - else if (adap->props.fe[0].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD) - adap->stream.complete = dvb_usb_data_complete_raw; - else - adap->stream.complete = dvb_usb_data_complete; - - adap->stream.user_priv = adap; - - /* resolve USB stream configuration */ - if (adap->dev->props.get_usb_stream_config) { - ret = adap->dev->props.get_usb_stream_config(NULL, - &stream_props); - if (ret < 0) - return ret; - } else { - stream_props = adap->props.fe[0].stream; - } - - return usb_urb_init(&adap->stream, &stream_props); -} - -int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) -{ - usb_urb_exit(&adap->stream); - return 0; -} From 3024985d15bdf5e8a55468a35c86ed9fa8c3eec5 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 29 May 2012 16:12:17 -0300 Subject: [PATCH 0226/5375] [media] dvb_usb_v2: move (struct usb_data_stream_properties) to upper level Move USB stream properties from frontend to adapter. It is property of adapter. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 3 +-- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 51cb388f928c..6ce97975bd03 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -129,8 +129,6 @@ struct dvb_usb_adapter_fe_properties { int (*frontend_attach) (struct dvb_usb_adapter *); int (*tuner_attach) (struct dvb_usb_adapter *); - struct usb_data_stream_properties stream; - int size_of_priv; }; @@ -144,6 +142,7 @@ struct dvb_usb_adapter_properties { int num_frontends; struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP]; + struct usb_data_stream_properties stream; }; /** diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index f196c0dc420e..7fcbcc3e5b7f 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -47,7 +47,7 @@ int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) if (ret < 0) return ret; } else { - stream_props = adap->props.fe[0].stream; + stream_props = adap->props.stream; } /* FIXME: can be removed as set later in anyway */ @@ -139,7 +139,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) if (ret < 0) return ret; } else { - stream_props = adap->props.fe[adap->active_fe].stream; + stream_props = adap->props.stream; } deb_ts("submitting all URBs\n"); From e46c5b66da84d8eccf4566216f0582964a28b73e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 29 May 2012 18:05:40 -0300 Subject: [PATCH 0227/5375] [media] dvb_usb_v2: move PID filters from frontend to adapter Filtering given PIDs from the transport stream is done by the DVB USB bridge. It is highly possible there is limitations what kind of stream DVB USB bridge can PID filter, but it still does not make sense to define filters for each frontend as frontend could offer different stream types for different standards. Likely new way is to enable / disable PID filters are needed to make decision at runtime (callback). PID filters are quite legacy stuff as those are aimed cut stream smaller to fit for the USB1.1... Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 33 +++++------ drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 26 ++++----- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 74 +++++++++--------------- 3 files changed, 55 insertions(+), 78 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 6ce97975bd03..ee6df793ce1b 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -114,17 +114,7 @@ struct usb_data_stream_properties { * @stream: configuration of the USB streaming */ struct dvb_usb_adapter_fe_properties { -#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 -#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 -#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 -#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 -#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD 0x10 - int caps; - int pid_filter_count; - int (*streaming_ctrl) (struct dvb_usb_adapter *, int); - int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); - int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); int (*frontend_attach) (struct dvb_usb_adapter *); int (*tuner_attach) (struct dvb_usb_adapter *); @@ -134,8 +124,18 @@ struct dvb_usb_adapter_fe_properties { #define MAX_NO_OF_FE_PER_ADAP 3 struct dvb_usb_adapter_properties { +#define DVB_USB_ADAP_HAS_PID_FILTER 0x01 +#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 +#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 +#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 +#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD 0x10 + int caps; int size_of_priv; + int pid_filter_count; + int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); + int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); + int (*frontend_ctrl) (struct dvb_frontend *, int); int (*fe_ioctl_override) (struct dvb_frontend *, unsigned int, void *, unsigned int); @@ -314,24 +314,21 @@ struct dvb_usb_fe_adapter { int (*fe_init) (struct dvb_frontend *); int (*fe_sleep) (struct dvb_frontend *); - int pid_filtering; - int max_feed_count; - void *priv; }; struct dvb_usb_adapter { - struct dvb_usb_device *dev; - struct dvb_usb_adapter_properties props; - struct usb_data_stream stream; - #define DVB_USB_ADAP_STATE_INIT 0x000 #define DVB_USB_ADAP_STATE_DVB 0x001 int state; - + struct dvb_usb_device *dev; + struct dvb_usb_adapter_properties props; + struct usb_data_stream stream; u8 id; + int pid_filtering; int feedcount; + int max_feed_count; /* dvb */ struct dvb_adapter dvb_adap; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 7fcbcc3e5b7f..980a1d30a2cb 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -97,14 +97,14 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) /* activate the pid on the device specific pid_filter */ deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n", - adap->fe_adap[adap->active_fe].pid_filtering ? + adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid, dvbdmxfeed->index, onoff ? "on" : "off"); - if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->fe_adap[adap->active_fe].pid_filtering && - adap->props.fe[adap->active_fe].pid_filter != NULL) - adap->props.fe[adap->active_fe].pid_filter(adap, - dvbdmxfeed->index, dvbdmxfeed->pid, onoff); + if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->pid_filtering && + adap->props.pid_filter != NULL) + adap->props.pid_filter(adap, dvbdmxfeed->index, + dvbdmxfeed->pid, onoff); /* start the feed if this was the first feed and there is still a feed * for reception. @@ -146,13 +146,13 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) usb_urb_submit(&adap->stream, &stream_props); deb_ts("controlling pid parser\n"); - if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->props.fe[adap->active_fe].caps & + if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props.caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && - adap->props.fe[adap->active_fe].pid_filter_ctrl != NULL) { - ret = adap->props.fe[adap->active_fe].pid_filter_ctrl( + adap->props.pid_filter_ctrl != NULL) { + ret = adap->props.pid_filter_ctrl( adap, - adap->fe_adap[adap->active_fe].pid_filtering); + adap->pid_filtering); if (ret < 0) { err("could not handle pid_parser"); return ret; @@ -214,8 +214,8 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->demux.filternum = 0; for (i = 0; i < adap->props.num_frontends; i++) { - if (adap->demux.filternum < adap->fe_adap[i].max_feed_count) - adap->demux.filternum = adap->fe_adap[i].max_feed_count; + if (adap->demux.filternum < adap->max_feed_count) + adap->demux.filternum = adap->max_feed_count; } adap->demux.feednum = adap->demux.filternum; adap->demux.start_feed = dvb_usb_start_feed; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 1441324a9115..0e26299c19ca 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -34,7 +34,7 @@ MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a" \ static int dvb_usb_adapter_init(struct dvb_usb_device *d) { struct dvb_usb_adapter *adap; - int ret, n, o, adapter_count; + int ret, n, adapter_count; /* resolve adapter count */ adapter_count = d->props.num_adapters; @@ -54,57 +54,37 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d) memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties)); - for (o = 0; o < adap->props.num_frontends; o++) { - struct dvb_usb_adapter_fe_properties *props = - &adap->props.fe[o]; - /* speed - when running at FULL speed we need a HW - * PID filter */ - if (d->udev->speed == USB_SPEED_FULL && - !(props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { - err("This USB2.0 device cannot be run on a" \ - " USB1.1 port. (it lacks a" \ - " hardware PID filter)"); - return -ENODEV; - } + /* speed - when running at FULL speed we need a HW PID filter */ + if (d->udev->speed == USB_SPEED_FULL && + !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) { + err("This USB2.0 device cannot be run on a" \ + " USB1.1 port. (it lacks a" \ + " hardware PID filter)"); + return -ENODEV; + } else if ((d->udev->speed == USB_SPEED_FULL && + adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) || + (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { + info("will use the device's hardware PID" \ + " filter (table count: %d).", + adap->props.pid_filter_count); + adap->pid_filtering = 1; + adap->max_feed_count = adap->props.pid_filter_count; + } else { + info("will pass the complete MPEG2 transport" \ + " stream to the software demuxer."); + adap->pid_filtering = 0; + adap->max_feed_count = 255; + } - if ((d->udev->speed == USB_SPEED_FULL && - props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || - (props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { - info("will use the device's hardware PID" \ - " filter (table count: %d).", - props->pid_filter_count); - adap->fe_adap[o].pid_filtering = 1; - adap->fe_adap[o].max_feed_count = - props->pid_filter_count; - } else { - info("will pass the complete MPEG2 transport" \ - " stream to the software demuxer."); - adap->fe_adap[o].pid_filtering = 0; - adap->fe_adap[o].max_feed_count = 255; - } - - if (!adap->fe_adap[o].pid_filtering && - dvb_usb_force_pid_filter_usage && - props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { + if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && + adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) { info("pid filter enabled by module option."); - adap->fe_adap[o].pid_filtering = 1; - adap->fe_adap[o].max_feed_count = - props->pid_filter_count; - } - - if (props->size_of_priv > 0) { - adap->fe_adap[o].priv = kzalloc(props->size_of_priv, GFP_KERNEL); - if (adap->fe_adap[o].priv == NULL) { - err("no memory for priv for adapter" \ - " %d fe %d.", n, o); - return -ENOMEM; - } - } + adap->pid_filtering = 1; + adap->max_feed_count = adap->props.pid_filter_count; } if (adap->props.size_of_priv > 0) { - adap->priv = kzalloc(adap->props.size_of_priv, - GFP_KERNEL); + adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL); if (adap->priv == NULL) { err("no memory for priv for adapter %d.", n); return -ENOMEM; From fec88df01dc1045579aa56379fa962f9f9fd8542 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 29 May 2012 20:30:05 -0300 Subject: [PATCH 0228/5375] [media] dvb_usb_v2: move 3 callbacks from the frontend to adapter Move .frontend_attach(), .tuner_attach() and .streaming_ctrl() from the frontend to adapter. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 12 +++++------- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 18 ++++++++---------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index ee6df793ce1b..6bab17b3e808 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -114,11 +114,6 @@ struct usb_data_stream_properties { * @stream: configuration of the USB streaming */ struct dvb_usb_adapter_fe_properties { - int (*streaming_ctrl) (struct dvb_usb_adapter *, int); - - int (*frontend_attach) (struct dvb_usb_adapter *); - int (*tuner_attach) (struct dvb_usb_adapter *); - int size_of_priv; }; @@ -136,9 +131,12 @@ struct dvb_usb_adapter_properties { int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); - int (*frontend_ctrl) (struct dvb_frontend *, int); + int (*frontend_attach) (struct dvb_usb_adapter *); + int (*tuner_attach) (struct dvb_usb_adapter *); + int (*frontend_ctrl) (struct dvb_frontend *, int); + int (*streaming_ctrl) (struct dvb_usb_adapter *, int); int (*fe_ioctl_override) (struct dvb_frontend *, - unsigned int, void *, unsigned int); + unsigned int, void *, unsigned int); int num_frontends; struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP]; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 980a1d30a2cb..9361598c6fdd 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -83,9 +83,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) deb_ts("stop feeding\n"); usb_urb_kill(&adap->stream); - if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { - ret = adap->props.fe[adap->active_fe].streaming_ctrl( - adap, 0); + if (adap->props.streaming_ctrl != NULL) { + ret = adap->props.streaming_ctrl(adap, 0); if (ret < 0) { err("error while stopping stream."); return ret; @@ -159,9 +158,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } } deb_ts("start feeding\n"); - if (adap->props.fe[adap->active_fe].streaming_ctrl != NULL) { - ret = adap->props.fe[adap->active_fe].streaming_ctrl( - adap, 1); + if (adap->props.streaming_ctrl != NULL) { + ret = adap->props.streaming_ctrl(adap, 1); if (ret < 0) { err("error while enabling fifo."); return ret; @@ -319,7 +317,7 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) /* register all given adapter frontends */ for (i = 0; i < adap->props.num_frontends; i++) { - if (adap->props.fe[i].frontend_attach == NULL) { + if (adap->props.frontend_attach == NULL) { err("strange: '%s' #%d,%d " \ "doesn't want to attach a frontend.", adap->dev->name, adap->id, i); @@ -327,7 +325,7 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) return 0; } - ret = adap->props.fe[i].frontend_attach(adap); + ret = adap->props.frontend_attach(adap); if (ret || adap->fe_adap[i].fe == NULL) { /* only print error when there is no FE at all */ if (i == 0) @@ -359,8 +357,8 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) } /* only attach the tuner if the demod is there */ - if (adap->props.fe[i].tuner_attach != NULL) - adap->props.fe[i].tuner_attach(adap); + if (adap->props.tuner_attach != NULL) + adap->props.tuner_attach(adap); adap->num_frontends_initialized++; } From 20bb9cc483e1dc78ce7c52e364c157dca8a54c60 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 29 May 2012 22:20:24 -0300 Subject: [PATCH 0229/5375] [media] dvb_usb_v2: get rid of (struct dvb_usb_adapter_fe_properties) Get rid of (struct dvb_usb_adapter_fe_properties) as we no longer need it. Frontends are now defined as a array of pointers inside adapter struct. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 18 ++--- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 90 +++++++++++++----------- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 2 +- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 6bab17b3e808..56f72f6079bd 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -113,9 +113,6 @@ struct usb_data_stream_properties { * pll_desc and pll_init_buf of struct dvb_usb_device). * @stream: configuration of the USB streaming */ -struct dvb_usb_adapter_fe_properties { - int size_of_priv; -}; #define MAX_NO_OF_FE_PER_ADAP 3 struct dvb_usb_adapter_properties { @@ -139,7 +136,6 @@ struct dvb_usb_adapter_properties { unsigned int, void *, unsigned int); int num_frontends; - struct dvb_usb_adapter_fe_properties fe[MAX_NO_OF_FE_PER_ADAP]; struct usb_data_stream_properties stream; }; @@ -306,15 +302,6 @@ struct usb_data_stream { * * @stream: the usb data stream. */ -struct dvb_usb_fe_adapter { - struct dvb_frontend *fe; - - int (*fe_init) (struct dvb_frontend *); - int (*fe_sleep) (struct dvb_frontend *); - - void *priv; -}; - struct dvb_usb_adapter { #define DVB_USB_ADAP_STATE_INIT 0x000 #define DVB_USB_ADAP_STATE_DVB 0x001 @@ -334,7 +321,10 @@ struct dvb_usb_adapter { struct dvb_demux demux; struct dvb_net dvb_net; - struct dvb_usb_fe_adapter fe_adap[MAX_NO_OF_FE_PER_ADAP]; + struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP]; + int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); + int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); + int active_fe; int num_frontends_initialized; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 9361598c6fdd..bc6abfe04579 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -115,7 +115,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) /* resolve TS configuration */ if (adap->dev->props.get_ts_config) { ret = adap->dev->props.get_ts_config( - adap->fe_adap[adap->active_fe].fe, + adap->fe[adap->active_fe], &ts_props); if (ret < 0) return ret; @@ -133,7 +133,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) /* resolve USB stream configuration */ if (adap->dev->props.get_usb_stream_config) { ret = adap->dev->props.get_usb_stream_config( - adap->fe_adap[adap->active_fe].fe, + adap->fe[adap->active_fe], &stream_props); if (ret < 0) return ret; @@ -292,8 +292,8 @@ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) dvb_usb_set_active_fe(fe, 1); - if (adap->fe_adap[fe->id].fe_init) - adap->fe_adap[fe->id].fe_init(fe); + if (adap->fe_init[fe->id]) + adap->fe_init[fe->id](fe); return 0; } @@ -302,8 +302,8 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) { struct dvb_usb_adapter *adap = fe->dvb->priv; - if (adap->fe_adap[fe->id].fe_sleep) - adap->fe_adap[fe->id].fe_sleep(fe); + if (adap->fe_sleep[fe->id]) + adap->fe_sleep[fe->id](fe); dvb_usb_set_active_fe(fe, 0); @@ -314,56 +314,66 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) { int ret, i; - /* register all given adapter frontends */ - for (i = 0; i < adap->props.num_frontends; i++) { + memset(adap->fe, 0, sizeof(adap->fe)); - if (adap->props.frontend_attach == NULL) { - err("strange: '%s' #%d,%d " \ - "doesn't want to attach a frontend.", - adap->dev->name, adap->id, i); + adap->active_fe = 0; - return 0; - } + if (adap->props.frontend_attach == NULL) { + err("strange: '%s' doesn't want to attach a frontend.", + adap->dev->name); + ret = 0; + goto err; + } - ret = adap->props.frontend_attach(adap); - if (ret || adap->fe_adap[i].fe == NULL) { - /* only print error when there is no FE at all */ - if (i == 0) - err("no frontend was attached by '%s'", - adap->dev->name); + /* attach all given adapter frontends */ + ret = adap->props.frontend_attach(adap); + if (ret < 0) + goto err; - return 0; - } + if (adap->fe[0] == NULL) { + err("no frontend was attached by '%s'", adap->dev->name); + goto err; + } - adap->fe_adap[i].fe->id = i; + for (i = 0; i < MAX_NO_OF_FE_PER_ADAP; i++) { + if (adap->fe[i] == NULL) + break; + + adap->fe[i]->id = i; /* re-assign sleep and wakeup functions */ - adap->fe_adap[i].fe_init = adap->fe_adap[i].fe->ops.init; - adap->fe_adap[i].fe->ops.init = dvb_usb_fe_wakeup; - adap->fe_adap[i].fe_sleep = adap->fe_adap[i].fe->ops.sleep; - adap->fe_adap[i].fe->ops.sleep = dvb_usb_fe_sleep; + adap->fe_init[i] = adap->fe[i]->ops.init; + adap->fe[i]->ops.init = dvb_usb_fe_wakeup; + adap->fe_sleep[i] = adap->fe[i]->ops.sleep; + adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; - if (dvb_register_frontend(&adap->dvb_adap, - adap->fe_adap[i].fe)) { + ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); + if (ret < 0) { err("Frontend %d registration failed.", i); - dvb_frontend_detach(adap->fe_adap[i].fe); - adap->fe_adap[i].fe = NULL; + dvb_frontend_detach(adap->fe[i]); + adap->fe[i] = NULL; /* In error case, do not try register more FEs, * still leaving already registered FEs alive. */ if (i == 0) - return -ENODEV; + goto err; else - return 0; + break; } - /* only attach the tuner if the demod is there */ - if (adap->props.tuner_attach != NULL) - adap->props.tuner_attach(adap); - adap->num_frontends_initialized++; } + /* attach all given adapter tuners */ + if (adap->props.tuner_attach) { + ret = adap->props.tuner_attach(adap); + if (ret < 0) + err("tuner attach failed - will continue"); + } + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; } int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) @@ -372,9 +382,9 @@ int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) /* unregister all given adapter frontends */ for (; i >= 0; i--) { - if (adap->fe_adap[i].fe != NULL) { - dvb_unregister_frontend(adap->fe_adap[i].fe); - dvb_frontend_detach(adap->fe_adap[i].fe); + if (adap->fe[i] != NULL) { + dvb_unregister_frontend(adap->fe[i]); + dvb_frontend_detach(adap->fe[i]); } } adap->num_frontends_initialized = 0; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 0e26299c19ca..61ec808dd6d9 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -104,7 +104,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d) return ret; /* use exclusive FE lock if there is multiple shared FEs */ - if (adap->fe_adap[1].fe) + if (adap->fe[1]) adap->dvb_adap.mfe_shared = 1; d->num_adapters_initialized++; From 1c9c73b7db1c74f0e9b8ea4755187d801f878651 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 1 Jun 2012 19:53:14 -0300 Subject: [PATCH 0230/5375] [media] dvb_usb_v2: remove .num_frontends It is no longer needed because all frontends are attached as a one go. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 1 - drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 56f72f6079bd..c6144bb9b82d 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -135,7 +135,6 @@ struct dvb_usb_adapter_properties { int (*fe_ioctl_override) (struct dvb_frontend *, unsigned int, void *, unsigned int); - int num_frontends; struct usb_data_stream_properties stream; }; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index bc6abfe04579..095cac5ee0b1 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -186,7 +186,6 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) { - int i; int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->name, adap->dev->props.owner, &adap->dev->udev->dev, @@ -211,10 +210,8 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->demux.priv = adap; adap->demux.filternum = 0; - for (i = 0; i < adap->props.num_frontends; i++) { - if (adap->demux.filternum < adap->max_feed_count) - adap->demux.filternum = adap->max_feed_count; - } + if (adap->demux.filternum < adap->max_feed_count) + adap->demux.filternum = adap->max_feed_count; adap->demux.feednum = adap->demux.filternum; adap->demux.start_feed = dvb_usb_start_feed; adap->demux.stop_feed = dvb_usb_stop_feed; From 21f5a32e1f0a4ae086e4985d4a949e7289440c3a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 3 Jun 2012 15:49:45 -0300 Subject: [PATCH 0231/5375] [media] dvb_usb_v2: delay firmware download as it blocks module init Delay firmware download and whole driver initialization using workqueue. udev causes problems when blocking firmware download was done during module init. This will likely resolve all DVB USB firmware downloading issues we have had during recent years. Fixes bug in case of DVB USB driver: https://bugzilla.redhat.com/show_bug.cgi?id=827538 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 77 +++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 61ec808dd6d9..561ceb69144f 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -217,7 +217,7 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) /* * USB */ -int dvb_usbv2_device_init(struct usb_interface *intf, +int dvb_usbv2_device_init_(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); @@ -295,12 +295,85 @@ err_kfree: return ret; } + +/* + * udev, which is used for the firmware downloading, requires we cannot + * block during module_init(). module_init() calls USB probe() which + * is this routine. Due to that we delay actual operation using workqueue + * and return always success here. + */ + +struct dvb_usb_delayed_init { + struct usb_interface *intf; + const struct usb_device_id *id; + struct work_struct work; +}; + +static void dvb_usbv2_init_work(struct work_struct *work) +{ + int ret; + struct dvb_usb_delayed_init *delayed_init = + container_of(work, struct dvb_usb_delayed_init, work); + + ret = dvb_usbv2_device_init_(delayed_init->intf, delayed_init->id); + if (ret < 0) { + usb_driver_release_interface( + to_usb_driver(delayed_init->intf->dev.driver), + delayed_init->intf); + kfree(delayed_init); + goto err; + } + + kfree(delayed_init); + + return; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return; +} + +int dvb_usbv2_device_init(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret; + struct dvb_usb_delayed_init *delayed_init; + + delayed_init = kzalloc(sizeof(struct dvb_usb_delayed_init), GFP_KERNEL); + if (!delayed_init) { + pr_err("%s: kzalloc() failed", DVB_USB_LOG_PREFIX); + ret = -ENOMEM; + goto err; + } + + delayed_init->intf = intf; + delayed_init->id = id; + INIT_WORK(&delayed_init->work, dvb_usbv2_init_work); + + ret = schedule_work(&delayed_init->work); + if (ret < 0) { + pr_err("%s: schedule_work() failed", DVB_USB_LOG_PREFIX); + goto err_kfree; + } + + return 0; +err_kfree: + kfree(delayed_init); +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + EXPORT_SYMBOL(dvb_usbv2_device_init); void dvb_usbv2_device_exit(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name = NULL; + const char *name = "generic DVB-USB module"; + + /* + * FIXME: we should ensure our device initialization work is finished + * until exit from this routine (cancel_work_sync?) + */ usb_set_intfdata(intf, NULL); if (d) { From a0d72d246d124096cad0b4bbce8a893e913f08a1 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 4 Jun 2012 16:36:09 -0300 Subject: [PATCH 0232/5375] [media] dvb_usb_v2: clean firmware downloading routines Remove Cypress USB-interface firmware downloading routines. That is common module and having single vendor chip routines in common module is wrong. Just move those elsewhere. Move single function out from the dvb_usb_firmware.c and remove that file. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 19 -- drivers/media/dvb/dvb-usb/dvb_usb_firmware.c | 176 ------------------- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 42 +++++ 3 files changed, 42 insertions(+), 195 deletions(-) delete mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_firmware.c diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index c6144bb9b82d..4aa5bd190aec 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -204,12 +204,6 @@ struct dvb_usb_device_properties { #define DVB_USB_IS_AN_I2C_ADAPTER 0x01 int caps; -#define DEVICE_SPECIFIC 0 -#define CYPRESS_AN2135 1 -#define CYPRESS_AN2235 2 -#define CYPRESS_FX2 3 - int usb_ctrl; - int size_of_priv; const char *firmware; @@ -398,17 +392,4 @@ extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16, int); extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16); -/* commonly used firmware download types and function */ -struct hexline { - u8 len; - u32 addr; - u8 type; - u8 data[255]; - u8 chk; -}; -extern int usbv2_cypress_load_firmware(struct usb_device *udev, - const struct firmware *fw, int type); -extern int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, - int *pos); - #endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c deleted file mode 100644 index e0b43139c0c4..000000000000 --- a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c +++ /dev/null @@ -1,176 +0,0 @@ -/* dvb-usb-firmware.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for downloading the firmware to Cypress FX 1 - * and 2 based devices. - * - * FIXME: This part does actually not belong to dvb-usb, but to the - * usb-subsystem. - */ -#include "dvb_usb_common.h" - -#include - -struct usb_cypress_controller { - int id; - /* name of the usb controller */ - const char *name; - /* needs to be restarted, when the firmware has been downloaded. */ - u16 cpu_cs_register; -}; - -static struct usb_cypress_controller cypress[] = { - { .id = DEVICE_SPECIFIC, .name = "Device specific", - .cpu_cs_register = 0 }, - { .id = CYPRESS_AN2135, .name = "Cypress AN2135", - .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_AN2235, .name = "Cypress AN2235", - .cpu_cs_register = 0x7f92 }, - { .id = CYPRESS_FX2, .name = "Cypress FX2", - .cpu_cs_register = 0xe600 }, -}; - -/* - * load a firmware packet to the device - */ -static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data, - u8 len) -{ - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); -} - -int usbv2_cypress_load_firmware(struct usb_device *udev, - const struct firmware *fw, int type) -{ - struct hexline hx; - u8 reset; - int ret, pos = 0; - - /* stop the CPU */ - reset = 1; - ret = usb_cypress_writemem(udev, cypress[type].cpu_cs_register, - &reset, 1); - if (ret != 1) - err("could not stop the USB controller CPU."); - - while ((ret = dvb_usbv2_get_hexline(fw, &hx, &pos)) > 0) { - deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n", - hx.addr, hx.len, hx.chk); - ret = usb_cypress_writemem(udev, hx.addr, hx.data, hx.len); - - if (ret != hx.len) { - err("error while transferring firmware " \ - "(transferred size: %d, block size: %d)", - ret, hx.len); - ret = -EINVAL; - break; - } - } - if (ret < 0) { - err("firmware download failed at %d with %d", pos, ret); - return ret; - } - - if (ret == 0) { - /* restart the CPU */ - reset = 0; - if (ret || usb_cypress_writemem(udev, - cypress[type].cpu_cs_register, - &reset, 1) != 1) { - err("could not restart the USB controller CPU."); - ret = -EINVAL; - } - } else - ret = -EIO; - - return ret; -} -EXPORT_SYMBOL(usbv2_cypress_load_firmware); - -int dvb_usb_download_firmware(struct dvb_usb_device *d) -{ - int ret; - const struct firmware *fw = NULL; - const char *name; - - /* resolve firmware name */ - name = d->props.firmware; - if (d->props.get_firmware_name) { - ret = d->props.get_firmware_name(d, &name); - if (ret < 0) - return ret; - } - - ret = request_firmware(&fw, name, &d->udev->dev); - if (ret != 0) { - err("did not find the firmware file. (%s) " \ - "Please see linux/Documentation/dvb/ for more" \ - " details on firmware-problems. (%d)", - name, ret); - return ret; - } - - info("downloading firmware from file '%s'", name); - - switch (d->props.usb_ctrl) { - case CYPRESS_AN2135: - case CYPRESS_AN2235: - case CYPRESS_FX2: - ret = usbv2_cypress_load_firmware(d->udev, fw, - d->props.usb_ctrl); - break; - case DEVICE_SPECIFIC: - if (d->props.download_firmware) - ret = d->props.download_firmware(d, fw); - else { - err("BUG: driver didn't specified a download_firmware" \ - "-callback, although it claims to have a" \ - " DEVICE_SPECIFIC one."); - ret = -EINVAL; - } - break; - default: - ret = -EINVAL; - break; - } - - release_firmware(fw); - return ret; -} - -int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, - int *pos) -{ - u8 *b = (u8 *) &fw->data[*pos]; - int data_offs = 4; - if (*pos >= fw->size) - return 0; - - memset(hx, 0, sizeof(struct hexline)); - - hx->len = b[0]; - - if ((*pos + hx->len + 4) >= fw->size) - return -EINVAL; - - hx->addr = b[1] | (b[2] << 8); - hx->type = b[3]; - - if (hx->type == 0x04) { - /* b[4] and b[5] are the Extended linear address record data - * field */ - hx->addr |= (b[4] << 24) | (b[5] << 16); -/* hx->len -= 2; - data_offs += 2; */ - } - memcpy(hx->data, &b[data_offs], hx->len); - hx->chk = b[hx->len + data_offs]; - - *pos += hx->len + 5; - - return *pos; -} -EXPORT_SYMBOL(dvb_usbv2_get_hexline); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 561ceb69144f..6e0903989484 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -31,6 +31,48 @@ module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a" \ " PID filter, if any (default: 0)."); +int dvb_usb_download_firmware(struct dvb_usb_device *d) +{ + int ret; + const struct firmware *fw = NULL; + const char *name; + + /* resolve firmware name */ + name = d->props.firmware; + if (d->props.get_firmware_name) { + ret = d->props.get_firmware_name(d, &name); + if (ret < 0) + return ret; + } + + if (!d->props.download_firmware) { + ret = -EINVAL; + goto err; + } + + ret = request_firmware(&fw, name, &d->udev->dev); + if (ret < 0) { + err("did not find the firmware file. (%s) " \ + "Please see linux/Documentation/dvb/ for more" \ + " details on firmware-problems. (%d)", name, ret); + goto err; + } + + info("downloading firmware from file '%s'", name); + + ret = d->props.download_firmware(d, fw); + + release_firmware(fw); + + if (ret < 0) + goto err; + + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + static int dvb_usb_adapter_init(struct dvb_usb_device *d) { struct dvb_usb_adapter *adap; From 0359b5fa9eff3c07e2c9a8993a471816f42990b7 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 4 Jun 2012 20:12:55 -0300 Subject: [PATCH 0233/5375] [media] dvb_usb_v2: add macro for filling usb_device_id table entry Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 4aa5bd190aec..e90d81f7e3d0 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -66,6 +66,16 @@ struct dvb_usb_driver_info { const struct dvb_usb_device_properties *props; }; +#define DVB_USB_DEVICE(vend, prod, props_, name_, rc) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ + .idVendor = (vend), \ + .idProduct = (prod), \ + .driver_info = (kernel_ulong_t) &((struct dvb_usb_driver_info) { \ + .props = (props_), \ + .name = (name_), \ + .rc_map = (rc), \ + }) + struct dvb_usb_device; struct dvb_usb_adapter; struct usb_data_stream; From 19ec2728d77e75b9f44188f356f5ca2f6d7ff165 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 4 Jun 2012 20:55:34 -0300 Subject: [PATCH 0234/5375] [media] dvb_usb_v2: use dynamic debugs Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 9 ----- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 40 +++++++++++----------- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 6 ++-- 3 files changed, 23 insertions(+), 32 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index 2c73829f2764..3a092053d823 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -15,19 +15,10 @@ extern int dvb_usb_debug; extern int dvb_usb_disable_rc_polling; -#define deb_info(args...) dprintk(dvb_usb_debug, 0x001, args) #define deb_xfer(args...) dprintk(dvb_usb_debug, 0x002, args) -#define deb_pll(args...) dprintk(dvb_usb_debug, 0x004, args) -#define deb_ts(args...) dprintk(dvb_usb_debug, 0x008, args) -#define deb_err(args...) dprintk(dvb_usb_debug, 0x010, args) -#define deb_rc(args...) dprintk(dvb_usb_debug, 0x020, args) -#define deb_fw(args...) dprintk(dvb_usb_debug, 0x040, args) -#define deb_mem(args...) dprintk(dvb_usb_debug, 0x080, args) #define deb_uxfer(args...) dprintk(dvb_usb_debug, 0x100, args) /* commonly used methods */ -extern int dvb_usb_download_firmware(struct dvb_usb_device *); - extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); extern int usb_urb_init(struct usb_data_stream *stream, diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 095cac5ee0b1..d7c8340ec706 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -80,7 +80,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) /* stop feed before setting a new pid if there will be no pid anymore */ if (newfeedcount == 0) { - deb_ts("stop feeding\n"); + pr_debug("%s: stop feeding\n", __func__); usb_urb_kill(&adap->stream); if (adap->props.streaming_ctrl != NULL) { @@ -95,10 +95,10 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) adap->feedcount = newfeedcount; /* activate the pid on the device specific pid_filter */ - deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n", - adap->pid_filtering ? - "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid, - dvbdmxfeed->index, onoff ? "on" : "off"); + pr_debug("%s: setting pid (%s): %5d %04x at index %d '%s'\n", __func__, + adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, + dvbdmxfeed->pid, dvbdmxfeed->index, + onoff ? "on" : "off"); if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && adap->pid_filtering && adap->props.pid_filter != NULL) @@ -141,23 +141,23 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) stream_props = adap->props.stream; } - deb_ts("submitting all URBs\n"); + pr_debug("%s: submitting all URBs\n", __func__); + usb_urb_submit(&adap->stream, &stream_props); - deb_ts("controlling pid parser\n"); + pr_debug("%s: controlling pid parser\n", __func__); if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->props.caps & - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && - adap->props.pid_filter_ctrl != NULL) { - ret = adap->props.pid_filter_ctrl( - adap, - adap->pid_filtering); + adap->props.caps & + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && + adap->props.pid_filter_ctrl != NULL) { + ret = adap->props.pid_filter_ctrl(adap, + adap->pid_filtering); if (ret < 0) { err("could not handle pid_parser"); return ret; } } - deb_ts("start feeding\n"); + pr_debug("%s: start feeding\n", __func__); if (adap->props.streaming_ctrl != NULL) { ret = adap->props.streaming_ctrl(adap, 1); if (ret < 0) { @@ -172,15 +172,15 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { - deb_ts("start pid: 0x%04x, feedtype: %d\n", - dvbdmxfeed->pid, dvbdmxfeed->type); + pr_debug("%s: start pid %04x feedtype %d", __func__, dvbdmxfeed->pid, + dvbdmxfeed->type); return dvb_usb_ctrl_feed(dvbdmxfeed, 1); } static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { - deb_ts("stop pid: 0x%04x, feedtype: %d\n", - dvbdmxfeed->pid, dvbdmxfeed->type); + pr_debug("%s: stop pid %04x feedtype %d", __func__, dvbdmxfeed->pid, + dvbdmxfeed->type); return dvb_usb_ctrl_feed(dvbdmxfeed, 0); } @@ -191,7 +191,7 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) &adap->dev->udev->dev, adap->dev->props.adapter_nr); if (ret < 0) { - deb_info("dvb_register_adapter failed: error %d", ret); + pr_debug("%s: dvb_register_adapter failed=%d\n", __func__, ret); goto err; } adap->dvb_adap.priv = adap; @@ -253,7 +253,7 @@ err: int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) { if (adap->state & DVB_USB_ADAP_STATE_DVB) { - deb_info("unregistering DVB part\n"); + pr_debug("%s: unregistering DVB part\n", __func__); dvb_net_release(&adap->dvb_net); adap->demux.dmx.close(&adap->demux.dmx); dvb_dmxdev_release(&adap->dmxdev); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 6e0903989484..731d6403faf0 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -189,11 +189,11 @@ static int dvb_usb_adapter_exit(struct dvb_usb_device *d) /* general initialization functions */ static int dvb_usb_exit(struct dvb_usb_device *d) { - deb_info("state before exiting everything: %x\n", d->state); + pr_debug("%s: state before exiting everything: %x\n", __func__, d->state); dvb_usb_remote_exit(d); dvb_usb_adapter_exit(d); dvb_usb_i2c_exit(d); - deb_info("state should be zero now: %x\n", d->state); + pr_debug("%s: state should be zero now: %x\n", __func__, d->state); d->state = DVB_USB_STATE_INIT; kfree(d->priv); kfree(d); @@ -249,7 +249,7 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */ - deb_info("power control: %d\n", onoff); + pr_debug("%s: power control: %d\n", __func__, onoff); if (d->props.power_ctrl) return d->props.power_ctrl(d, onoff); } From e80e9af3086674bdd2d65c09557c7d0df8f30f99 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 4 Jun 2012 22:18:34 -0300 Subject: [PATCH 0235/5375] [media] dvb_usb_v2: remove various unneeded variables Adapter priv is not really needed, use device priv instead. There is only driver or two using that. Device caps are not needed. There was only "has I2C adapter" capability defined. It is useless as we can see same just checking existence of i2c_algo callback. And also remove some totally not used at all variables. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 9 +-------- drivers/media/dvb/dvb-usb/dvb_usb_i2c.c | 7 +------ drivers/media/dvb/dvb-usb/dvb_usb_init.c | 10 +--------- 3 files changed, 3 insertions(+), 23 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index e90d81f7e3d0..e338b4777a11 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -211,9 +211,6 @@ struct dvb_usb_device_properties { struct module *owner; short *adapter_nr; -#define DVB_USB_IS_AN_I2C_ADAPTER 0x01 - int caps; - int size_of_priv; const char *firmware; @@ -330,8 +327,6 @@ struct dvb_usb_adapter { int active_fe; int num_frontends_initialized; - - void *priv; }; /** @@ -379,7 +374,7 @@ struct dvb_usb_device { struct mutex i2c_mutex; struct i2c_adapter i2c_adap; - int num_adapters_initialized; + int num_adapters_initialized; struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; /* remote control */ @@ -387,8 +382,6 @@ struct dvb_usb_device { struct input_dev *input_dev; char rc_phys[64]; struct delayed_work rc_query_work; - u32 last_event; - int last_state; void *priv; }; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c index 6b272c861b4a..ced91e6f480f 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c @@ -11,14 +11,9 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) { int ret = 0; - if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER)) + if (!d->props.i2c_algo) return 0; - if (d->props.i2c_algo == NULL) { - err("no i2c algorithm specified"); - return -EINVAL; - } - strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); d->i2c_adap.algo = d->props.i2c_algo; d->i2c_adap.algo_data = NULL; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 731d6403faf0..a2beb60908d1 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -125,14 +125,6 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d) adap->max_feed_count = adap->props.pid_filter_count; } - if (adap->props.size_of_priv > 0) { - adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL); - if (adap->priv == NULL) { - err("no memory for priv for adapter %d.", n); - return -ENOMEM; - } - } - ret = dvb_usb_adapter_stream_init(adap); if (ret) return ret; @@ -178,7 +170,7 @@ static int dvb_usb_adapter_exit(struct dvb_usb_device *d) dvb_usb_adapter_frontend_exit(&d->adapter[n]); dvb_usb_adapter_dvb_exit(&d->adapter[n]); dvb_usb_adapter_stream_exit(&d->adapter[n]); - kfree(d->adapter[n].priv); + } d->num_adapters_initialized = 0; d->state &= ~DVB_USB_STATE_DVB; From e48b2a68617cfb7881e1c5e420e1a992b1e60e89 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 4 Jun 2012 23:15:26 -0300 Subject: [PATCH 0236/5375] [media] dvb_usb_v2: frontend switching changes Some error checking changes and refactoring. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 80 +++++++++++++++---------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index d7c8340ec706..e1de89a1c006 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -68,12 +68,9 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; int newfeedcount, ret; - if (adap == NULL) - return -ENODEV; - - if ((adap->active_fe < 0) || - (adap->active_fe >= adap->num_frontends_initialized)) { - return -EINVAL; + if (adap == NULL || adap->active_fe < 0) { + ret = -ENODEV; + goto err; } newfeedcount = adap->feedcount + (onoff ? 1 : -1); @@ -168,6 +165,9 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; } static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) @@ -264,47 +264,62 @@ int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) return 0; } -static int dvb_usb_set_active_fe(struct dvb_frontend *fe, int onoff) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - - int ret = (adap->props.frontend_ctrl) ? - adap->props.frontend_ctrl(fe, onoff) : 0; - - if (ret < 0) { - err("frontend_ctrl request failed"); - return ret; - } - if (onoff) - adap->active_fe = fe->id; - - return 0; -} - static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) { + int ret; struct dvb_usb_adapter *adap = fe->dvb->priv; - dvb_usb_device_power_ctrl(adap->dev, 1); + ret = dvb_usb_device_power_ctrl(adap->dev, 1); + if (ret < 0) + goto err; - dvb_usb_set_active_fe(fe, 1); + if (adap->props.frontend_ctrl) { + ret = adap->props.frontend_ctrl(fe, 1); + if (ret < 0) + goto err; + } - if (adap->fe_init[fe->id]) - adap->fe_init[fe->id](fe); + if (adap->fe_init[fe->id]) { + ret = adap->fe_init[fe->id](fe); + if (ret < 0) + goto err; + } + + adap->active_fe = fe->id; return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; } static int dvb_usb_fe_sleep(struct dvb_frontend *fe) { + int ret; struct dvb_usb_adapter *adap = fe->dvb->priv; - if (adap->fe_sleep[fe->id]) - adap->fe_sleep[fe->id](fe); + if (adap->fe_sleep[fe->id]) { + ret = adap->fe_sleep[fe->id](fe); + if (ret < 0) + goto err; + } - dvb_usb_set_active_fe(fe, 0); + if (adap->props.frontend_ctrl) { + ret = adap->props.frontend_ctrl(fe, 0); + if (ret < 0) + goto err; + } - return dvb_usb_device_power_ctrl(adap->dev, 0); + ret = dvb_usb_device_power_ctrl(adap->dev, 0); + if (ret < 0) + goto err; + + adap->active_fe = -1; + + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; } int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) @@ -312,8 +327,7 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) int ret, i; memset(adap->fe, 0, sizeof(adap->fe)); - - adap->active_fe = 0; + adap->active_fe = -1; if (adap->props.frontend_attach == NULL) { err("strange: '%s' doesn't want to attach a frontend.", From 0a8673569ff92d7dd6c07153696d1975d13a3b99 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 5 Jun 2012 20:37:46 -0300 Subject: [PATCH 0237/5375] [media] dvb_usb_v2: ensure driver_info is not null It could be null in case of driver does not set it properly, like missing dynamic ID handling. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index a2beb60908d1..3078371d626b 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -258,10 +258,18 @@ int dvb_usbv2_device_init_(struct usb_interface *intf, struct dvb_usb_device *d = NULL; struct dvb_usb_driver_info *driver_info = (struct dvb_usb_driver_info *) id->driver_info; - const struct dvb_usb_device_properties *props = driver_info->props; + const struct dvb_usb_device_properties *props; int ret = -ENOMEM; bool cold = false; + if (!id->driver_info) { + pr_err("%s: driver_info is null", KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } + + props = driver_info->props; + d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); if (d == NULL) { err("no memory for 'struct dvb_usb_device'"); @@ -326,7 +334,8 @@ int dvb_usbv2_device_init_(struct usb_interface *intf, err_kfree: kfree(d->priv); kfree(d); - +err: + pr_debug("%s: failed=%d\n", __func__, ret); return ret; } From 4f208d4e2d871c2416c9a86695d6f7d17e76349b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 6 Jun 2012 00:05:06 -0300 Subject: [PATCH 0238/5375] [media] dvb_usb_v2: refactor delayed init Move work to the struct dvb_usb_device that we can access it inside .disconnect(). Also many other minor changes. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 2 + drivers/media/dvb/dvb-usb/dvb_usb_init.c | 171 ++++++++++------------- 2 files changed, 74 insertions(+), 99 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index e338b4777a11..44c799cedc87 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -358,6 +358,8 @@ struct dvb_usb_device { const char *rc_map; struct dvb_usb_rc rc; struct usb_device *udev; + struct work_struct probe_work; + struct usb_interface *intf; #define DVB_USB_STATE_INIT 0x000 #define DVB_USB_STATE_I2C 0x001 diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 3078371d626b..d7a6efc9a52e 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -251,44 +251,29 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) /* * USB */ -int dvb_usbv2_device_init_(struct usb_interface *intf, - const struct usb_device_id *id) + +/* + * udev, which is used for the firmware downloading, requires we cannot + * block during module_init(). module_init() calls USB probe() which + * is this routine. Due to that we delay actual operation using workqueue + * and return always success here. + */ + +static void dvb_usbv2_init_work(struct work_struct *work) { - struct usb_device *udev = interface_to_usbdev(intf); - struct dvb_usb_device *d = NULL; - struct dvb_usb_driver_info *driver_info = - (struct dvb_usb_driver_info *) id->driver_info; - const struct dvb_usb_device_properties *props; - int ret = -ENOMEM; + int ret; + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, probe_work); bool cold = false; - if (!id->driver_info) { - pr_err("%s: driver_info is null", KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } + pr_debug("%s:\n", __func__); - props = driver_info->props; - - d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); - if (d == NULL) { - err("no memory for 'struct dvb_usb_device'"); - return -ENOMEM; - } - - d->udev = udev; - d->name = driver_info->name; - d->rc_map = driver_info->rc_map; - memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); - mutex_init(&d->usb_mutex); - mutex_init(&d->i2c_mutex); - - if (d->props.size_of_priv > 0) { + if (d->props.size_of_priv) { d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); - if (d->priv == NULL) { - err("no memory for priv in 'struct dvb_usb_device'"); + if (!d->priv) { + pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME); ret = -ENOMEM; - goto err_kfree; + goto err_usb_driver_release_interface; } } @@ -300,77 +285,41 @@ int dvb_usbv2_device_init_(struct usb_interface *intf, cold = true; ret = 0; } else { - goto err_kfree; + goto err_usb_driver_release_interface; } } if (cold) { - info("found a '%s' in cold state, will try to load a firmware", - d->name); + pr_info("%s: found a '%s' in cold state\n", + KBUILD_MODNAME, d->name); ret = dvb_usb_download_firmware(d); if (ret == 0) { ; } else if (ret == RECONNECTS_USB) { ret = 0; - goto err_kfree; + goto exit_usb_driver_release_interface; } else { - goto err_kfree; + goto err_usb_driver_release_interface; } } - info("found a '%s' in warm state.", d->name); - - usb_set_intfdata(intf, d); + pr_info("%s: found a '%s' in warm state\n", KBUILD_MODNAME, d->name); ret = dvb_usb_init(d); + if (ret < 0) + goto err_usb_driver_release_interface; - if (ret == 0) - info("%s successfully initialized and connected.", d->name); - else - info("%s error while loading driver (%d)", d->name, ret); - - return 0; - -err_kfree: - kfree(d->priv); - kfree(d); -err: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - -/* - * udev, which is used for the firmware downloading, requires we cannot - * block during module_init(). module_init() calls USB probe() which - * is this routine. Due to that we delay actual operation using workqueue - * and return always success here. - */ - -struct dvb_usb_delayed_init { - struct usb_interface *intf; - const struct usb_device_id *id; - struct work_struct work; -}; - -static void dvb_usbv2_init_work(struct work_struct *work) -{ - int ret; - struct dvb_usb_delayed_init *delayed_init = - container_of(work, struct dvb_usb_delayed_init, work); - - ret = dvb_usbv2_device_init_(delayed_init->intf, delayed_init->id); - if (ret < 0) { - usb_driver_release_interface( - to_usb_driver(delayed_init->intf->dev.driver), - delayed_init->intf); - kfree(delayed_init); - goto err; - } - - kfree(delayed_init); + pr_info("%s: '%s' successfully initialized and connected\n", + KBUILD_MODNAME, d->name); return; -err: +err_usb_driver_release_interface: + pr_info("%s: '%s' error while loading driver (%d)\n", KBUILD_MODNAME, + d->name, ret); +exit_usb_driver_release_interface: + /* it finally calls .disconnect() which frees mem */ + usb_driver_release_interface(to_usb_driver(d->intf->dev.driver), + d->intf); pr_debug("%s: failed=%d\n", __func__, ret); return; } @@ -379,28 +328,45 @@ int dvb_usbv2_device_init(struct usb_interface *intf, const struct usb_device_id *id) { int ret; - struct dvb_usb_delayed_init *delayed_init; + struct dvb_usb_device *d; + struct dvb_usb_driver_info *driver_info = + (struct dvb_usb_driver_info *) id->driver_info; - delayed_init = kzalloc(sizeof(struct dvb_usb_delayed_init), GFP_KERNEL); - if (!delayed_init) { - pr_err("%s: kzalloc() failed", DVB_USB_LOG_PREFIX); + pr_debug("%s:\n", __func__); + + if (!id->driver_info) { + pr_err("%s: driver_info failed\n", KBUILD_MODNAME); + ret = -ENODEV; + goto err; + } + + d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); + if (!d) { + pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME); ret = -ENOMEM; goto err; } - delayed_init->intf = intf; - delayed_init->id = id; - INIT_WORK(&delayed_init->work, dvb_usbv2_init_work); - - ret = schedule_work(&delayed_init->work); + d->name = driver_info->name; + d->rc_map = driver_info->rc_map; + d->udev = interface_to_usbdev(intf); + d->intf = intf; + memcpy(&d->props, driver_info->props, + sizeof(struct dvb_usb_device_properties)); + mutex_init(&d->usb_mutex); + mutex_init(&d->i2c_mutex); + INIT_WORK(&d->probe_work, dvb_usbv2_init_work); + usb_set_intfdata(intf, d); + ret = schedule_work(&d->probe_work); if (ret < 0) { - pr_err("%s: schedule_work() failed", DVB_USB_LOG_PREFIX); + pr_err("%s: schedule_work() failed\n", KBUILD_MODNAME); goto err_kfree; } return 0; err_kfree: - kfree(delayed_init); + usb_set_intfdata(intf, NULL); + kfree(d); err: pr_debug("%s: failed=%d\n", __func__, ret); return ret; @@ -413,9 +379,14 @@ void dvb_usbv2_device_exit(struct usb_interface *intf) struct dvb_usb_device *d = usb_get_intfdata(intf); const char *name = "generic DVB-USB module"; + pr_debug("%s:\n", __func__); + /* - * FIXME: we should ensure our device initialization work is finished - * until exit from this routine (cancel_work_sync?) + * FIXME: We should ensure initialization work is finished + * until exit from this routine (cancel_work_sync / flush_work). + * Unfortunately usb_driver_release_interface() call finally goes + * here too and in that case we endup deadlock. How to perform + * operation conditionally only on disconned / unload? */ usb_set_intfdata(intf, NULL); @@ -423,7 +394,9 @@ void dvb_usbv2_device_exit(struct usb_interface *intf) name = d->name; dvb_usb_exit(d); } - info("%s successfully deinitialized and disconnected.", name); + + pr_info("%s: '%s' successfully deinitialized and disconnected\n", + KBUILD_MODNAME, name); } EXPORT_SYMBOL(dvb_usbv2_device_exit); From 96ffea88cddd9bd873a03a7c8c65d015a9d56490 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 6 Jun 2012 15:01:32 -0300 Subject: [PATCH 0239/5375] [media] dvb_usb_v2: remove usb_clear_halt() Calling usb_clear_halt() during device init is not correct. 2 of 7 AF9015 devices I have timeouts next USB control message after usb_clear_halt(). It was originally performed between tuner_attach() and rc_query() and likely not causing problems since rc_query() is repeated continously. None could see it when first rc_query() failed... Secondly it was not called for .generic_bulk_ctrl_endpoint_response. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index d7a6efc9a52e..581be9d990a0 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -145,17 +145,6 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d) d->state |= DVB_USB_STATE_DVB; } - /* - * when reloading the driver w/o replugging the device - * sometimes a timeout occures, this helps - */ - if (d->props.generic_bulk_ctrl_endpoint != 0) { - usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint)); - usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint)); - } - return 0; err: pr_debug("%s: failed=%d\n", __func__, ret); @@ -177,7 +166,6 @@ static int dvb_usb_adapter_exit(struct dvb_usb_device *d) return 0; } - /* general initialization functions */ static int dvb_usb_exit(struct dvb_usb_device *d) { From cce99cf93312ed0de22128037de11e00fa327cb5 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 6 Jun 2012 17:52:51 -0300 Subject: [PATCH 0240/5375] [media] dvb_usb_v2: unregister all frontends in error case Unregister all if there is any error meet during frontend initialization. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 78 +++++++++++++------------ 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index e1de89a1c006..b6fc5a6fe99b 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -324,32 +324,36 @@ err: int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) { - int ret, i; + int ret, i, count_registered = 0; + + pr_debug("%s:\n", __func__); memset(adap->fe, 0, sizeof(adap->fe)); adap->active_fe = -1; - if (adap->props.frontend_attach == NULL) { - err("strange: '%s' doesn't want to attach a frontend.", - adap->dev->name); + if (adap->props.frontend_attach) { + ret = adap->props.frontend_attach(adap); + if (ret < 0) { + pr_debug("%s: frontend_attach() failed=%d\n", __func__, + ret); + goto err_dvb_frontend_detach; + } + } else { + pr_debug("%s: frontend_attach() do not exists\n", __func__); ret = 0; goto err; } - /* attach all given adapter frontends */ - ret = adap->props.frontend_attach(adap); - if (ret < 0) - goto err; - - if (adap->fe[0] == NULL) { - err("no frontend was attached by '%s'", adap->dev->name); - goto err; + if (adap->props.tuner_attach) { + ret = adap->props.tuner_attach(adap); + if (ret < 0) { + pr_debug("%s: tuner_attach() failed=%d\n", __func__, + ret); + goto err_dvb_frontend_detach; + } } - for (i = 0; i < MAX_NO_OF_FE_PER_ADAP; i++) { - if (adap->fe[i] == NULL) - break; - + for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) { adap->fe[i]->id = i; /* re-assign sleep and wakeup functions */ @@ -360,28 +364,28 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); if (ret < 0) { - err("Frontend %d registration failed.", i); - dvb_frontend_detach(adap->fe[i]); - adap->fe[i] = NULL; - /* In error case, do not try register more FEs, - * still leaving already registered FEs alive. */ - if (i == 0) - goto err; - else - break; + pr_err("%s: frontend%d registration failed\n", + KBUILD_MODNAME, i); + goto err_dvb_unregister_frontend; } - adap->num_frontends_initialized++; + count_registered++; } - /* attach all given adapter tuners */ - if (adap->props.tuner_attach) { - ret = adap->props.tuner_attach(adap); - if (ret < 0) - err("tuner attach failed - will continue"); - } + adap->num_frontends_initialized = count_registered; return 0; + +err_dvb_unregister_frontend: + for (i = count_registered - 1; i >= 0; i--) + dvb_unregister_frontend(adap->fe[i]); + +err_dvb_frontend_detach: + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { + if (adap->fe[i]) + dvb_frontend_detach(adap->fe[i]); + } + err: pr_debug("%s: failed=%d\n", __func__, ret); return ret; @@ -389,15 +393,17 @@ err: int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) { - int i = adap->num_frontends_initialized - 1; + int i; - /* unregister all given adapter frontends */ - for (; i >= 0; i--) { - if (adap->fe[i] != NULL) { + pr_debug("%s:\n", __func__); + + for (i = adap->num_frontends_initialized - 1; i >= 0; i--) { + if (adap->fe[i]) { dvb_unregister_frontend(adap->fe[i]); dvb_frontend_detach(adap->fe[i]); } } + adap->num_frontends_initialized = 0; return 0; From 23d8e63a903bf8b6d9bf99bdd0e45aa901a90fff Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 6 Jun 2012 22:46:38 -0300 Subject: [PATCH 0241/5375] [media] dvb_usb_v2: use Kernel logging (pr_debug/pr_err/pr_info) Use Kernel logging insteads of own macros. Get rid of old debugs and use dynamic debug. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 38 -------------------- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 5 --- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 25 +++++++------ drivers/media/dvb/dvb-usb/dvb_usb_i2c.c | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 41 +++++++++++----------- drivers/media/dvb/dvb-usb/dvb_usb_remote.c | 8 ++--- drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 20 ++++++----- drivers/media/dvb/dvb-usb/usb_urb.c | 35 ++++++++++-------- 8 files changed, 71 insertions(+), 103 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 44c799cedc87..78b69286a803 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -20,46 +20,8 @@ #include "dvb_demux.h" #include "dvb_net.h" #include "dmxdev.h" - -#include "dvb-pll.h" - #include "dvb-usb-ids.h" -/* debug */ -#ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var, level, args...) \ - do { if ((var & level)) { printk(args); } } while (0) - -#define debug_dump(b, l, func) {\ - int loop_; \ - for (loop_ = 0; loop_ < l; loop_++) \ - func("%02x ", b[loop_]); \ - func("\n");\ -} -#define DVB_USB_DEBUG_STATUS -#else -#define dprintk(args...) -#define debug_dump(b, l, func) - -#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" - -#endif - -/* generic log methods - taken from usb.h */ -#ifndef DVB_USB_LOG_PREFIX - #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)" -#endif - -#undef err -#define err(format, arg...) \ - printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef info -#define info(format, arg...) \ - printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) \ - printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) - struct dvb_usb_driver_info { const char *name; const char *rc_map; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index 3a092053d823..058fa8c06846 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -9,15 +9,10 @@ #ifndef DVB_USB_COMMON_H #define DVB_USB_COMMON_H -#define DVB_USB_LOG_PREFIX "dvb_usb" #include "dvb_usb.h" -extern int dvb_usb_debug; extern int dvb_usb_disable_rc_polling; -#define deb_xfer(args...) dprintk(dvb_usb_debug, 0x002, args) -#define deb_uxfer(args...) dprintk(dvb_usb_debug, 0x100, args) - /* commonly used methods */ extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index b6fc5a6fe99b..b9524326c8ba 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -83,7 +83,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) if (adap->props.streaming_ctrl != NULL) { ret = adap->props.streaming_ctrl(adap, 0); if (ret < 0) { - err("error while stopping stream."); + pr_err("%s: error while stopping stream", + KBUILD_MODNAME); return ret; } } @@ -150,7 +151,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) ret = adap->props.pid_filter_ctrl(adap, adap->pid_filtering); if (ret < 0) { - err("could not handle pid_parser"); + pr_err("%s: could not handle pid_parser", + KBUILD_MODNAME); return ret; } } @@ -158,7 +160,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) if (adap->props.streaming_ctrl != NULL) { ret = adap->props.streaming_ctrl(adap, 1); if (ret < 0) { - err("error while enabling fifo."); + pr_err("%s: error while enabling fifo", + KBUILD_MODNAME); return ret; } } @@ -172,14 +175,14 @@ err: static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { - pr_debug("%s: start pid %04x feedtype %d", __func__, dvbdmxfeed->pid, + pr_debug("%s: start pid=%04x feedtype=%d\n", __func__, dvbdmxfeed->pid, dvbdmxfeed->type); return dvb_usb_ctrl_feed(dvbdmxfeed, 1); } static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { - pr_debug("%s: stop pid %04x feedtype %d", __func__, dvbdmxfeed->pid, + pr_debug("%s: stop pid=%04x feedtype=%d\n", __func__, dvbdmxfeed->pid, dvbdmxfeed->type); return dvb_usb_ctrl_feed(dvbdmxfeed, 0); } @@ -200,9 +203,11 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) if (adap->dev->props.read_mac_address) { if (adap->dev->props.read_mac_address(adap->dev, adap->dvb_adap.proposed_mac) == 0) - info("MAC address: %pM", adap->dvb_adap.proposed_mac); + pr_info("%s: MAC address: %pM", KBUILD_MODNAME, + adap->dvb_adap.proposed_mac); else - err("MAC address reading failed."); + pr_err("%s: MAC address reading failed", + KBUILD_MODNAME); } @@ -218,7 +223,7 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->demux.write_to_decoder = NULL; ret = dvb_dmx_init(&adap->demux); if (ret < 0) { - err("dvb_dmx_init failed: error %d", ret); + pr_err("%s: dvb_dmx_init() failed=%d", KBUILD_MODNAME, ret); goto err_dmx; } @@ -227,13 +232,13 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->dmxdev.capabilities = 0; ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); if (ret < 0) { - err("dvb_dmxdev_init failed: error %d", ret); + pr_err("%s: dvb_dmxdev_init failed=%d", KBUILD_MODNAME, ret); goto err_dmx_dev; } ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); if (ret < 0) { - err("dvb_net_init failed: error %d", ret); + pr_err("%s: dvb_net_init failed=%d", KBUILD_MODNAME, ret); goto err_net_init; } diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c index ced91e6f480f..202e1d1acffb 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c @@ -23,7 +23,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) ret = i2c_add_adapter(&d->i2c_adap); if (ret < 0) - err("could not add i2c adapter"); + pr_err("%s: could not add i2c adapter", KBUILD_MODNAME); d->state |= DVB_USB_STATE_I2C; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 581be9d990a0..9dcf4e525795 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -13,13 +13,6 @@ */ #include "dvb_usb_common.h" -/* debug */ -int dvb_usb_debug; -module_param_named(debug, dvb_usb_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8"\ - ",err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." - DVB_USB_DEBUG_STATUS); - int dvb_usb_disable_rc_polling; module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); MODULE_PARM_DESC(disable_rc_polling, @@ -52,13 +45,15 @@ int dvb_usb_download_firmware(struct dvb_usb_device *d) ret = request_firmware(&fw, name, &d->udev->dev); if (ret < 0) { - err("did not find the firmware file. (%s) " \ - "Please see linux/Documentation/dvb/ for more" \ - " details on firmware-problems. (%d)", name, ret); + pr_err("%s: did not find the firmware file. (%s) " \ + "Please see linux/Documentation/dvb/ for " \ + "more details on firmware-problems. (%d)", + KBUILD_MODNAME, name, ret); goto err; } - info("downloading firmware from file '%s'", name); + pr_info("%s: downloading firmware from file '%s'", KBUILD_MODNAME, + name); ret = d->props.download_firmware(d, fw); @@ -99,28 +94,31 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d) /* speed - when running at FULL speed we need a HW PID filter */ if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) { - err("This USB2.0 device cannot be run on a" \ - " USB1.1 port. (it lacks a" \ - " hardware PID filter)"); + pr_err("%s: this USB2.0 device cannot be run on a " \ + "USB1.1 port (it lacks a hardware " \ + "PID filter)", KBUILD_MODNAME); return -ENODEV; } else if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) || (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { - info("will use the device's hardware PID" \ - " filter (table count: %d).", - adap->props.pid_filter_count); + pr_info("%s: will use the device's hardware PID " \ + "filter (table count: %d)", + KBUILD_MODNAME, + adap->props.pid_filter_count); adap->pid_filtering = 1; adap->max_feed_count = adap->props.pid_filter_count; } else { - info("will pass the complete MPEG2 transport" \ - " stream to the software demuxer."); + pr_info("%s: will pass the complete MPEG2 transport " \ + "stream to the software demuxer", + KBUILD_MODNAME); adap->pid_filtering = 0; adap->max_feed_count = 255; } if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) { - info("pid filter enabled by module option."); + pr_info("%s: pid filter enabled by module option", + KBUILD_MODNAME); adap->pid_filtering = 1; adap->max_feed_count = adap->props.pid_filter_count; } @@ -210,7 +208,8 @@ static int dvb_usb_init(struct dvb_usb_device *d) ret = dvb_usb_remote_init(d); if (ret) - err("could not initialize remote control."); + pr_err("%s: could not initialize remote control\n", + KBUILD_MODNAME); dvb_usb_device_power_ctrl(d, 0); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c index 22d7790e7c42..f64982a1cd83 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c @@ -31,7 +31,8 @@ static void dvb_usb_read_remote_control(struct work_struct *work) ret = d->rc.query(d); if (ret < 0) - err("error %d while querying for an remote control event", ret); + pr_err("%s: error %d while querying for an remote control " \ + "event", KBUILD_MODNAME, ret); schedule_delayed_work(&d->rc_query_work, msecs_to_jiffies(d->rc.interval)); @@ -89,9 +90,8 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) /* initialize a work queue for handling polling */ INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); - - info("schedule remote query interval to %d msecs", - d->rc.interval); + pr_info("%s: schedule remote query interval to %d msecs", + KBUILD_MODNAME, d->rc.interval); schedule_delayed_work(&d->rc_query_work, msecs_to_jiffies(d->rc.interval)); } diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index 43563b341b80..e28a4dc3cb04 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -17,7 +17,8 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, return -EINVAL; if (d->props.generic_bulk_ctrl_endpoint == 0) { - err("endpoint for generic control not specified."); + pr_err("%s: endpoint for generic control not specified", + KBUILD_MODNAME); return -EINVAL; } @@ -25,15 +26,16 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, if (ret) return ret; - deb_xfer(">>> "); - debug_dump(wbuf, wlen, deb_xfer); + print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": >>> ", DUMP_PREFIX_NONE, + 32, 1, wbuf, wlen, 0); ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint), wbuf, wlen, &actlen, 2000); if (ret) - err("bulk message failed: %d (%d/%d)", ret, wlen, actlen); + pr_err("%s: bulk message failed: %d (%d/%d)", KBUILD_MODNAME, + ret, wlen, actlen); else ret = actlen != wlen ? -1 : 0; @@ -49,11 +51,11 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, rbuf, rlen, &actlen, 2000); if (ret) - err("recv bulk message failed: %d", ret); - else { - deb_xfer("<<< "); - debug_dump(rbuf, actlen, deb_xfer); - } + pr_err("%s: recv bulk message failed: %d", + KBUILD_MODNAME, ret); + else + print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": <<< ", + DUMP_PREFIX_NONE, 32, 1, wbuf, wlen, 0); } mutex_unlock(&d->usb_mutex); diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c index bf987c09b0cd..baa2938db151 100644 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -22,11 +22,12 @@ static void usb_urb_complete(struct urb *urb) int i; u8 *b; - deb_uxfer("'%s' urb completed. status: %d, length: %d/%d," \ - " pack_num: %d, errors: %d\n", - ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", - urb->status, urb->actual_length, urb->transfer_buffer_length, - urb->number_of_packets, urb->error_count); + pr_debug("%s: %s urb completed status=%d length=%d/%d" \ + " pack_num=%d errors=%d\n", __func__, + ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", + urb->status, urb->actual_length, + urb->transfer_buffer_length, + urb->number_of_packets, urb->error_count); switch (urb->status) { case 0: /* success */ @@ -47,8 +48,8 @@ static void usb_urb_complete(struct urb *urb) case PIPE_ISOCHRONOUS: for (i = 0; i < urb->number_of_packets; i++) { if (urb->iso_frame_desc[i].status != 0) - pr_debug("%s: iso frame descriptor has an" \ - " error=%d\n", __func__, + pr_debug("%s: iso frame descriptor has an " \ + "error=%d\n", __func__, urb->iso_frame_desc[i].status); else if (urb->iso_frame_desc[i].actual_length > 0) stream->complete(stream, @@ -58,14 +59,14 @@ static void usb_urb_complete(struct urb *urb) urb->iso_frame_desc[i].status = 0; urb->iso_frame_desc[i].actual_length = 0; } - debug_dump(b, 20, deb_uxfer); break; case PIPE_BULK: if (urb->actual_length > 0) stream->complete(stream, b, urb->actual_length); break; default: - err("unknown endpoint type in completition handler."); + pr_err("%s: unknown endpoint type in completition handler", + KBUILD_MODNAME); return; } usb_submit_urb(urb, GFP_ATOMIC); @@ -98,8 +99,8 @@ int usb_urb_submit(struct usb_data_stream *stream, pr_debug("%s: submit URB=%d\n", __func__, i); ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); if (ret) { - err("could not submit URB no. %d - get them all back", - i); + pr_err("%s: could not submit URB no. %d - get them " \ + "all back", KBUILD_MODNAME, i); usb_urb_kill(stream); return ret; } @@ -263,12 +264,14 @@ int usb_urb_reconfig(struct usb_data_stream *stream, } else if (props->type == USB_ISOC) { buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb; } else { - err("invalid endpoint type=%d", props->type); + pr_err("%s: invalid endpoint type=%d", KBUILD_MODNAME, + props->type); return -EINVAL; } if (stream->buf_num < props->count || stream->buf_size < buf_size) { - err("cannot reconfigure as allocated buffers are too small"); + pr_err("%s: cannot reconfigure as allocated buffers are too " \ + "small", KBUILD_MODNAME); return -EINVAL; } @@ -316,7 +319,8 @@ int usb_urb_init(struct usb_data_stream *stream, stream->props.endpoint)); if (stream->complete == NULL) { - err("there is no data callback - this doesn't make sense."); + pr_err("%s: there is no data callback - this doesn't make " \ + "sense", KBUILD_MODNAME); return -EINVAL; } @@ -337,7 +341,8 @@ int usb_urb_init(struct usb_data_stream *stream, return usb_urb_alloc_isoc_urbs(stream); default: - err("unknown URB-type for data transfer."); + pr_err("%s: unknown URB-type for data transfer", + KBUILD_MODNAME); return -EINVAL; } } From a177c72bf57f70585f08231145b2431b4182b2b4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Jun 2012 15:40:25 -0300 Subject: [PATCH 0242/5375] [media] dvb_usb_v2: move I2C adapter code to different file No worth to keep it on own file as it is only 30 LOC. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_i2c.c | 39 ------------------------ drivers/media/dvb/dvb-usb/dvb_usb_init.c | 31 +++++++++++++++++++ 2 files changed, 31 insertions(+), 39 deletions(-) delete mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_i2c.c diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c b/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c deleted file mode 100644 index 202e1d1acffb..000000000000 --- a/drivers/media/dvb/dvb-usb/dvb_usb_i2c.c +++ /dev/null @@ -1,39 +0,0 @@ -/* dvb-usb-i2c.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for (de-)initializing an I2C adapter. - */ -#include "dvb_usb_common.h" - -int dvb_usb_i2c_init(struct dvb_usb_device *d) -{ - int ret = 0; - - if (!d->props.i2c_algo) - return 0; - - strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); - d->i2c_adap.algo = d->props.i2c_algo; - d->i2c_adap.algo_data = NULL; - d->i2c_adap.dev.parent = &d->udev->dev; - - i2c_set_adapdata(&d->i2c_adap, d); - - ret = i2c_add_adapter(&d->i2c_adap); - if (ret < 0) - pr_err("%s: could not add i2c adapter", KBUILD_MODNAME); - - d->state |= DVB_USB_STATE_I2C; - - return ret; -} - -int dvb_usb_i2c_exit(struct dvb_usb_device *d) -{ - if (d->state & DVB_USB_STATE_I2C) - i2c_del_adapter(&d->i2c_adap); - d->state &= ~DVB_USB_STATE_I2C; - return 0; -} diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 9dcf4e525795..aa7caa5c4684 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -68,6 +68,37 @@ err: return ret; } +int dvb_usb_i2c_init(struct dvb_usb_device *d) +{ + int ret = 0; + + if (!d->props.i2c_algo) + return 0; + + strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); + d->i2c_adap.algo = d->props.i2c_algo; + d->i2c_adap.algo_data = NULL; + d->i2c_adap.dev.parent = &d->udev->dev; + + i2c_set_adapdata(&d->i2c_adap, d); + + ret = i2c_add_adapter(&d->i2c_adap); + if (ret < 0) + pr_err("%s: could not add i2c adapter", KBUILD_MODNAME); + + d->state |= DVB_USB_STATE_I2C; + + return ret; +} + +int dvb_usb_i2c_exit(struct dvb_usb_device *d) +{ + if (d->state & DVB_USB_STATE_I2C) + i2c_del_adapter(&d->i2c_adap); + d->state &= ~DVB_USB_STATE_I2C; + return 0; +} + static int dvb_usb_adapter_init(struct dvb_usb_device *d) { struct dvb_usb_adapter *adap; From 6b8c8c40894a88035fb29472a25f6864cd2e8197 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Jun 2012 16:23:40 -0300 Subject: [PATCH 0243/5375] [media] dvb_usb_v2: rename device_init/device_exit to probe/disconnect Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 4 ++-- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 78b69286a803..e67333b4a726 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -350,9 +350,9 @@ struct dvb_usb_device { void *priv; }; -extern int dvb_usbv2_device_init(struct usb_interface *, +extern int dvb_usbv2_probe(struct usb_interface *, const struct usb_device_id *); -extern void dvb_usbv2_device_exit(struct usb_interface *); +extern void dvb_usbv2_disconnect(struct usb_interface *); /* the generic read/write method for device control */ extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16, diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index aa7caa5c4684..c0857d03275e 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -342,7 +342,7 @@ exit_usb_driver_release_interface: return; } -int dvb_usbv2_device_init(struct usb_interface *intf, +int dvb_usbv2_probe(struct usb_interface *intf, const struct usb_device_id *id) { int ret; @@ -389,10 +389,9 @@ err: pr_debug("%s: failed=%d\n", __func__, ret); return ret; } +EXPORT_SYMBOL(dvb_usbv2_probe); -EXPORT_SYMBOL(dvb_usbv2_device_init); - -void dvb_usbv2_device_exit(struct usb_interface *intf) +void dvb_usbv2_disconnect(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); const char *name = "generic DVB-USB module"; @@ -416,7 +415,7 @@ void dvb_usbv2_device_exit(struct usb_interface *intf) pr_info("%s: '%s' successfully deinitialized and disconnected\n", KBUILD_MODNAME, name); } -EXPORT_SYMBOL(dvb_usbv2_device_exit); +EXPORT_SYMBOL(dvb_usbv2_disconnect); MODULE_VERSION("1.0"); MODULE_AUTHOR("Patrick Boettcher "); From 36764037640e1892d769cfcfe1df51b985d84563 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Jun 2012 17:34:41 -0300 Subject: [PATCH 0244/5375] [media] dvb_usb_v2: add .bInterfaceNumber match There is no USB match flag for used USB interface. It is rather common there is multiple interfaces offering different services. For example one for television and one for remote controller. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 1 + drivers/media/dvb/dvb-usb/dvb_usb_init.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index e67333b4a726..4394a5d6f161 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -172,6 +172,7 @@ struct dvb_usb_device_properties { const char *driver_name; struct module *owner; short *adapter_nr; + u8 bInterfaceNumber; int size_of_priv; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index c0857d03275e..7c98a40562e4 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -350,7 +350,8 @@ int dvb_usbv2_probe(struct usb_interface *intf, struct dvb_usb_driver_info *driver_info = (struct dvb_usb_driver_info *) id->driver_info; - pr_debug("%s:\n", __func__); + pr_debug("%s: bInterfaceNumber=%d\n", __func__, + intf->cur_altsetting->desc.bInterfaceNumber); if (!id->driver_info) { pr_err("%s: driver_info failed\n", KBUILD_MODNAME); @@ -371,6 +372,13 @@ int dvb_usbv2_probe(struct usb_interface *intf, d->intf = intf; memcpy(&d->props, driver_info->props, sizeof(struct dvb_usb_device_properties)); + + if (d->intf->cur_altsetting->desc.bInterfaceNumber != + d->props.bInterfaceNumber) { + ret = 0; + goto exit_kfree; + } + mutex_init(&d->usb_mutex); mutex_init(&d->i2c_mutex); INIT_WORK(&d->probe_work, dvb_usbv2_init_work); @@ -384,6 +392,7 @@ int dvb_usbv2_probe(struct usb_interface *intf, return 0; err_kfree: usb_set_intfdata(intf, NULL); +exit_kfree: kfree(d); err: pr_debug("%s: failed=%d\n", __func__, ret); From 65de8f978fcf83c89277fca98b5202ee430131cd Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Jun 2012 17:52:06 -0300 Subject: [PATCH 0245/5375] [media] dvb_usb_v2: add missing new line for log writings Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 3 --- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 17 +++++++++-------- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 14 +++++++------- drivers/media/dvb/dvb-usb/dvb_usb_remote.c | 4 ++-- drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 6 +++--- drivers/media/dvb/dvb-usb/usb_urb.c | 12 ++++++------ 6 files changed, 27 insertions(+), 29 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index 058fa8c06846..c3035a154860 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -26,9 +26,6 @@ extern int usb_urb_kill(struct usb_data_stream *stream); extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap); extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap); -extern int dvb_usb_i2c_init(struct dvb_usb_device *); -extern int dvb_usb_i2c_exit(struct dvb_usb_device *); - extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap); extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap); extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index b9524326c8ba..a2ec0427f833 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -83,7 +83,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) if (adap->props.streaming_ctrl != NULL) { ret = adap->props.streaming_ctrl(adap, 0); if (ret < 0) { - pr_err("%s: error while stopping stream", + pr_err("%s: error while stopping stream\n", KBUILD_MODNAME); return ret; } @@ -151,7 +151,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) ret = adap->props.pid_filter_ctrl(adap, adap->pid_filtering); if (ret < 0) { - pr_err("%s: could not handle pid_parser", + pr_err("%s: could not handle pid_parser\n", KBUILD_MODNAME); return ret; } @@ -160,7 +160,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) if (adap->props.streaming_ctrl != NULL) { ret = adap->props.streaming_ctrl(adap, 1); if (ret < 0) { - pr_err("%s: error while enabling fifo", + pr_err("%s: error while enabling fifo\n", KBUILD_MODNAME); return ret; } @@ -203,10 +203,10 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) if (adap->dev->props.read_mac_address) { if (adap->dev->props.read_mac_address(adap->dev, adap->dvb_adap.proposed_mac) == 0) - pr_info("%s: MAC address: %pM", KBUILD_MODNAME, + pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME, adap->dvb_adap.proposed_mac); else - pr_err("%s: MAC address reading failed", + pr_err("%s: MAC address reading failed\n", KBUILD_MODNAME); } @@ -223,7 +223,7 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->demux.write_to_decoder = NULL; ret = dvb_dmx_init(&adap->demux); if (ret < 0) { - pr_err("%s: dvb_dmx_init() failed=%d", KBUILD_MODNAME, ret); + pr_err("%s: dvb_dmx_init() failed=%d\n", KBUILD_MODNAME, ret); goto err_dmx; } @@ -232,13 +232,14 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->dmxdev.capabilities = 0; ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); if (ret < 0) { - pr_err("%s: dvb_dmxdev_init failed=%d", KBUILD_MODNAME, ret); + pr_err("%s: dvb_dmxdev_init() failed=%d\n", KBUILD_MODNAME, + ret); goto err_dmx_dev; } ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); if (ret < 0) { - pr_err("%s: dvb_net_init failed=%d", KBUILD_MODNAME, ret); + pr_err("%s: dvb_net_init() failed=%d\n", KBUILD_MODNAME, ret); goto err_net_init; } diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 7c98a40562e4..0a452fc4edc8 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -47,12 +47,12 @@ int dvb_usb_download_firmware(struct dvb_usb_device *d) if (ret < 0) { pr_err("%s: did not find the firmware file. (%s) " \ "Please see linux/Documentation/dvb/ for " \ - "more details on firmware-problems. (%d)", + "more details on firmware-problems. (%d)\n", KBUILD_MODNAME, name, ret); goto err; } - pr_info("%s: downloading firmware from file '%s'", KBUILD_MODNAME, + pr_info("%s: downloading firmware from file '%s'\n", KBUILD_MODNAME, name); ret = d->props.download_firmware(d, fw); @@ -84,7 +84,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) ret = i2c_add_adapter(&d->i2c_adap); if (ret < 0) - pr_err("%s: could not add i2c adapter", KBUILD_MODNAME); + pr_err("%s: could not add i2c adapter\n", KBUILD_MODNAME); d->state |= DVB_USB_STATE_I2C; @@ -127,20 +127,20 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d) !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) { pr_err("%s: this USB2.0 device cannot be run on a " \ "USB1.1 port (it lacks a hardware " \ - "PID filter)", KBUILD_MODNAME); + "PID filter)\n", KBUILD_MODNAME); return -ENODEV; } else if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) || (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { pr_info("%s: will use the device's hardware PID " \ - "filter (table count: %d)", + "filter (table count: %d)\n", KBUILD_MODNAME, adap->props.pid_filter_count); adap->pid_filtering = 1; adap->max_feed_count = adap->props.pid_filter_count; } else { pr_info("%s: will pass the complete MPEG2 transport " \ - "stream to the software demuxer", + "stream to the software demuxer\n", KBUILD_MODNAME); adap->pid_filtering = 0; adap->max_feed_count = 255; @@ -148,7 +148,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d) if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) { - pr_info("%s: pid filter enabled by module option", + pr_info("%s: pid filter enabled by module option\n", KBUILD_MODNAME); adap->pid_filtering = 1; adap->max_feed_count = adap->props.pid_filter_count; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c index f64982a1cd83..8c7f1221f89a 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c @@ -32,7 +32,7 @@ static void dvb_usb_read_remote_control(struct work_struct *work) ret = d->rc.query(d); if (ret < 0) pr_err("%s: error %d while querying for an remote control " \ - "event", KBUILD_MODNAME, ret); + "event\n", KBUILD_MODNAME, ret); schedule_delayed_work(&d->rc_query_work, msecs_to_jiffies(d->rc.interval)); @@ -90,7 +90,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) /* initialize a work queue for handling polling */ INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); - pr_info("%s: schedule remote query interval to %d msecs", + pr_info("%s: schedule remote query interval to %d msecs\n", KBUILD_MODNAME, d->rc.interval); schedule_delayed_work(&d->rc_query_work, msecs_to_jiffies(d->rc.interval)); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index e28a4dc3cb04..f2dc6b928ebe 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -17,7 +17,7 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, return -EINVAL; if (d->props.generic_bulk_ctrl_endpoint == 0) { - pr_err("%s: endpoint for generic control not specified", + pr_err("%s: endpoint for generic control not specified\n", KBUILD_MODNAME); return -EINVAL; } @@ -34,7 +34,7 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, &actlen, 2000); if (ret) - pr_err("%s: bulk message failed: %d (%d/%d)", KBUILD_MODNAME, + pr_err("%s: bulk message failed: %d (%d/%d)\n", KBUILD_MODNAME, ret, wlen, actlen); else ret = actlen != wlen ? -1 : 0; @@ -51,7 +51,7 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, rbuf, rlen, &actlen, 2000); if (ret) - pr_err("%s: recv bulk message failed: %d", + pr_err("%s: recv bulk message failed: %d\n", KBUILD_MODNAME, ret); else print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": <<< ", diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c index baa2938db151..396c755c3ad0 100644 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -65,7 +65,7 @@ static void usb_urb_complete(struct urb *urb) stream->complete(stream, b, urb->actual_length); break; default: - pr_err("%s: unknown endpoint type in completition handler", + pr_err("%s: unknown endpoint type in completition handler\n", KBUILD_MODNAME); return; } @@ -100,7 +100,7 @@ int usb_urb_submit(struct usb_data_stream *stream, ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); if (ret) { pr_err("%s: could not submit URB no. %d - get them " \ - "all back", KBUILD_MODNAME, i); + "all back\n", KBUILD_MODNAME, i); usb_urb_kill(stream); return ret; } @@ -264,14 +264,14 @@ int usb_urb_reconfig(struct usb_data_stream *stream, } else if (props->type == USB_ISOC) { buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb; } else { - pr_err("%s: invalid endpoint type=%d", KBUILD_MODNAME, + pr_err("%s: invalid endpoint type=%d\n", KBUILD_MODNAME, props->type); return -EINVAL; } if (stream->buf_num < props->count || stream->buf_size < buf_size) { pr_err("%s: cannot reconfigure as allocated buffers are too " \ - "small", KBUILD_MODNAME); + "small\n", KBUILD_MODNAME); return -EINVAL; } @@ -320,7 +320,7 @@ int usb_urb_init(struct usb_data_stream *stream, if (stream->complete == NULL) { pr_err("%s: there is no data callback - this doesn't make " \ - "sense", KBUILD_MODNAME); + "sense\n", KBUILD_MODNAME); return -EINVAL; } @@ -341,7 +341,7 @@ int usb_urb_init(struct usb_data_stream *stream, return usb_urb_alloc_isoc_urbs(stream); default: - pr_err("%s: unknown URB-type for data transfer", + pr_err("%s: unknown URB-type for data transfer\n", KBUILD_MODNAME); return -EINVAL; } From 36a5c2bdedcba50435e1e9a9c62a99797783b2c4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Jun 2012 18:37:42 -0300 Subject: [PATCH 0246/5375] [media] dvb_usb_v2: fix dvb_usb_generic_rw() debug Debug prints write operation data instead of read data was intention. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index f2dc6b928ebe..a32722087a0c 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -55,7 +55,8 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, KBUILD_MODNAME, ret); else print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": <<< ", - DUMP_PREFIX_NONE, 32, 1, wbuf, wlen, 0); + DUMP_PREFIX_NONE, 32, 1, rbuf, actlen, + 0); } mutex_unlock(&d->usb_mutex); From 3238aafbc3f860d685fc96b5b93a2f14decaec2e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Jun 2012 21:11:28 -0300 Subject: [PATCH 0247/5375] [media] dvb_usb_v2: do not free resources until delayed init is done It was possible to free resources by unloading module while initialization was still ongoing on delayed work. Use PID to make decision on .disconnect() if caller is our work or some other as work also calls .disconnect() in error case. There could be better solution still... Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 1 + drivers/media/dvb/dvb-usb/dvb_usb_init.c | 21 ++++++++------------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 4394a5d6f161..79f8571b9b20 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -322,6 +322,7 @@ struct dvb_usb_device { struct dvb_usb_rc rc; struct usb_device *udev; struct work_struct probe_work; + pid_t work_pid; struct usb_interface *intf; #define DVB_USB_STATE_INIT 0x000 diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 0a452fc4edc8..9f75bb18ed17 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -266,10 +266,6 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } -/* - * USB - */ - /* * udev, which is used for the firmware downloading, requires we cannot * block during module_init(). module_init() calls USB probe() which @@ -284,7 +280,9 @@ static void dvb_usbv2_init_work(struct work_struct *work) container_of(work, struct dvb_usb_device, probe_work); bool cold = false; - pr_debug("%s:\n", __func__); + d->work_pid = current->pid; + + pr_debug("%s: work_pid=%d\n", __func__, d->work_pid); if (d->props.size_of_priv) { d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); @@ -405,15 +403,12 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) struct dvb_usb_device *d = usb_get_intfdata(intf); const char *name = "generic DVB-USB module"; - pr_debug("%s:\n", __func__); + pr_debug("%s: pid=%d work_pid=%d\n", __func__, current->pid, + d->work_pid); - /* - * FIXME: We should ensure initialization work is finished - * until exit from this routine (cancel_work_sync / flush_work). - * Unfortunately usb_driver_release_interface() call finally goes - * here too and in that case we endup deadlock. How to perform - * operation conditionally only on disconned / unload? - */ + /* ensure initialization work is finished until release resources */ + if (d->work_pid != current->pid) + cancel_work_sync(&d->probe_work); usb_set_intfdata(intf, NULL); if (d) { From 597843435c0a6421d687a5f7a1ce11548e7cd6e1 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 1 Aug 2012 14:44:06 -0300 Subject: [PATCH 0248/5375] [media] dvb_usb_v2: enable compile Compilation was disabled as it was failing with allyesconfig. Rename duplicate functions and enable building. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 15 ++++++ drivers/media/dvb/dvb-usb/Makefile | 3 ++ drivers/media/dvb/dvb-usb/dvb_usb_common.h | 28 +++++------ drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 24 +++++----- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 56 +++++++++++----------- drivers/media/dvb/dvb-usb/dvb_usb_remote.c | 8 ++-- drivers/media/dvb/dvb-usb/usb_urb.c | 12 ++--- 7 files changed, 82 insertions(+), 64 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index c2161565023a..a6ffdb322041 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -13,6 +13,21 @@ config DVB_USB Say Y if you own a USB DVB device. +config DVB_USB_V2 + tristate "Support for various USB DVB devices v2" + depends on DVB_CORE && USB && I2C && RC_CORE + help + By enabling this you will be able to choose the various supported + USB1.1 and USB2.0 DVB devices. + + Almost every USB device needs a firmware, please look into + . + + For a complete list of supported USB devices see the LinuxTV DVB Wiki: + + + Say Y if you own a USB DVB device. + config DVB_USB_DEBUG bool "Enable extended debug support for all DVB-USB devices" depends on DVB_USB diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index b667ac39a4e3..3c73e7b2a9f8 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -1,6 +1,9 @@ dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o obj-$(CONFIG_DVB_USB) += dvb-usb.o +dvb_usbv2-objs = dvb_usb_init.o dvb_usb_urb.o dvb_usb_dvb.o dvb_usb_remote.o usb_urb.o +obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o + dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index c3035a154860..dcdccb7fde31 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -11,27 +11,27 @@ #include "dvb_usb.h" -extern int dvb_usb_disable_rc_polling; +extern int dvb_usbv2_disable_rc_polling; /* commonly used methods */ -extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff); +extern int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff); -extern int usb_urb_init(struct usb_data_stream *stream, +extern int usb_urb_initv2(struct usb_data_stream *stream, struct usb_data_stream_properties *props); -extern int usb_urb_exit(struct usb_data_stream *stream); -extern int usb_urb_submit(struct usb_data_stream *stream, +extern int usb_urb_exitv2(struct usb_data_stream *stream); +extern int usb_urb_submitv2(struct usb_data_stream *stream, struct usb_data_stream_properties *props); -extern int usb_urb_kill(struct usb_data_stream *stream); +extern int usb_urb_killv2(struct usb_data_stream *stream); -extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap); -extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap); +extern int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap); +extern int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap); -extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap); -extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap); -extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap); -extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap); +extern int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap); +extern int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap); +extern int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap); +extern int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap); -extern int dvb_usb_remote_init(struct dvb_usb_device *); -extern int dvb_usb_remote_exit(struct dvb_usb_device *); +extern int dvb_usbv2_remote_init(struct dvb_usb_device *); +extern int dvb_usbv2_remote_exit(struct dvb_usb_device *); #endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index a2ec0427f833..a08d879fd177 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -32,7 +32,7 @@ static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, dvb_dmx_swfilter_raw(&adap->demux, buffer, length); } -int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) +int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) { int ret; struct usb_data_stream_properties stream_props; @@ -53,12 +53,12 @@ int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) /* FIXME: can be removed as set later in anyway */ adap->stream.complete = dvb_usb_data_complete; - return usb_urb_init(&adap->stream, &stream_props); + return usb_urb_initv2(&adap->stream, &stream_props); } -int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) +int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) { - usb_urb_exit(&adap->stream); + usb_urb_exitv2(&adap->stream); return 0; } @@ -78,7 +78,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) /* stop feed before setting a new pid if there will be no pid anymore */ if (newfeedcount == 0) { pr_debug("%s: stop feeding\n", __func__); - usb_urb_kill(&adap->stream); + usb_urb_killv2(&adap->stream); if (adap->props.streaming_ctrl != NULL) { ret = adap->props.streaming_ctrl(adap, 0); @@ -141,7 +141,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) pr_debug("%s: submitting all URBs\n", __func__); - usb_urb_submit(&adap->stream, &stream_props); + usb_urb_submitv2(&adap->stream, &stream_props); pr_debug("%s: controlling pid parser\n", __func__); if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && @@ -187,7 +187,7 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) return dvb_usb_ctrl_feed(dvbdmxfeed, 0); } -int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap) +int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) { int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->name, adap->dev->props.owner, @@ -256,7 +256,7 @@ err: return ret; } -int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) +int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) { if (adap->state & DVB_USB_ADAP_STATE_DVB) { pr_debug("%s: unregistering DVB part\n", __func__); @@ -275,7 +275,7 @@ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) int ret; struct dvb_usb_adapter *adap = fe->dvb->priv; - ret = dvb_usb_device_power_ctrl(adap->dev, 1); + ret = dvb_usbv2_device_power_ctrl(adap->dev, 1); if (ret < 0) goto err; @@ -316,7 +316,7 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) goto err; } - ret = dvb_usb_device_power_ctrl(adap->dev, 0); + ret = dvb_usbv2_device_power_ctrl(adap->dev, 0); if (ret < 0) goto err; @@ -328,7 +328,7 @@ err: return ret; } -int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) +int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) { int ret, i, count_registered = 0; @@ -397,7 +397,7 @@ err: return ret; } -int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) +int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) { int i; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 9f75bb18ed17..c98712a29133 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -13,8 +13,8 @@ */ #include "dvb_usb_common.h" -int dvb_usb_disable_rc_polling; -module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); +int dvb_usbv2_disable_rc_polling; +module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644); MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); @@ -24,7 +24,7 @@ module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a" \ " PID filter, if any (default: 0)."); -int dvb_usb_download_firmware(struct dvb_usb_device *d) +int dvb_usbv2_download_firmware(struct dvb_usb_device *d) { int ret; const struct firmware *fw = NULL; @@ -68,7 +68,7 @@ err: return ret; } -int dvb_usb_i2c_init(struct dvb_usb_device *d) +int dvb_usbv2_i2c_init(struct dvb_usb_device *d) { int ret = 0; @@ -91,7 +91,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) return ret; } -int dvb_usb_i2c_exit(struct dvb_usb_device *d) +int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) { if (d->state & DVB_USB_STATE_I2C) i2c_del_adapter(&d->i2c_adap); @@ -99,7 +99,7 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d) return 0; } -static int dvb_usb_adapter_init(struct dvb_usb_device *d) +static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) { struct dvb_usb_adapter *adap; int ret, n, adapter_count; @@ -154,15 +154,15 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d) adap->max_feed_count = adap->props.pid_filter_count; } - ret = dvb_usb_adapter_stream_init(adap); + ret = dvb_usbv2_adapter_stream_init(adap); if (ret) return ret; - ret = dvb_usb_adapter_dvb_init(adap); + ret = dvb_usbv2_adapter_dvb_init(adap); if (ret) return ret; - ret = dvb_usb_adapter_frontend_init(adap); + ret = dvb_usbv2_adapter_frontend_init(adap); if (ret) return ret; @@ -180,14 +180,14 @@ err: return ret; } -static int dvb_usb_adapter_exit(struct dvb_usb_device *d) +static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) { int n; for (n = 0; n < d->num_adapters_initialized; n++) { - dvb_usb_adapter_frontend_exit(&d->adapter[n]); - dvb_usb_adapter_dvb_exit(&d->adapter[n]); - dvb_usb_adapter_stream_exit(&d->adapter[n]); + dvb_usbv2_adapter_frontend_exit(&d->adapter[n]); + dvb_usbv2_adapter_dvb_exit(&d->adapter[n]); + dvb_usbv2_adapter_stream_exit(&d->adapter[n]); } d->num_adapters_initialized = 0; @@ -196,12 +196,12 @@ static int dvb_usb_adapter_exit(struct dvb_usb_device *d) } /* general initialization functions */ -static int dvb_usb_exit(struct dvb_usb_device *d) +static int dvb_usbv2_exit(struct dvb_usb_device *d) { pr_debug("%s: state before exiting everything: %x\n", __func__, d->state); - dvb_usb_remote_exit(d); - dvb_usb_adapter_exit(d); - dvb_usb_i2c_exit(d); + dvb_usbv2_remote_exit(d); + dvb_usbv2_adapter_exit(d); + dvb_usbv2_i2c_exit(d); pr_debug("%s: state should be zero now: %x\n", __func__, d->state); d->state = DVB_USB_STATE_INIT; kfree(d->priv); @@ -209,14 +209,14 @@ static int dvb_usb_exit(struct dvb_usb_device *d) return 0; } -static int dvb_usb_init(struct dvb_usb_device *d) +static int dvb_usbv2_init(struct dvb_usb_device *d) { int ret = 0; d->state = DVB_USB_STATE_INIT; /* check the capabilities and set appropriate variables */ - dvb_usb_device_power_ctrl(d, 1); + dvb_usbv2_device_power_ctrl(d, 1); /* read config */ if (d->props.read_config) { @@ -225,24 +225,24 @@ static int dvb_usb_init(struct dvb_usb_device *d) goto err; } - ret = dvb_usb_i2c_init(d); + ret = dvb_usbv2_i2c_init(d); if (ret == 0) - ret = dvb_usb_adapter_init(d); + ret = dvb_usbv2_adapter_init(d); if (ret) { - dvb_usb_exit(d); + dvb_usbv2_exit(d); return ret; } if (d->props.init) d->props.init(d); - ret = dvb_usb_remote_init(d); + ret = dvb_usbv2_remote_init(d); if (ret) pr_err("%s: could not initialize remote control\n", KBUILD_MODNAME); - dvb_usb_device_power_ctrl(d, 0); + dvb_usbv2_device_power_ctrl(d, 0); return 0; err: @@ -250,7 +250,7 @@ err: return ret; } -int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) +int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) { if (onoff) d->powered++; @@ -308,7 +308,7 @@ static void dvb_usbv2_init_work(struct work_struct *work) if (cold) { pr_info("%s: found a '%s' in cold state\n", KBUILD_MODNAME, d->name); - ret = dvb_usb_download_firmware(d); + ret = dvb_usbv2_download_firmware(d); if (ret == 0) { ; } else if (ret == RECONNECTS_USB) { @@ -321,7 +321,7 @@ static void dvb_usbv2_init_work(struct work_struct *work) pr_info("%s: found a '%s' in warm state\n", KBUILD_MODNAME, d->name); - ret = dvb_usb_init(d); + ret = dvb_usbv2_init(d); if (ret < 0) goto err_usb_driver_release_interface; @@ -413,7 +413,7 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (d) { name = d->name; - dvb_usb_exit(d); + dvb_usbv2_exit(d); } pr_info("%s: '%s' successfully deinitialized and disconnected\n", diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c index 8c7f1221f89a..4b7cd0e29bfa 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c @@ -26,7 +26,7 @@ static void dvb_usb_read_remote_control(struct work_struct *work) /* when the parameter has been set to 1 via sysfs while the * driver was running, or when bulk mode is enabled after IR init */ - if (dvb_usb_disable_rc_polling || d->rc.bulk_mode) + if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) return; ret = d->rc.query(d); @@ -38,12 +38,12 @@ static void dvb_usb_read_remote_control(struct work_struct *work) msecs_to_jiffies(d->rc.interval)); } -int dvb_usb_remote_init(struct dvb_usb_device *d) +int dvb_usbv2_remote_init(struct dvb_usb_device *d) { int ret; struct rc_dev *dev; - if (dvb_usb_disable_rc_polling || !d->props.get_rc_config) + if (dvb_usbv2_disable_rc_polling || !d->props.get_rc_config) return 0; ret = d->props.get_rc_config(d, &d->rc); @@ -104,7 +104,7 @@ err: return ret; } -int dvb_usb_remote_exit(struct dvb_usb_device *d) +int dvb_usbv2_remote_exit(struct dvb_usb_device *d) { if (d->state & DVB_USB_STATE_REMOTE) { cancel_delayed_work_sync(&d->rc_query_work); diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c index 396c755c3ad0..16e9fa03c847 100644 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -72,7 +72,7 @@ static void usb_urb_complete(struct urb *urb) usb_submit_urb(urb, GFP_ATOMIC); } -int usb_urb_kill(struct usb_data_stream *stream) +int usb_urb_killv2(struct usb_data_stream *stream) { int i; for (i = 0; i < stream->urbs_submitted; i++) { @@ -84,7 +84,7 @@ int usb_urb_kill(struct usb_data_stream *stream) return 0; } -int usb_urb_submit(struct usb_data_stream *stream, +int usb_urb_submitv2(struct usb_data_stream *stream, struct usb_data_stream_properties *props) { int i, ret; @@ -101,7 +101,7 @@ int usb_urb_submit(struct usb_data_stream *stream, if (ret) { pr_err("%s: could not submit URB no. %d - get them " \ "all back\n", KBUILD_MODNAME, i); - usb_urb_kill(stream); + usb_urb_killv2(stream); return ret; } stream->urbs_submitted++; @@ -113,7 +113,7 @@ int usb_urb_free_urbs(struct usb_data_stream *stream) { int i; - usb_urb_kill(stream); + usb_urb_killv2(stream); for (i = 0; i < stream->urbs_initialized; i++) { if (stream->urb_list[i] != NULL) { @@ -305,7 +305,7 @@ int usb_urb_reconfig(struct usb_data_stream *stream, return 0; } -int usb_urb_init(struct usb_data_stream *stream, +int usb_urb_initv2(struct usb_data_stream *stream, struct usb_data_stream_properties *props) { int ret; @@ -347,7 +347,7 @@ int usb_urb_init(struct usb_data_stream *stream, } } -int usb_urb_exit(struct usb_data_stream *stream) +int usb_urb_exitv2(struct usb_data_stream *stream) { usb_urb_free_urbs(stream); usb_free_stream_buffers(stream); From a3645e5430dbcc1b4116bd5add450c5bba9b6c45 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Jun 2012 20:36:35 -0300 Subject: [PATCH 0249/5375] [media] af9015: switch to new DVB-USB Almost all hacks are now removed and much less code. Reducing af9015 driver code from 2084 to 1609, it is almost 500 LOC less! Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 +- drivers/media/dvb/dvb-usb/af9015.c | 2318 +++++++++++----------------- drivers/media/dvb/dvb-usb/af9015.h | 67 +- 3 files changed, 956 insertions(+), 1431 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index a6ffdb322041..2f6973a24cc6 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -341,7 +341,7 @@ config DVB_USB_DTV5100 config DVB_USB_AF9015 tristate "Afatech AF9015 DVB-T USB2.0 support" - depends on DVB_USB + depends on DVB_USB_V2 select DVB_AF9013 select DVB_PLL if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 677fed79b01e..fe5ef3a03edc 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -21,18 +21,7 @@ * */ -#include -#include - #include "af9015.h" -#include "af9013.h" -#include "mt2060.h" -#include "qt1010.h" -#include "tda18271.h" -#include "mxl5005s.h" -#include "mc44s803.h" -#include "tda18218.h" -#include "mxl5007t.h" static int dvb_usb_af9015_debug; module_param_named(debug, dvb_usb_af9015_debug, int, 0644); @@ -42,44 +31,18 @@ module_param_named(remote, dvb_usb_af9015_remote, int, 0644); MODULE_PARM_DESC(remote, "select remote"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static DEFINE_MUTEX(af9015_usb_mutex); - -static struct af9015_config af9015_config; -static struct dvb_usb_device_properties af9015_properties[3]; -static int af9015_properties_count = ARRAY_SIZE(af9015_properties); - -static struct af9013_config af9015_af9013_config[] = { - { - .i2c_addr = AF9015_I2C_DEMOD, - .ts_mode = AF9013_TS_USB, - .api_version = { 0, 1, 9, 0 }, - .gpio[0] = AF9013_GPIO_HI, - .gpio[3] = AF9013_GPIO_TUNER_ON, - - }, { - .ts_mode = AF9013_TS_SERIAL, - .api_version = { 0, 1, 9, 0 }, - .gpio[0] = AF9013_GPIO_TUNER_ON, - .gpio[1] = AF9013_GPIO_LO, - } -}; - -static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) +static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) { #define BUF_LEN 63 #define REQ_HDR_LEN 8 /* send header size */ #define ACK_HDR_LEN 2 /* rece header size */ - int act_len, ret; + struct af9015_state *state = d->priv; + int ret, wlen, rlen; u8 buf[BUF_LEN]; u8 write = 1; - u8 msg_len = REQ_HDR_LEN; - static u8 seq; /* packet sequence number */ - - if (mutex_lock_interruptible(&af9015_usb_mutex) < 0) - return -EAGAIN; buf[0] = req->cmd; - buf[1] = seq++; + buf[1] = state->seq++; buf[2] = req->i2c_addr; buf[3] = req->addr >> 8; buf[4] = req->addr & 0xff; @@ -111,7 +74,7 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) default: err("unknown command:%d", req->cmd); ret = -1; - goto error_unlock; + goto error; } /* buffer overflow check */ @@ -119,73 +82,42 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { err("too much data; cmd:%d len:%d", req->cmd, req->data_len); ret = -EINVAL; - goto error_unlock; + goto error; } - /* write requested */ - if (write) { - memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len); - msg_len += req->data_len; - } - - deb_xfer(">>> "); - debug_dump(buf, msg_len, deb_xfer); - - /* send req */ - ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, - &act_len, AF9015_USB_TIMEOUT); - if (ret) - err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len); - else - if (act_len != msg_len) - ret = -1; /* all data is not send */ - if (ret) - goto error_unlock; - - /* no ack for those packets */ - if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) - goto exit_unlock; - /* write receives seq + status = 2 bytes read receives seq + status + data = 2 + N bytes */ - msg_len = ACK_HDR_LEN; - if (!write) - msg_len += req->data_len; - - ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, - &act_len, AF9015_USB_TIMEOUT); - if (ret) { - err("recv bulk message failed:%d", ret); - ret = -1; - goto error_unlock; + wlen = REQ_HDR_LEN; + rlen = ACK_HDR_LEN; + if (write) { + wlen += req->data_len; + memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len); + } else { + rlen += req->data_len; } - deb_xfer("<<< "); - debug_dump(buf, act_len, deb_xfer); + /* no ack for these packets */ + if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) + rlen = 0; + + ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen, 0); + if (ret) + goto error; /* check status */ - if (buf[1]) { + if (rlen && buf[1]) { err("command failed:%d", buf[1]); ret = -1; - goto error_unlock; + goto error; } /* read request, copy returned data to return buf */ if (!write) memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len); - -error_unlock: -exit_unlock: - mutex_unlock(&af9015_usb_mutex); - +error: return ret; } -static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) -{ - return af9015_rw_udev(d->udev, req); -} - static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) { @@ -194,11 +126,6 @@ static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, return af9015_ctrl_msg(d, &req); } -static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) -{ - return af9015_write_regs(d, addr, &val, 1); -} - static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) { struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, @@ -206,6 +133,11 @@ static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) return af9015_ctrl_msg(d, &req); } +static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) +{ + return af9015_write_regs(d, addr, &val, 1); +} + static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) { return af9015_read_regs(d, addr, val, 1); @@ -214,10 +146,11 @@ static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, u8 val) { + struct af9015_state *state = d->priv; struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; - if (addr == af9015_af9013_config[0].i2c_addr || - addr == af9015_af9013_config[1].i2c_addr) + if (addr == state->af9013_config[0].i2c_addr || + addr == state->af9013_config[1].i2c_addr) req.addr_len = 3; return af9015_ctrl_msg(d, &req); @@ -226,19 +159,53 @@ static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, u8 *val) { + struct af9015_state *state = d->priv; struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; - if (addr == af9015_af9013_config[0].i2c_addr || - addr == af9015_af9013_config[1].i2c_addr) + if (addr == state->af9013_config[0].i2c_addr || + addr == state->af9013_config[1].i2c_addr) req.addr_len = 3; return af9015_ctrl_msg(d, &req); } +static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) +{ + int ret; + u8 val, mask = 0x01; + + ret = af9015_read_reg(d, addr, &val); + if (ret) + return ret; + + mask <<= bit; + if (op) { + /* set bit */ + val |= mask; + } else { + /* clear bit */ + mask ^= 0xff; + val &= mask; + } + + return af9015_write_reg(d, addr, val); +} + +static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 1); +} + +static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) +{ + return af9015_do_reg_bit(d, addr, bit, 0); +} + static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct af9015_state *state = d->priv; int ret = 0, i = 0; u16 addr; u8 uninitialized_var(mbox), addr_len; @@ -270,8 +237,8 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. return -EAGAIN; while (i < num) { - if (msg[i].addr == af9015_af9013_config[0].i2c_addr || - msg[i].addr == af9015_af9013_config[1].i2c_addr) { + if (msg[i].addr == state->af9013_config[0].i2c_addr || + msg[i].addr == state->af9013_config[1].i2c_addr) { addr = msg[i].buf[0] << 8; addr += msg[i].buf[1]; mbox = msg[i].buf[2]; @@ -287,7 +254,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto error; } - if (msg[i].addr == af9015_af9013_config[0].i2c_addr) + if (msg[i].addr == state->af9013_config[0].i2c_addr) req.cmd = READ_MEMORY; else req.cmd = READ_I2C; @@ -304,8 +271,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto error; } - if (msg[i].addr == - af9015_af9013_config[0].i2c_addr) { + if (msg[i].addr == state->af9013_config[0].i2c_addr) { ret = -EINVAL; goto error; } @@ -323,7 +289,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto error; } - if (msg[i].addr == af9015_af9013_config[0].i2c_addr) + if (msg[i].addr == state->af9013_config[0].i2c_addr) req.cmd = WRITE_MEMORY; else req.cmd = WRITE_I2C; @@ -358,137 +324,419 @@ static struct i2c_algorithm af9015_i2c_algo = { .functionality = af9015_i2c_func, }; -static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) +static int af9015_identify_state(struct dvb_usb_device *d) { int ret; - u8 val, mask = 0x01; + u8 reply; + struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; - ret = af9015_read_reg(d, addr, &val); + ret = af9015_ctrl_msg(d, &req); if (ret) return ret; - mask <<= bit; - if (op) { - /* set bit */ - val |= mask; - } else { - /* clear bit */ - mask ^= 0xff; - val &= mask; - } - - return af9015_write_reg(d, addr, val); -} - -static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 1); -} - -static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 0); -} - -static int af9015_init_endpoint(struct dvb_usb_device *d) -{ - int ret; - u16 frame_size; - u8 packet_size; - deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); - - /* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0. - We use smaller - about 1/4 from the original, 5 and 87. */ -#define TS_PACKET_SIZE 188 - -#define TS_USB20_PACKET_COUNT 87 -#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) - -#define TS_USB11_PACKET_COUNT 5 -#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) - -#define TS_USB20_MAX_PACKET_SIZE 512 -#define TS_USB11_MAX_PACKET_SIZE 64 - - if (d->udev->speed == USB_SPEED_FULL) { - frame_size = TS_USB11_FRAME_SIZE/4; - packet_size = TS_USB11_MAX_PACKET_SIZE/4; - } else { - frame_size = TS_USB20_FRAME_SIZE/4; - packet_size = TS_USB20_MAX_PACKET_SIZE/4; - } - - ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ - if (ret) - goto error; - ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ - if (ret) - goto error; - if (af9015_config.dual_mode) { - ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ - if (ret) - goto error; - } - ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ - if (ret) - goto error; - if (af9015_config.dual_mode) { - ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ - if (ret) - goto error; - } - /* EP4 xfer length */ - ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); - if (ret) - goto error; - /* EP5 xfer length */ - ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ - if (ret) - goto error; - ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ - if (ret) - goto error; - ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ - if (ret) - goto error; - if (af9015_config.dual_mode) { - ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ - if (ret) - goto error; - } - - /* enable / disable mp2if2 */ - if (af9015_config.dual_mode) - ret = af9015_set_reg_bit(d, 0xd50b, 0); + deb_info("%s: reply:%02x\n", __func__, reply); + if (reply == 0x02) + ret = WARM; else - ret = af9015_clear_reg_bit(d, 0xd50b, 0); + ret = COLD; + + return ret; +} + +static int af9015_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + struct af9015_state *state = d->priv; + int i, len, remaining, ret; + struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; + u16 checksum = 0; + + deb_info("%s:\n", __func__); + + /* calc checksum */ + for (i = 0; i < fw->size; i++) + checksum += fw->data[i]; + + state->firmware_size = fw->size; + state->firmware_checksum = checksum; + + #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[fw->size - remaining]; + req.addr = FW_ADDR + fw->size - remaining; + + ret = af9015_ctrl_msg(d, &req); + if (ret) { + err("firmware download failed:%d", ret); + goto error; + } + } + + /* firmware loaded, request boot */ + req.cmd = BOOT; + req.data_len = 0; + ret = af9015_ctrl_msg(d, &req); + if (ret) { + err("firmware boot failed:%d", ret); + goto error; + } + +error: + return ret; +} + +/* hash (and dump) eeprom */ +static int af9015_eeprom_hash(struct dvb_usb_device *d) +{ + struct af9015_state *state = d->priv; + int ret; + static const unsigned int eeprom_size = 256; + unsigned int reg; + u8 val, *eeprom; + struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; + + eeprom = kmalloc(eeprom_size, GFP_KERNEL); + if (eeprom == NULL) + return -ENOMEM; + + for (reg = 0; reg < eeprom_size; reg++) { + req.addr = reg; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto free; + + eeprom[reg] = val; + } + + if (dvb_usb_af9015_debug & 0x01) + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom, + eeprom_size); + + BUG_ON(eeprom_size % 4); + + state->eeprom_sum = 0; + for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) { + state->eeprom_sum *= GOLDEN_RATIO_PRIME_32; + state->eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]); + } + + deb_info("%s: eeprom sum=%.8x\n", __func__, state->eeprom_sum); + + ret = 0; +free: + kfree(eeprom); + return ret; +} + +static int af9015_read_config(struct dvb_usb_device *d) +{ + struct af9015_state *state = d->priv; + int ret; + u8 val, i, offset = 0; + struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; + + deb_info("%s:\n", __func__); + + /* IR remote controller */ + req.addr = AF9015_EEPROM_IR_MODE; + /* first message will timeout often due to possible hw bug */ + for (i = 0; i < 4; i++) { + ret = af9015_ctrl_msg(d, &req); + if (!ret) + break; + } + if (ret) + goto error; + + ret = af9015_eeprom_hash(d); + if (ret) + goto error; + + deb_info("%s: IR mode=%d\n", __func__, val); + state->ir_mode = val; + + /* TS mode - one or two receivers */ + req.addr = AF9015_EEPROM_TS_MODE; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->dual_mode = val; + deb_info("%s: TS mode=%d\n", __func__, state->dual_mode); + + /* disable 2nd adapter because we don't have PID-filters */ + if (d->udev->speed == USB_SPEED_FULL) + state->dual_mode = 0; + + if (state->dual_mode) { + /* read 2nd demodulator I2C address */ + req.addr = AF9015_EEPROM_DEMOD2_I2C; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->af9013_config[1].i2c_addr = val; + } + + for (i = 0; i < state->dual_mode + 1; i++) { + if (i == 1) + offset = AF9015_EEPROM_OFFSET; + /* xtal */ + req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + switch (val) { + case 0: + state->af9013_config[i].clock = 28800000; + break; + case 1: + state->af9013_config[i].clock = 20480000; + break; + case 2: + state->af9013_config[i].clock = 28000000; + break; + case 3: + state->af9013_config[i].clock = 25000000; + break; + }; + deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i, + val, state->af9013_config[i].clock); + + /* IF frequency */ + req.addr = AF9015_EEPROM_IF1H + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->af9013_config[i].if_frequency = val << 8; + + req.addr = AF9015_EEPROM_IF1L + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + + state->af9013_config[i].if_frequency += val; + state->af9013_config[i].if_frequency *= 1000; + deb_info("%s: [%d] IF frequency=%d\n", __func__, i, + state->af9013_config[i].if_frequency); + + /* MT2060 IF1 */ + req.addr = AF9015_EEPROM_MT2060_IF1H + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + state->mt2060_if1[i] = val << 8; + req.addr = AF9015_EEPROM_MT2060_IF1L + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + state->mt2060_if1[i] += val; + deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i, + state->mt2060_if1[i]); + + /* tuner */ + req.addr = AF9015_EEPROM_TUNER_ID1 + offset; + ret = af9015_ctrl_msg(d, &req); + if (ret) + goto error; + switch (val) { + case AF9013_TUNER_ENV77H11D5: + case AF9013_TUNER_MT2060: + case AF9013_TUNER_QT1010: + case AF9013_TUNER_UNKNOWN: + case AF9013_TUNER_MT2060_2: + case AF9013_TUNER_TDA18271: + case AF9013_TUNER_QT1010A: + case AF9013_TUNER_TDA18218: + state->af9013_config[i].spec_inv = 1; + break; + case AF9013_TUNER_MXL5003D: + case AF9013_TUNER_MXL5005D: + case AF9013_TUNER_MXL5005R: + case AF9013_TUNER_MXL5007T: + state->af9013_config[i].spec_inv = 0; + break; + case AF9013_TUNER_MC44S803: + state->af9013_config[i].gpio[1] = AF9013_GPIO_LO; + state->af9013_config[i].spec_inv = 1; + break; + default: + warn("tuner id=%d not supported, please report!", val); + return -ENODEV; + }; + + state->af9013_config[i].tuner = val; + deb_info("%s: [%d] tuner id=%d\n", __func__, i, val); + } error: if (ret) - err("endpoint init failed:%d", ret); + err("eeprom read failed=%d", ret); + + /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM + content :-( Override some wrong values here. Ditto for the + AVerTV Red HD+ (A850T) device. */ + if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA && + ((le16_to_cpu(d->udev->descriptor.idProduct) == + USB_PID_AVERMEDIA_A850) || + (le16_to_cpu(d->udev->descriptor.idProduct) == + USB_PID_AVERMEDIA_A850T))) { + deb_info("%s: AverMedia A850: overriding config\n", __func__); + /* disable dual mode */ + state->dual_mode = 0; + + /* set correct IF */ + state->af9013_config[0].if_frequency = 4570000; + } + + return ret; +} + +static int af9015_get_usb_stream_config(struct dvb_frontend *fe, + struct usb_data_stream_properties *stream) +{ + struct dvb_usb_adapter *adap; + + deb_info("%s: fe=%p\n", __func__, fe); + + stream->type = USB_BULK; + stream->count = 8; + stream->endpoint = 0x84; + stream->u.bulk.buffersize = TS_USB20_FRAME_SIZE; + + if (fe == NULL) + return 0; + + adap = fe->dvb->priv; + + if (adap->id == 1) + stream->endpoint = 0x85; + + if (adap->dev->udev->speed == USB_SPEED_FULL) + stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE; + + return 0; +} + +static int af9015_get_adapter_count(struct dvb_usb_device *d) +{ + struct af9015_state *state = d->priv; + return state->dual_mode + 1; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_set_frontend(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *state = adap->dev->priv; + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->set_frontend[adap->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *state = adap->dev->priv; + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->read_status[adap->id](fe, status); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_init(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *state = adap->dev->priv; + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->init[adap->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_sleep(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *state = adap->dev->priv; + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->sleep[adap->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override tuner callbacks for resource locking */ +static int af9015_tuner_init(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *state = adap->dev->priv; + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->tuner_init[adap->id](fe); + + mutex_unlock(&state->fe_mutex); + + return ret; +} + +/* override tuner callbacks for resource locking */ +static int af9015_tuner_sleep(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *state = adap->dev->priv; + + if (mutex_lock_interruptible(&state->fe_mutex)) + return -EAGAIN; + + ret = state->tuner_sleep[adap->id](fe); + + mutex_unlock(&state->fe_mutex); + return ret; } static int af9015_copy_firmware(struct dvb_usb_device *d) { + struct af9015_state *state = d->priv; int ret; u8 fw_params[4]; u8 val, i; @@ -496,16 +744,16 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) fw_params }; deb_info("%s:\n", __func__); - fw_params[0] = af9015_config.firmware_size >> 8; - fw_params[1] = af9015_config.firmware_size & 0xff; - fw_params[2] = af9015_config.firmware_checksum >> 8; - fw_params[3] = af9015_config.firmware_checksum & 0xff; + fw_params[0] = state->firmware_size >> 8; + fw_params[1] = state->firmware_size & 0xff; + fw_params[2] = state->firmware_checksum >> 8; + fw_params[3] = state->firmware_checksum & 0xff; /* wait 2nd demodulator ready */ msleep(100); - ret = af9015_read_reg_i2c(d, - af9015_af9013_config[1].i2c_addr, 0x98be, &val); + ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, + 0x98be, &val); if (ret) goto error; else @@ -533,8 +781,8 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) goto error; /* request boot firmware */ - ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].i2c_addr, - 0xe205, 1); + ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr, + 0xe205, 1); deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); if (ret) goto error; @@ -543,8 +791,8 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) msleep(100); /* check firmware status */ - ret = af9015_read_reg_i2c(d, - af9015_af9013_config[1].i2c_addr, 0x98be, &val); + ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, + 0x98be, &val); deb_info("%s: firmware status cmd status:%d fw status:%02x\n", __func__, ret, val); if (ret) @@ -567,650 +815,29 @@ exit: return ret; } -/* hash (and dump) eeprom */ -static int af9015_eeprom_hash(struct usb_device *udev) -{ - static const unsigned int eeprom_size = 256; - unsigned int reg; - int ret; - u8 val, *eeprom; - struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; - - eeprom = kmalloc(eeprom_size, GFP_KERNEL); - if (eeprom == NULL) - return -ENOMEM; - - for (reg = 0; reg < eeprom_size; reg++) { - req.addr = reg; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto free; - eeprom[reg] = val; - } - - if (dvb_usb_af9015_debug & 0x01) - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom, - eeprom_size); - - BUG_ON(eeprom_size % 4); - - af9015_config.eeprom_sum = 0; - for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) { - af9015_config.eeprom_sum *= GOLDEN_RATIO_PRIME_32; - af9015_config.eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]); - } - - deb_info("%s: eeprom sum=%.8x\n", __func__, af9015_config.eeprom_sum); - - ret = 0; -free: - kfree(eeprom); - return ret; -} - -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; - -error: - return ret; -} - -static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) -{ - int ret; - deb_info("%s: onoff:%d\n", __func__, onoff); - - if (onoff) - ret = af9015_set_reg_bit(adap->dev, 0xd503, 0); - else - ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0); - - return ret; -} - -static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) -{ - int ret; - u8 idx; - - deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", - __func__, index, pid, onoff); - - ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff)); - if (ret) - goto error; - - ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8)); - if (ret) - goto error; - - idx = ((index & 0x1f) | (1 << 5)); - ret = af9015_write_reg(adap->dev, 0xd504, idx); - -error: - return ret; -} - -static int af9015_download_firmware(struct usb_device *udev, - const struct firmware *fw) -{ - int i, len, remaining, ret; - struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; - u16 checksum = 0; - - deb_info("%s:\n", __func__); - - /* calc checksum */ - for (i = 0; i < fw->size; i++) - checksum += fw->data[i]; - - af9015_config.firmware_size = fw->size; - af9015_config.firmware_checksum = checksum; - - #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[fw->size - remaining]; - req.addr = FW_ADDR + fw->size - remaining; - - ret = af9015_rw_udev(udev, &req); - if (ret) { - err("firmware download failed:%d", ret); - goto error; - } - } - - /* firmware loaded, request boot */ - req.cmd = BOOT; - ret = af9015_rw_udev(udev, &req); - if (ret) { - err("firmware boot failed:%d", ret); - goto error; - } - -error: - return ret; -} - -struct af9015_rc_setup { - unsigned int id; - char *rc_codes; -}; - -static char *af9015_rc_setup_match(unsigned int id, - const struct af9015_rc_setup *table) -{ - for (; table->rc_codes; table++) - if (table->id == id) - return table->rc_codes; - return NULL; -} - -static const struct af9015_rc_setup af9015_rc_setup_modparam[] = { - { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M }, - { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II }, - { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND }, - { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE }, - { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS }, - { } -}; - -static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { - { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II }, - { 0xa3703d00, RC_MAP_ALINK_DTU_M }, - { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */ - { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */ - { } -}; - -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, - RC_MAP_AZUREWAVE_AD_TU700 }, - { (USB_VID_VISIONPLUS << 16) | USB_PID_TINYTWIN, - RC_MAP_AZUREWAVE_AD_TU700 }, - { (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGI_VOX_MINI_III, - RC_MAP_MSI_DIGIVOX_III }, - { (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGIVOX_DUO, - RC_MAP_MSI_DIGIVOX_III }, - { (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV_DONGLE_GOLD, - RC_MAP_LEADTEK_Y04G0051 }, - { (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV2000DS, - RC_MAP_LEADTEK_Y04G0051 }, - { (USB_VID_AVERMEDIA << 16) | USB_PID_AVERMEDIA_VOLAR_X, - RC_MAP_AVERMEDIA_M135A }, - { (USB_VID_AFATECH << 16) | USB_PID_TREKSTOR_DVBT, - RC_MAP_TREKSTOR }, - { (USB_VID_KWORLD_2 << 16) | USB_PID_TINYTWIN_2, - RC_MAP_DIGITALNOW_TINYTWIN }, - { (USB_VID_GTEK << 16) | USB_PID_TINYTWIN_3, - RC_MAP_DIGITALNOW_TINYTWIN }, - { (USB_VID_KWORLD_2 << 16) | USB_PID_SVEON_STV22, - RC_MAP_MSI_DIGIVOX_III }, - { } -}; - -static void af9015_set_remote_config(struct usb_device *udev, - struct dvb_usb_device_properties *props) -{ - u16 vid = le16_to_cpu(udev->descriptor.idVendor); - u16 pid = le16_to_cpu(udev->descriptor.idProduct); - - /* try to load remote based module param */ - props->rc.core.rc_codes = af9015_rc_setup_match( - dvb_usb_af9015_remote, af9015_rc_setup_modparam); - - /* try to load remote based eeprom hash */ - if (!props->rc.core.rc_codes) - props->rc.core.rc_codes = af9015_rc_setup_match( - af9015_config.eeprom_sum, af9015_rc_setup_hashes); - - /* try to load remote based USB ID */ - if (!props->rc.core.rc_codes) - props->rc.core.rc_codes = af9015_rc_setup_match( - (vid << 16) | pid, af9015_rc_setup_usbids); - - /* try to load remote based USB iManufacturer string */ - if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) { - /* Check USB manufacturer and product strings and try - to determine correct remote in case of chip vendor - reference IDs are used. - DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */ - char manufacturer[10]; - memset(manufacturer, 0, sizeof(manufacturer)); - usb_string(udev, udev->descriptor.iManufacturer, - manufacturer, sizeof(manufacturer)); - if (!strcmp("MSI", manufacturer)) { - /* iManufacturer 1 MSI - iProduct 2 MSI K-VOX */ - props->rc.core.rc_codes = af9015_rc_setup_match( - AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, - af9015_rc_setup_modparam); - } - } - - /* finally load "empty" just for leaving IR receiver enabled */ - if (!props->rc.core.rc_codes) - props->rc.core.rc_codes = RC_MAP_EMPTY; - - return; -} - -static int af9015_read_config(struct usb_device *udev) -{ - int ret; - u8 val, i, offset = 0; - struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; - - /* IR remote controller */ - req.addr = AF9015_EEPROM_IR_MODE; - /* first message will timeout often due to possible hw bug */ - for (i = 0; i < 4; i++) { - ret = af9015_rw_udev(udev, &req); - if (!ret) - break; - } - if (ret) - goto error; - - ret = af9015_eeprom_hash(udev); - if (ret) - goto error; - - deb_info("%s: IR mode=%d\n", __func__, val); - for (i = 0; i < af9015_properties_count; i++) { - if (val == AF9015_IR_MODE_DISABLED) - af9015_properties[i].rc.core.rc_codes = NULL; - else - af9015_set_remote_config(udev, &af9015_properties[i]); - } - - /* TS mode - one or two receivers */ - req.addr = AF9015_EEPROM_TS_MODE; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - af9015_config.dual_mode = val; - deb_info("%s: TS mode=%d\n", __func__, af9015_config.dual_mode); - - /* Set adapter0 buffer size according to USB port speed, adapter1 buffer - size can be static because it is enabled only USB2.0 */ - for (i = 0; i < af9015_properties_count; i++) { - /* USB1.1 set smaller buffersize and disable 2nd adapter */ - if (udev->speed == USB_SPEED_FULL) { - af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize - = TS_USB11_FRAME_SIZE; - /* disable 2nd adapter because we don't have - PID-filters */ - af9015_config.dual_mode = 0; - } else { - af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize - = TS_USB20_FRAME_SIZE; - } - } - - if (af9015_config.dual_mode) { - /* read 2nd demodulator I2C address */ - req.addr = AF9015_EEPROM_DEMOD2_I2C; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - af9015_af9013_config[1].i2c_addr = val; - - /* enable 2nd adapter */ - for (i = 0; i < af9015_properties_count; i++) - af9015_properties[i].num_adapters = 2; - - } else { - /* disable 2nd adapter */ - for (i = 0; i < af9015_properties_count; i++) - af9015_properties[i].num_adapters = 1; - } - - for (i = 0; i < af9015_properties[0].num_adapters; i++) { - if (i == 1) - offset = AF9015_EEPROM_OFFSET; - /* xtal */ - req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - switch (val) { - case 0: - af9015_af9013_config[i].clock = 28800000; - break; - case 1: - af9015_af9013_config[i].clock = 20480000; - break; - case 2: - af9015_af9013_config[i].clock = 28000000; - break; - case 3: - af9015_af9013_config[i].clock = 25000000; - break; - }; - deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i, - val, af9015_af9013_config[i].clock); - - /* IF frequency */ - req.addr = AF9015_EEPROM_IF1H + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - - af9015_af9013_config[i].if_frequency = val << 8; - - req.addr = AF9015_EEPROM_IF1L + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - - af9015_af9013_config[i].if_frequency += val; - af9015_af9013_config[i].if_frequency *= 1000; - deb_info("%s: [%d] IF frequency=%d\n", __func__, i, - af9015_af9013_config[0].if_frequency); - - /* MT2060 IF1 */ - req.addr = AF9015_EEPROM_MT2060_IF1H + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - af9015_config.mt2060_if1[i] = val << 8; - req.addr = AF9015_EEPROM_MT2060_IF1L + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - af9015_config.mt2060_if1[i] += val; - deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i, - af9015_config.mt2060_if1[i]); - - /* tuner */ - req.addr = AF9015_EEPROM_TUNER_ID1 + offset; - ret = af9015_rw_udev(udev, &req); - if (ret) - goto error; - switch (val) { - case AF9013_TUNER_ENV77H11D5: - case AF9013_TUNER_MT2060: - case AF9013_TUNER_QT1010: - case AF9013_TUNER_UNKNOWN: - case AF9013_TUNER_MT2060_2: - case AF9013_TUNER_TDA18271: - case AF9013_TUNER_QT1010A: - case AF9013_TUNER_TDA18218: - af9015_af9013_config[i].spec_inv = 1; - break; - case AF9013_TUNER_MXL5003D: - case AF9013_TUNER_MXL5005D: - case AF9013_TUNER_MXL5005R: - case AF9013_TUNER_MXL5007T: - af9015_af9013_config[i].spec_inv = 0; - break; - case AF9013_TUNER_MC44S803: - af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO; - af9015_af9013_config[i].spec_inv = 1; - break; - default: - warn("tuner id=%d not supported, please report!", val); - return -ENODEV; - }; - - af9015_af9013_config[i].tuner = val; - deb_info("%s: [%d] tuner id=%d\n", __func__, i, val); - } - -error: - if (ret) - err("eeprom read failed=%d", ret); - - /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM - content :-( Override some wrong values here. Ditto for the - AVerTV Red HD+ (A850T) device. */ - if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA && - ((le16_to_cpu(udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850) || - (le16_to_cpu(udev->descriptor.idProduct) == - USB_PID_AVERMEDIA_A850T))) { - deb_info("%s: AverMedia A850: overriding config\n", __func__); - /* disable dual mode */ - af9015_config.dual_mode = 0; - /* disable 2nd adapter */ - for (i = 0; i < af9015_properties_count; i++) - af9015_properties[i].num_adapters = 1; - - /* set correct IF */ - af9015_af9013_config[0].if_frequency = 4570000; - } - - return ret; -} - -static int af9015_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - int ret; - u8 reply; - struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; - - ret = af9015_rw_udev(udev, &req); - if (ret) - return ret; - - deb_info("%s: reply:%02x\n", __func__, reply); - if (reply == 0x02) - *cold = 0; - else - *cold = 1; - - return ret; -} - -static int af9015_rc_query(struct dvb_usb_device *d) -{ - struct af9015_state *priv = d->priv; - int ret; - 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 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) { - 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]) { - if (buf[12] == (u8) ~buf[13]) { - /* NEC */ - priv->rc_keycode = buf[12] << 8 | buf[14]; - } else { - /* NEC extended*/ - priv->rc_keycode = buf[12] << 16 | - buf[13] << 8 | buf[14]; - } - } else { - /* 32 bit NEC */ - priv->rc_keycode = buf[12] << 24 | buf[13] << 16 | - buf[14] << 8 | buf[15]; - } - 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]; - -error: - if (ret) - err("%s: failed:%d", __func__, ret); - - return ret; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_set_frontend(struct dvb_frontend *fe) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *priv = adap->dev->priv; - - if (mutex_lock_interruptible(&adap->dev->usb_mutex)) - return -EAGAIN; - - ret = priv->set_frontend[adap->id](fe); - - mutex_unlock(&adap->dev->usb_mutex); - - return ret; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_read_status(struct dvb_frontend *fe, - fe_status_t *status) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *priv = adap->dev->priv; - - if (mutex_lock_interruptible(&adap->dev->usb_mutex)) - return -EAGAIN; - - ret = priv->read_status[adap->id](fe, status); - - mutex_unlock(&adap->dev->usb_mutex); - - return ret; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_init(struct dvb_frontend *fe) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *priv = adap->dev->priv; - - if (mutex_lock_interruptible(&adap->dev->usb_mutex)) - return -EAGAIN; - - ret = priv->init[adap->id](fe); - - mutex_unlock(&adap->dev->usb_mutex); - - return ret; -} - -/* override demod callbacks for resource locking */ -static int af9015_af9013_sleep(struct dvb_frontend *fe) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *priv = adap->dev->priv; - - if (mutex_lock_interruptible(&adap->dev->usb_mutex)) - return -EAGAIN; - - ret = priv->sleep[adap->id](fe); - - mutex_unlock(&adap->dev->usb_mutex); - - return ret; -} - -/* override tuner callbacks for resource locking */ -static int af9015_tuner_init(struct dvb_frontend *fe) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *priv = adap->dev->priv; - - if (mutex_lock_interruptible(&adap->dev->usb_mutex)) - return -EAGAIN; - - ret = priv->tuner_init[adap->id](fe); - - mutex_unlock(&adap->dev->usb_mutex); - - return ret; -} - -/* override tuner callbacks for resource locking */ -static int af9015_tuner_sleep(struct dvb_frontend *fe) -{ - int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *priv = adap->dev->priv; - - if (mutex_lock_interruptible(&adap->dev->usb_mutex)) - return -EAGAIN; - - ret = priv->tuner_sleep[adap->id](fe); - - mutex_unlock(&adap->dev->usb_mutex); - - return ret; -} - - static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) { int ret; struct af9015_state *state = adap->dev->priv; - if (adap->id == 1) { + if (adap->id == 0) { + state->af9013_config[0].ts_mode = AF9013_TS_USB; + memcpy(state->af9013_config[0].api_version, "\x0\x1\x9\x0", 4); + state->af9013_config[0].gpio[0] = AF9013_GPIO_HI; + state->af9013_config[0].gpio[3] = AF9013_GPIO_TUNER_ON; + } else if (adap->id == 1) { + state->af9013_config[1].ts_mode = AF9013_TS_SERIAL; + memcpy(state->af9013_config[1].api_version, "\x0\x1\x9\x0", 4); + state->af9013_config[1].gpio[0] = AF9013_GPIO_TUNER_ON; + state->af9013_config[1].gpio[1] = AF9013_GPIO_LO; + /* copy firmware to 2nd demodulator */ - if (af9015_config.dual_mode) { + if (state->dual_mode) { ret = af9015_copy_firmware(adap->dev); if (ret) { err("firmware copy to 2nd frontend " \ "failed, will disable it"); - af9015_config.dual_mode = 0; + state->dual_mode = 0; return -ENODEV; } } else { @@ -1219,8 +846,8 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) } /* attach demodulator */ - adap->fe_adap[0].fe = dvb_attach(af9013_attach, - &af9015_af9013_config[adap->id], &adap->dev->i2c_adap); + adap->fe[0] = dvb_attach(af9013_attach, + &state->af9013_config[adap->id], &adap->dev->i2c_adap); /* * AF9015 firmware does not like if it gets interrupted by I2C adapter @@ -1228,27 +855,26 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) * is used only 2nd demodulator and tuner on dual tuner devices. * Override demodulator callbacks and use mutex for limit access to * those "critical" paths to keep AF9015 happy. - * Note: we abuse unused usb_mutex here. */ - if (adap->fe_adap[0].fe) { + if (adap->fe[0]) { state->set_frontend[adap->id] = - adap->fe_adap[0].fe->ops.set_frontend; - adap->fe_adap[0].fe->ops.set_frontend = + adap->fe[0]->ops.set_frontend; + adap->fe[0]->ops.set_frontend = af9015_af9013_set_frontend; state->read_status[adap->id] = - adap->fe_adap[0].fe->ops.read_status; - adap->fe_adap[0].fe->ops.read_status = + adap->fe[0]->ops.read_status; + adap->fe[0]->ops.read_status = af9015_af9013_read_status; - state->init[adap->id] = adap->fe_adap[0].fe->ops.init; - adap->fe_adap[0].fe->ops.init = af9015_af9013_init; + state->init[adap->id] = adap->fe[0]->ops.init; + adap->fe[0]->ops.init = af9015_af9013_init; - state->sleep[adap->id] = adap->fe_adap[0].fe->ops.sleep; - adap->fe_adap[0].fe->ops.sleep = af9015_af9013_sleep; + state->sleep[adap->id] = adap->fe[0]->ops.sleep; + adap->fe[0]->ops.sleep = af9015_af9013_sleep; } - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static struct mt2060_config af9015_mt2060_config = { @@ -1316,57 +942,57 @@ static struct mxl5007t_config af9015_mxl5007t_config = { static int af9015_tuner_attach(struct dvb_usb_adapter *adap) { - int ret; struct af9015_state *state = adap->dev->priv; + int ret; deb_info("%s:\n", __func__); - switch (af9015_af9013_config[adap->id].tuner) { + switch (state->af9013_config[adap->id].tuner) { case AF9013_TUNER_MT2060: case AF9013_TUNER_MT2060_2: - ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe, + ret = dvb_attach(mt2060_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mt2060_config, - af9015_config.mt2060_if1[adap->id]) + state->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: - ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe, + ret = dvb_attach(qt1010_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0xc0, + ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0, &adap->dev->i2c_adap, &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18218: - ret = dvb_attach(tda18218_attach, adap->fe_adap[0].fe, + ret = dvb_attach(tda18218_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_tda18218_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5003D: - ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mxl5003_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: - ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mxl5005_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0xc0, + ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0, &adap->dev->i2c_adap, DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MC44S803: - ret = dvb_attach(mc44s803_attach, adap->fe_adap[0].fe, + ret = dvb_attach(mc44s803_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mc44s803_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5007T: - ret = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe, + ret = dvb_attach(mxl5007t_attach, adap->fe[0], &adap->dev->i2c_adap, 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; break; @@ -1374,575 +1000,437 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) default: ret = -ENODEV; err("Unknown tuner id:%d", - af9015_af9013_config[adap->id].tuner); + state->af9013_config[adap->id].tuner); } - if (adap->fe_adap[0].fe->ops.tuner_ops.init) { + if (adap->fe[0]->ops.tuner_ops.init) { state->tuner_init[adap->id] = - adap->fe_adap[0].fe->ops.tuner_ops.init; - adap->fe_adap[0].fe->ops.tuner_ops.init = af9015_tuner_init; + adap->fe[0]->ops.tuner_ops.init; + adap->fe[0]->ops.tuner_ops.init = af9015_tuner_init; } - if (adap->fe_adap[0].fe->ops.tuner_ops.sleep) { + if (adap->fe[0]->ops.tuner_ops.sleep) { state->tuner_sleep[adap->id] = - adap->fe_adap[0].fe->ops.tuner_ops.sleep; - adap->fe_adap[0].fe->ops.tuner_ops.sleep = af9015_tuner_sleep; + adap->fe[0]->ops.tuner_ops.sleep; + adap->fe[0]->ops.tuner_ops.sleep = af9015_tuner_sleep; } return ret; } -enum af9015_usb_table_entry { - AFATECH_9015, - AFATECH_9016, - WINFAST_DTV_GOLD, - PINNACLE_PCTV_71E, - KWORLD_PLUSTV_399U, - TINYTWIN, - AZUREWAVE_TU700, - TERRATEC_AF9015, - KWORLD_PLUSTV_PC160, - AVERTV_VOLAR_X, - XTENSIONS_380U, - MSI_DIGIVOX_DUO, - AVERTV_VOLAR_X_REV2, - TELESTAR_STARSTICK_2, - AVERMEDIA_A309_USB, - MSI_DIGIVOX_MINI_III, - KWORLD_E396, - KWORLD_E39B, - KWORLD_E395, - TREKSTOR_DVBT, - AVERTV_A850, - AVERTV_A805, - CONCEPTRONIC_CTVDIGRCU, - KWORLD_MC810, - GENIUS_TVGO_DVB_T03, - KWORLD_399U_2, - KWORLD_PC160_T, - SVEON_STV20, - TINYTWIN_2, - WINFAST_DTV2000DS, - KWORLD_UB383_T, - KWORLD_E39A, - AVERMEDIA_A815M, - CINERGY_T_STICK_RC, - CINERGY_T_DUAL_RC, - AVERTV_A850T, - TINYTWIN_3, - SVEON_STV22, +static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + int ret; + deb_info("%s: onoff:%d\n", __func__, onoff); + + if (onoff) + ret = af9015_set_reg_bit(adap->dev, 0xd503, 0); + else + ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0); + + return ret; +} + +static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + int ret; + u8 idx; + + deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", + __func__, index, pid, onoff); + + ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff)); + if (ret) + goto error; + + ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8)); + if (ret) + goto error; + + idx = ((index & 0x1f) | (1 << 5)); + ret = af9015_write_reg(adap->dev, 0xd504, idx); + +error: + return ret; +} + +static int af9015_init_endpoint(struct dvb_usb_device *d) +{ + struct af9015_state *state = d->priv; + int ret; + u16 frame_size; + u8 packet_size; + deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); + + if (d->udev->speed == USB_SPEED_FULL) { + frame_size = TS_USB11_FRAME_SIZE/4; + packet_size = TS_USB11_MAX_PACKET_SIZE/4; + } else { + frame_size = TS_USB20_FRAME_SIZE/4; + packet_size = TS_USB20_MAX_PACKET_SIZE/4; + } + + ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ + if (ret) + goto error; + if (state->dual_mode) { + ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ + if (ret) + goto error; + } + ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ + if (ret) + goto error; + if (state->dual_mode) { + ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ + if (ret) + goto error; + } + /* EP4 xfer length */ + ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); + if (ret) + goto error; + /* EP5 xfer length */ + ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ + if (ret) + goto error; + ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ + if (ret) + goto error; + if (state->dual_mode) { + ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ + if (ret) + goto error; + } + + /* enable / disable mp2if2 */ + if (state->dual_mode) + ret = af9015_set_reg_bit(d, 0xd50b, 0); + else + ret = af9015_clear_reg_bit(d, 0xd50b, 0); + +error: + if (ret) + err("endpoint init failed:%d", ret); + return ret; +} + +static int af9015_init(struct dvb_usb_device *d) +{ + struct af9015_state *state = d->priv; + int ret; + deb_info("%s:\n", __func__); + + mutex_init(&state->fe_mutex); + + /* init RC canary */ + ret = af9015_write_reg(d, 0x98e9, 0xff); + if (ret) + goto error; + + ret = af9015_init_endpoint(d); + if (ret) + goto error; + +error: + return ret; +} + +struct af9015_rc_setup { + unsigned int id; + char *rc_codes; }; -static struct usb_device_id af9015_usb_table[] = { - [AFATECH_9015] = { - USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, - [AFATECH_9016] = { - USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, - [WINFAST_DTV_GOLD] = { - USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, - [PINNACLE_PCTV_71E] = { - USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)}, - [KWORLD_PLUSTV_399U] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)}, - [TINYTWIN] = { - USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)}, - [AZUREWAVE_TU700] = { - USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)}, - [TERRATEC_AF9015] = { - USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)}, - [KWORLD_PLUSTV_PC160] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)}, - [AVERTV_VOLAR_X] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)}, - [XTENSIONS_380U] = { - USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, - [MSI_DIGIVOX_DUO] = { - USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, - [AVERTV_VOLAR_X_REV2] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, - [TELESTAR_STARSTICK_2] = { - USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, - [AVERMEDIA_A309_USB] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, - [MSI_DIGIVOX_MINI_III] = { - USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, - [KWORLD_E396] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, - [KWORLD_E39B] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)}, - [KWORLD_E395] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)}, - [TREKSTOR_DVBT] = { - USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)}, - [AVERTV_A850] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, - [AVERTV_A805] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)}, - [CONCEPTRONIC_CTVDIGRCU] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)}, - [KWORLD_MC810] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)}, - [GENIUS_TVGO_DVB_T03] = { - USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)}, - [KWORLD_399U_2] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)}, - [KWORLD_PC160_T] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)}, - [SVEON_STV20] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)}, - [TINYTWIN_2] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)}, - [WINFAST_DTV2000DS] = { - USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)}, - [KWORLD_UB383_T] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)}, - [KWORLD_E39A] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)}, - [AVERMEDIA_A815M] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)}, - [CINERGY_T_STICK_RC] = { - USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_T_STICK_RC)}, - [CINERGY_T_DUAL_RC] = { - USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)}, - [AVERTV_A850T] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)}, - [TINYTWIN_3] = { - USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)}, - [SVEON_STV22] = { - USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)}, +static char *af9015_rc_setup_match(unsigned int id, + const struct af9015_rc_setup *table) +{ + for (; table->rc_codes; table++) + if (table->id == id) + return table->rc_codes; + return NULL; +} + +static const struct af9015_rc_setup af9015_rc_setup_modparam[] = { + { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M }, + { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II }, + { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND }, + { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE }, + { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS }, { } }; -MODULE_DEVICE_TABLE(usb, af9015_usb_table); -#define AF9015_RC_INTERVAL 500 -static struct dvb_usb_device_properties af9015_properties[] = { - { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, +static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { + { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II }, + { 0xa3703d00, RC_MAP_ALINK_DTU_M }, + { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */ + { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */ + { } +}; - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = af9015_download_firmware, - .firmware = "dvb-usb-af9015.fw", - .no_reconnect = 1, +static int af9015_rc_query(struct dvb_usb_device *d) +{ + struct af9015_state *state = d->priv; + int ret; + u8 buf[17]; - .size_of_priv = sizeof(struct af9015_state), + deb_info("%s:\n", __func__); - .num_adapters = 2, - .adapter = { - { - .num_frontends = 1, - .fe = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + /* read registers needed to detect remote controller code */ + ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf)); + if (ret) + goto error; - .pid_filter_count = 32, - .pid_filter = af9015_pid_filter, - .pid_filter_ctrl = af9015_pid_filter_ctrl, + /* If any of these are non-zero, assume invalid data */ + if (buf[1] || buf[2] || buf[3]) + return ret; - .frontend_attach = af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x84, - }, - } - }, - }, - { - .num_frontends = 1, - .fe = { - { - .frontend_attach = af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x85, - .u = { - .bulk = { - .buffersize = TS_USB20_FRAME_SIZE, - } - } - }, - } - }, + /* Check for repeat of previous code */ + if ((state->rc_repeat != buf[6] || buf[0]) && + !memcmp(&buf[12], state->rc_last, 4)) { + deb_rc("%s: key repeated\n", __func__); + rc_keydown(d->rc_dev, state->rc_keycode, 0); + state->rc_repeat = buf[6]; + return ret; + } + + /* Only process key if canary killed */ + if (buf[16] != 0xff && buf[0] != 0x01) { + 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(state->rc_last, &buf[12], 4); + if (buf[14] == (u8) ~buf[15]) { + if (buf[12] == (u8) ~buf[13]) { + /* NEC */ + state->rc_keycode = buf[12] << 8 | buf[14]; + } else { + /* NEC extended*/ + state->rc_keycode = buf[12] << 16 | + buf[13] << 8 | buf[14]; } - }, - - .identify_state = af9015_identify_state, - - .rc.core = { - .protocol = RC_TYPE_NEC, - .module_name = "af9015", - .rc_query = af9015_rc_query, - .rc_interval = AF9015_RC_INTERVAL, - .allowed_protos = RC_TYPE_NEC, - }, - - .i2c_algo = &af9015_i2c_algo, - - .num_device_descs = 12, /* check max from dvb-usb.h */ - .devices = { - { - .name = "Afatech AF9015 DVB-T USB2.0 stick", - .cold_ids = { - &af9015_usb_table[AFATECH_9015], - &af9015_usb_table[AFATECH_9016], - }, - }, { - .name = "Leadtek WinFast DTV Dongle Gold", - .cold_ids = { - &af9015_usb_table[WINFAST_DTV_GOLD], - }, - }, { - .name = "Pinnacle PCTV 71e", - .cold_ids = { - &af9015_usb_table[PINNACLE_PCTV_71E], - }, - }, { - .name = "KWorld PlusTV Dual DVB-T Stick " \ - "(DVB-T 399U)", - .cold_ids = { - &af9015_usb_table[KWORLD_PLUSTV_399U], - &af9015_usb_table[KWORLD_399U_2], - }, - }, { - .name = "DigitalNow TinyTwin DVB-T Receiver", - .cold_ids = { - &af9015_usb_table[TINYTWIN], - &af9015_usb_table[TINYTWIN_2], - &af9015_usb_table[TINYTWIN_3], - }, - }, { - .name = "TwinHan AzureWave AD-TU700(704J)", - .cold_ids = { - &af9015_usb_table[AZUREWAVE_TU700], - }, - }, { - .name = "TerraTec Cinergy T USB XE", - .cold_ids = { - &af9015_usb_table[TERRATEC_AF9015], - }, - }, { - .name = "KWorld PlusTV Dual DVB-T PCI " \ - "(DVB-T PC160-2T)", - .cold_ids = { - &af9015_usb_table[KWORLD_PLUSTV_PC160], - }, - }, { - .name = "AVerMedia AVerTV DVB-T Volar X", - .cold_ids = { - &af9015_usb_table[AVERTV_VOLAR_X], - }, - }, { - .name = "TerraTec Cinergy T Stick RC", - .cold_ids = { - &af9015_usb_table[CINERGY_T_STICK_RC], - }, - }, { - .name = "TerraTec Cinergy T Stick Dual RC", - .cold_ids = { - &af9015_usb_table[CINERGY_T_DUAL_RC], - }, - }, { - .name = "AverMedia AVerTV Red HD+ (A850T)", - .cold_ids = { - &af9015_usb_table[AVERTV_A850T], - }, - }, + } else { + /* 32 bit NEC */ + state->rc_keycode = buf[12] << 24 | buf[13] << 16 | + buf[14] << 8 | buf[15]; } - }, { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, + rc_keydown(d->rc_dev, state->rc_keycode, 0); + } else { + deb_rc("%s: no key press\n", __func__); + /* Invalidate last keypress */ + /* Not really needed, but helps with debug */ + state->rc_last[2] = state->rc_last[3]; + } - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = af9015_download_firmware, - .firmware = "dvb-usb-af9015.fw", - .no_reconnect = 1, + state->rc_repeat = buf[6]; - .size_of_priv = sizeof(struct af9015_state), +error: + if (ret) + err("%s: failed:%d", __func__, ret); - .num_adapters = 2, - .adapter = { - { - .num_frontends = 1, - .fe = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + return ret; +} - .pid_filter_count = 32, - .pid_filter = af9015_pid_filter, - .pid_filter_ctrl = af9015_pid_filter_ctrl, +static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + struct af9015_state *state = d->priv; + u16 vid = le16_to_cpu(d->udev->descriptor.idVendor); - .frontend_attach = af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x84, - }, - } - }, - }, - { - .num_frontends = 1, - .fe = { - { - .frontend_attach = af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x85, - .u = { - .bulk = { - .buffersize = TS_USB20_FRAME_SIZE, - } - } - }, - } - }, - } - }, + if (state->ir_mode == AF9015_IR_MODE_DISABLED) + return 0; - .identify_state = af9015_identify_state, + /* try to load remote based module param */ + rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote, + af9015_rc_setup_modparam); - .rc.core = { - .protocol = RC_TYPE_NEC, - .module_name = "af9015", - .rc_query = af9015_rc_query, - .rc_interval = AF9015_RC_INTERVAL, - .allowed_protos = RC_TYPE_NEC, - }, + /* try to load remote based eeprom hash */ + if (!rc->map_name) + rc->map_name = af9015_rc_setup_match(state->eeprom_sum, + af9015_rc_setup_hashes); - .i2c_algo = &af9015_i2c_algo, - - .num_device_descs = 10, /* check max from dvb-usb.h */ - .devices = { - { - .name = "Xtensions XD-380", - .cold_ids = { - &af9015_usb_table[XTENSIONS_380U], - }, - }, { - .name = "MSI DIGIVOX Duo", - .cold_ids = { - &af9015_usb_table[MSI_DIGIVOX_DUO], - }, - }, { - .name = "Fujitsu-Siemens Slim Mobile USB DVB-T", - .cold_ids = { - &af9015_usb_table[AVERTV_VOLAR_X_REV2], - }, - }, { - .name = "Telestar Starstick 2", - .cold_ids = { - &af9015_usb_table[TELESTAR_STARSTICK_2], - }, - }, { - .name = "AVerMedia A309", - .cold_ids = { - &af9015_usb_table[AVERMEDIA_A309_USB], - }, - }, { - .name = "MSI Digi VOX mini III", - .cold_ids = { - &af9015_usb_table[MSI_DIGIVOX_MINI_III], - }, - }, { - .name = "KWorld USB DVB-T TV Stick II " \ - "(VS-DVB-T 395U)", - .cold_ids = { - &af9015_usb_table[KWORLD_E396], - &af9015_usb_table[KWORLD_E39B], - &af9015_usb_table[KWORLD_E395], - &af9015_usb_table[KWORLD_E39A], - }, - }, { - .name = "TrekStor DVB-T USB Stick", - .cold_ids = { - &af9015_usb_table[TREKSTOR_DVBT], - }, - }, { - .name = "AverMedia AVerTV Volar Black HD " \ - "(A850)", - .cold_ids = { - &af9015_usb_table[AVERTV_A850], - }, - }, { - .name = "Sveon STV22 Dual USB DVB-T Tuner HDTV", - .cold_ids = { - &af9015_usb_table[SVEON_STV22], - }, - }, + /* try to load remote based USB iManufacturer string */ + if (!rc->map_name && vid == USB_VID_AFATECH) { + /* Check USB manufacturer and product strings and try + to determine correct remote in case of chip vendor + reference IDs are used. + DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */ + char manufacturer[10]; + memset(manufacturer, 0, sizeof(manufacturer)); + usb_string(d->udev, d->udev->descriptor.iManufacturer, + manufacturer, sizeof(manufacturer)); + if (!strcmp("MSI", manufacturer)) { + /* iManufacturer 1 MSI + iProduct 2 MSI K-VOX */ + rc->map_name = af9015_rc_setup_match( + AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, + af9015_rc_setup_modparam); } - }, { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, + } - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = af9015_download_firmware, - .firmware = "dvb-usb-af9015.fw", - .no_reconnect = 1, + rc->allowed_protos = RC_TYPE_NEC; + rc->query = af9015_rc_query; + rc->interval = 500; - .size_of_priv = sizeof(struct af9015_state), + return 0; +} - .num_adapters = 2, - .adapter = { - { - .num_frontends = 1, - .fe = { - { - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, +/* interface 0 is used by DVB-T receiver and + interface 1 is for remote controller (HID) */ +static struct dvb_usb_device_properties af9015_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct af9015_state), - .pid_filter_count = 32, - .pid_filter = af9015_pid_filter, - .pid_filter_ctrl = af9015_pid_filter_ctrl, + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, - .frontend_attach = af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x84, - }, - } - }, - }, - { - .num_frontends = 1, - .fe = { - { - .frontend_attach = af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x85, - .u = { - .bulk = { - .buffersize = TS_USB20_FRAME_SIZE, - } - } - }, - } - }, - } + .identify_state = af9015_identify_state, + .firmware = "dvb-usb-af9015.fw", + .download_firmware = af9015_download_firmware, + + .read_config = af9015_read_config, + .i2c_algo = &af9015_i2c_algo, + .init = af9015_init, + .get_rc_config = af9015_get_rc_config, + .get_usb_stream_config = af9015_get_usb_stream_config, + + .get_adapter_count = af9015_get_adapter_count, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + .frontend_attach = af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, }, - - .identify_state = af9015_identify_state, - - .rc.core = { - .protocol = RC_TYPE_NEC, - .module_name = "af9015", - .rc_query = af9015_rc_query, - .rc_interval = AF9015_RC_INTERVAL, - .allowed_protos = RC_TYPE_NEC, - }, - - .i2c_algo = &af9015_i2c_algo, - - .num_device_descs = 9, /* check max from dvb-usb.h */ - .devices = { - { - .name = "AverMedia AVerTV Volar GPS 805 (A805)", - .cold_ids = { - &af9015_usb_table[AVERTV_A805], - }, - }, { - .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \ - "V3.0", - .cold_ids = { - &af9015_usb_table[CONCEPTRONIC_CTVDIGRCU], - }, - }, { - .name = "KWorld Digial MC-810", - .cold_ids = { - &af9015_usb_table[KWORLD_MC810], - }, - }, { - .name = "Genius TVGo DVB-T03", - .cold_ids = { - &af9015_usb_table[GENIUS_TVGO_DVB_T03], - }, - }, { - .name = "KWorld PlusTV DVB-T PCI Pro Card " \ - "(DVB-T PC160-T)", - .cold_ids = { - &af9015_usb_table[KWORLD_PC160_T], - }, - }, { - .name = "Sveon STV20 Tuner USB DVB-T HDTV", - .cold_ids = { - &af9015_usb_table[SVEON_STV20], - }, - }, { - .name = "Leadtek WinFast DTV2000DS", - .cold_ids = { - &af9015_usb_table[WINFAST_DTV2000DS], - }, - }, { - .name = "KWorld USB DVB-T Stick Mobile " \ - "(UB383-T)", - .cold_ids = { - &af9015_usb_table[KWORLD_UB383_T], - }, - }, { - .name = "AverMedia AVerTV Volar M (A815Mac)", - .cold_ids = { - &af9015_usb_table[AVERMEDIA_A815M], - }, - }, + { + .frontend_attach = af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, } }, }; -static int af9015_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret = 0; - struct dvb_usb_device *d = NULL; - struct usb_device *udev = interface_to_usbdev(intf); - u8 i; - - deb_info("%s: interface:%d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); - - /* interface 0 is used by DVB-T receiver and - interface 1 is for remote controller (HID) */ - if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { - ret = af9015_read_config(udev); - if (ret) - return ret; - - for (i = 0; i < af9015_properties_count; i++) { - ret = dvb_usb_device_init(intf, &af9015_properties[i], - THIS_MODULE, &d, adapter_nr); - if (!ret) - break; - if (ret != -ENODEV) - return ret; - } - if (ret) - return ret; - - if (d) - ret = af9015_init(d); - } - - return ret; -} +static const struct usb_device_id af9015_id_table[] = { + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015, + &af9015_props, "Afatech AF9015 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016, + &af9015_props, "Afatech AF9015 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD, + &af9015_props, "Leadtek WinFast DTV Dongle Gold", RC_MAP_LEADTEK_Y04G0051) }, + { DVB_USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E, + &af9015_props, "Pinnacle PCTV 71e", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U, + &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN, + &af9015_props, "DigitalNow TinyTwin", RC_MAP_AZUREWAVE_AD_TU700) }, + { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700, + &af9015_props, "TwinHan AzureWave AD-TU700(704J)", RC_MAP_AZUREWAVE_AD_TU700) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2, + &af9015_props, "TerraTec Cinergy T USB XE", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T, + &af9015_props, "KWorld PlusTV Dual DVB-T PCI (DVB-T PC160-2T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X, + &af9015_props, "AVerMedia AVerTV DVB-T Volar X", RC_MAP_AVERMEDIA_M135A) }, + { DVB_USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380, + &af9015_props, "Xtensions XD-380", NULL) }, + { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO, + &af9015_props, "MSI DIGIVOX Duo", RC_MAP_MSI_DIGIVOX_III) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2, + &af9015_props, "Fujitsu-Siemens Slim Mobile USB DVB-T", NULL) }, + { DVB_USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2, + &af9015_props, "Telestar Starstick 2", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309, + &af9015_props, "AVerMedia A309", NULL) }, + { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III, + &af9015_props, "MSI Digi VOX mini III", RC_MAP_MSI_DIGIVOX_III) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT, + &af9015_props, "TrekStor DVB-T USB Stick", RC_MAP_TREKSTOR) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850, + &af9015_props, "AverMedia AVerTV Volar Black HD (A850)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805, + &af9015_props, "AverMedia AVerTV Volar GPS 805 (A805)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU, + &af9015_props, "Conceptronic USB2.0 DVB-T CTVDIGRCU V3.0", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810, + &af9015_props, "KWorld Digial MC-810", NULL) }, + { DVB_USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03, + &af9015_props, "Genius TVGo DVB-T03", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2, + &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T, + &af9015_props, "KWorld PlusTV DVB-T PCI Pro Card (DVB-T PC160-T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20, + &af9015_props, "Sveon STV20 Tuner USB DVB-T HDTV", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2, + &af9015_props, "DigitalNow TinyTwin v2", RC_MAP_DIGITALNOW_TINYTWIN) }, + { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS, + &af9015_props, "Leadtek WinFast DTV2000DS", RC_MAP_LEADTEK_Y04G0051) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T, + &af9015_props, "KWorld USB DVB-T Stick Mobile (UB383-T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4, + &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M, + &af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC, + &af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, + &af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T, + &af9015_props, "AverMedia AVerTV Red HD+ (A850T)", NULL) }, + { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3, + &af9015_props, "DigitalNow TinyTwin v3", RC_MAP_DIGITALNOW_TINYTWIN) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22, + &af9015_props, "Sveon STV22 Dual USB DVB-T Tuner HDTV", RC_MAP_MSI_DIGIVOX_III) }, + { } +}; +MODULE_DEVICE_TABLE(usb, af9015_id_table); /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver af9015_usb_driver = { - .name = "dvb_usb_af9015", - .probe = af9015_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = af9015_usb_table, + .name = KBUILD_MODNAME, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .id_table = af9015_id_table, + .no_dynamic_id = 1, }; module_usb_driver(af9015_usb_driver); diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h index 2f68419e899b..b41ee73b26dc 100644 --- a/drivers/media/dvb/dvb-usb/af9015.h +++ b/drivers/media/dvb/dvb-usb/af9015.h @@ -21,18 +21,54 @@ * */ -#ifndef _DVB_USB_AF9015_H_ -#define _DVB_USB_AF9015_H_ +#ifndef AF9015_H +#define AF9015_H + +#include +#include "dvb_usb.h" +#include "af9013.h" +#include "dvb-pll.h" +#include "mt2060.h" +#include "qt1010.h" +#include "tda18271.h" +#include "mxl5005s.h" +#include "mc44s803.h" +#include "tda18218.h" +#include "mxl5007t.h" #define DVB_USB_LOG_PREFIX "af9015" -#include "dvb-usb.h" + +#ifdef CONFIG_DVB_USB_DEBUG +#define dprintk(var, level, args...) \ + do { if ((var & level)) printk(args); } while (0) +#define DVB_USB_DEBUG_STATUS +#else +#define dprintk(args...) +#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" +#endif #define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args) #define deb_rc(args...) dprintk(dvb_usb_af9015_debug, 0x02, args) -#define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args) -#define deb_reg(args...) dprintk(dvb_usb_af9015_debug, 0x08, args) -#define deb_i2c(args...) dprintk(dvb_usb_af9015_debug, 0x10, args) -#define deb_fw(args...) dprintk(dvb_usb_af9015_debug, 0x20, args) + +#undef err +#define err(format, arg...) \ + printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) \ + printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) + +/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0. + We use smaller - about 1/4 from the original, 5 and 87. */ +#define TS_PACKET_SIZE 188 + +#define TS_USB20_PACKET_COUNT 87 +#define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) + +#define TS_USB11_PACKET_COUNT 5 +#define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) + +#define TS_USB20_MAX_PACKET_SIZE 512 +#define TS_USB11_MAX_PACKET_SIZE 64 #define AF9015_I2C_EEPROM 0xa0 #define AF9015_I2C_DEMOD 0x38 @@ -99,9 +135,17 @@ enum af9015_ir_mode { }; struct af9015_state { + u8 ir_mode; u8 rc_repeat; u32 rc_keycode; u8 rc_last[4]; + u8 dual_mode; + u8 seq; /* packet sequence number */ + u16 mt2060_if1[2]; + u16 firmware_size; + u16 firmware_checksum; + u32 eeprom_sum; + struct af9013_config af9013_config[2]; /* for demod callback override */ int (*set_frontend[2]) (struct dvb_frontend *fe); @@ -110,14 +154,7 @@ struct af9015_state { int (*sleep[2]) (struct dvb_frontend *fe); int (*tuner_init[2]) (struct dvb_frontend *fe); int (*tuner_sleep[2]) (struct dvb_frontend *fe); -}; - -struct af9015_config { - u8 dual_mode:1; - u16 mt2060_if1[2]; - u16 firmware_size; - u16 firmware_checksum; - u32 eeprom_sum; + struct mutex fe_mutex; }; enum af9015_remote { From 77f54517fd5fc3f94486729a74064fbb55f140b8 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Jun 2012 21:22:06 -0300 Subject: [PATCH 0250/5375] [media] af9015: use USB core soft_unbind I think it is better to allow driver finish pending operations and disconnect device. Killing all ongoing USB transfers could have very bad effect, even break hardware in worst case. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index fe5ef3a03edc..9d0bd9bed739 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -1431,6 +1431,7 @@ static struct usb_driver af9015_usb_driver = { .disconnect = dvb_usbv2_disconnect, .id_table = af9015_id_table, .no_dynamic_id = 1, + .soft_unbind = 1, }; module_usb_driver(af9015_usb_driver); From 0fba999f13b7480278946be4b51db4a1035e7f4f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Jun 2012 21:37:11 -0300 Subject: [PATCH 0251/5375] [media] dvb_usb_v2: I2C adapter cleanup changes Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index c98712a29133..5759d8e2f8ef 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -70,10 +70,12 @@ err: int dvb_usbv2_i2c_init(struct dvb_usb_device *d) { - int ret = 0; + int ret; - if (!d->props.i2c_algo) - return 0; + if (!d->props.i2c_algo) { + ret = 0; + goto err; + } strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); d->i2c_adap.algo = d->props.i2c_algo; @@ -83,11 +85,16 @@ int dvb_usbv2_i2c_init(struct dvb_usb_device *d) i2c_set_adapdata(&d->i2c_adap, d); ret = i2c_add_adapter(&d->i2c_adap); - if (ret < 0) - pr_err("%s: could not add i2c adapter\n", KBUILD_MODNAME); + if (ret < 0) { + pr_err("%s: i2c_add_adapter() failed\n", KBUILD_MODNAME); + goto err; + } d->state |= DVB_USB_STATE_I2C; + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); return ret; } @@ -95,7 +102,9 @@ int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) { if (d->state & DVB_USB_STATE_I2C) i2c_del_adapter(&d->i2c_adap); + d->state &= ~DVB_USB_STATE_I2C; + return 0; } From d496eb8ae49e4fbaae43ac2115db0efe20d37556 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Jun 2012 23:24:29 -0300 Subject: [PATCH 0252/5375] [media] dvb_usb_v2: misc cleanup changes Error handling, remove unneeded stuff, renaming, etc. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 86 +++++++++++++----------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 5759d8e2f8ef..2d0fbaf6c6d0 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -17,14 +17,13 @@ int dvb_usbv2_disable_rc_polling; module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644); MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); - static int dvb_usb_force_pid_filter_usage; module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a" \ " PID filter, if any (default: 0)."); -int dvb_usbv2_download_firmware(struct dvb_usb_device *d) +static int dvb_usbv2_download_firmware(struct dvb_usb_device *d) { int ret; const struct firmware *fw = NULL; @@ -35,7 +34,7 @@ int dvb_usbv2_download_firmware(struct dvb_usb_device *d) if (d->props.get_firmware_name) { ret = d->props.get_firmware_name(d, &name); if (ret < 0) - return ret; + goto err; } if (!d->props.download_firmware) { @@ -68,7 +67,7 @@ err: return ret; } -int dvb_usbv2_i2c_init(struct dvb_usb_device *d) +static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) { int ret; @@ -98,7 +97,7 @@ err: return ret; } -int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) +static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) { if (d->state & DVB_USB_STATE_I2C) i2c_del_adapter(&d->i2c_adap); @@ -111,7 +110,7 @@ int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) { struct dvb_usb_adapter *adap; - int ret, n, adapter_count; + int ret, i, adapter_count; /* resolve adapter count */ adapter_count = d->props.num_adapters; @@ -123,12 +122,12 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) adapter_count = ret; } - for (n = 0; n < adapter_count; n++) { - adap = &d->adapter[n]; + for (i = 0; i < adapter_count; i++) { + adap = &d->adapter[i]; adap->dev = d; - adap->id = n; + adap->id = i; - memcpy(&adap->props, &d->props.adapter[n], + memcpy(&adap->props, &d->props.adapter[i], sizeof(struct dvb_usb_adapter_properties)); /* speed - when running at FULL speed we need a HW PID filter */ @@ -137,7 +136,8 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) pr_err("%s: this USB2.0 device cannot be run on a " \ "USB1.1 port (it lacks a hardware " \ "PID filter)\n", KBUILD_MODNAME); - return -ENODEV; + ret = -ENODEV; + goto err; } else if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) || (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { @@ -165,15 +165,15 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) ret = dvb_usbv2_adapter_stream_init(adap); if (ret) - return ret; + goto err; ret = dvb_usbv2_adapter_dvb_init(adap); if (ret) - return ret; + goto err; ret = dvb_usbv2_adapter_frontend_init(adap); if (ret) - return ret; + goto err; /* use exclusive FE lock if there is multiple shared FEs */ if (adap->fe[1]) @@ -191,16 +191,17 @@ err: static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) { - int n; - - for (n = 0; n < d->num_adapters_initialized; n++) { - dvb_usbv2_adapter_frontend_exit(&d->adapter[n]); - dvb_usbv2_adapter_dvb_exit(&d->adapter[n]); - dvb_usbv2_adapter_stream_exit(&d->adapter[n]); + int i; + for (i = d->num_adapters_initialized - 1; i >= 0; i--) { + dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); + dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); + dvb_usbv2_adapter_stream_exit(&d->adapter[i]); } + d->num_adapters_initialized = 0; d->state &= ~DVB_USB_STATE_DVB; + return 0; } @@ -215,6 +216,7 @@ static int dvb_usbv2_exit(struct dvb_usb_device *d) d->state = DVB_USB_STATE_INIT; kfree(d->priv); kfree(d); + return 0; } @@ -227,7 +229,6 @@ static int dvb_usbv2_init(struct dvb_usb_device *d) /* check the capabilities and set appropriate variables */ dvb_usbv2_device_power_ctrl(d, 1); - /* read config */ if (d->props.read_config) { ret = d->props.read_config(d); if (ret < 0) @@ -235,32 +236,36 @@ static int dvb_usbv2_init(struct dvb_usb_device *d) } ret = dvb_usbv2_i2c_init(d); - if (ret == 0) - ret = dvb_usbv2_adapter_init(d); + if (ret < 0) + goto err; - if (ret) { - dvb_usbv2_exit(d); - return ret; + ret = dvb_usbv2_adapter_init(d); + if (ret < 0) + goto err; + + if (d->props.init) { + ret = d->props.init(d); + if (ret < 0) + goto err; } - if (d->props.init) - d->props.init(d); - ret = dvb_usbv2_remote_init(d); - if (ret) - pr_err("%s: could not initialize remote control\n", - KBUILD_MODNAME); + if (ret < 0) + goto err; dvb_usbv2_device_power_ctrl(d, 0); return 0; err: + dvb_usbv2_device_power_ctrl(d, 0); pr_debug("%s: failed=%d\n", __func__, ret); return ret; } int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) { + int ret; + if (onoff) d->powered++; else @@ -268,11 +273,17 @@ int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */ - pr_debug("%s: power control: %d\n", __func__, onoff); - if (d->props.power_ctrl) - return d->props.power_ctrl(d, onoff); + pr_debug("%s: power control=%d\n", __func__, onoff); + if (d->props.power_ctrl) { + ret = d->props.power_ctrl(d, onoff); + goto err; + } } + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; } /* @@ -383,7 +394,7 @@ int dvb_usbv2_probe(struct usb_interface *intf, if (d->intf->cur_altsetting->desc.bInterfaceNumber != d->props.bInterfaceNumber) { ret = 0; - goto exit_kfree; + goto err_kfree; } mutex_init(&d->usb_mutex); @@ -398,8 +409,6 @@ int dvb_usbv2_probe(struct usb_interface *intf, return 0; err_kfree: - usb_set_intfdata(intf, NULL); -exit_kfree: kfree(d); err: pr_debug("%s: failed=%d\n", __func__, ret); @@ -419,7 +428,6 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) if (d->work_pid != current->pid) cancel_work_sync(&d->probe_work); - usb_set_intfdata(intf, NULL); if (d) { name = d->name; dvb_usbv2_exit(d); From 823eebac89f7adef3fb75e2a68e9e88be9b4afbe Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Jun 2012 23:42:47 -0300 Subject: [PATCH 0253/5375] [media] dvb_usb_v2: probe/disconnect error handling In my understanding we never call .disconnect() when .probe() returns error. Change .probe() to return error all cases it cannot handle given interface and simplify .disconnect() handling. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 2d0fbaf6c6d0..1f0fb11c587c 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -393,7 +393,7 @@ int dvb_usbv2_probe(struct usb_interface *intf, if (d->intf->cur_altsetting->desc.bInterfaceNumber != d->props.bInterfaceNumber) { - ret = 0; + ret = -ENODEV; goto err_kfree; } @@ -419,7 +419,7 @@ EXPORT_SYMBOL(dvb_usbv2_probe); void dvb_usbv2_disconnect(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name = "generic DVB-USB module"; + const char *name; pr_debug("%s: pid=%d work_pid=%d\n", __func__, current->pid, d->work_pid); @@ -428,10 +428,8 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) if (d->work_pid != current->pid) cancel_work_sync(&d->probe_work); - if (d) { - name = d->name; - dvb_usbv2_exit(d); - } + name = d->name; + dvb_usbv2_exit(d); pr_info("%s: '%s' successfully deinitialized and disconnected\n", KBUILD_MODNAME, name); From 5b6a63cc2f11a9b00862d13104d1304e082acfe5 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 10 Jun 2012 00:46:22 -0300 Subject: [PATCH 0254/5375] [media] dvb_usb_v2: add .disconnect() callback Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 1 + drivers/media/dvb/dvb-usb/dvb_usb_init.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 79f8571b9b20..d0c628782f76 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -195,6 +195,7 @@ struct dvb_usb_device_properties { #define COLD 1 int (*identify_state) (struct dvb_usb_device *); int (*init) (struct dvb_usb_device *); + void (*disconnect) (struct dvb_usb_device *); int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *); int (*get_usb_stream_config) (struct dvb_frontend *, struct usb_data_stream_properties *); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 1f0fb11c587c..976a706b4cc7 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -428,6 +428,9 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) if (d->work_pid != current->pid) cancel_work_sync(&d->probe_work); + if (d->props.disconnect) + d->props.disconnect(d); + name = d->name; dvb_usbv2_exit(d); From ef81e9ebbe57236683e6950d0ec82a20f2d350eb Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 11 Jun 2012 17:47:04 -0300 Subject: [PATCH 0255/5375] [media] dvb_usb_v2: suspend/resume stop/start USB streaming Stop remote polling and USB streaming before suspend and resume those when back to normal operation. It is far away from complete implementation, but at least it does not hang system anymore on suspend while streaming is ongoing. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 2 ++ drivers/media/dvb/dvb-usb/dvb_usb_init.c | 43 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index d0c628782f76..7e4832664f5d 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -356,6 +356,8 @@ struct dvb_usb_device { extern int dvb_usbv2_probe(struct usb_interface *, const struct usb_device_id *); extern void dvb_usbv2_disconnect(struct usb_interface *); +extern int dvb_usbv2_suspend(struct usb_interface *, pm_message_t); +extern int dvb_usbv2_resume(struct usb_interface *); /* the generic read/write method for device control */ extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16, diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 976a706b4cc7..60011f56cc90 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -439,6 +439,49 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) } EXPORT_SYMBOL(dvb_usbv2_disconnect); +int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + int i; + + pr_debug("%s:\n", __func__); + + /* stop remote controller poll */ + if (d->rc.query && !d->rc.bulk_mode) + cancel_delayed_work_sync(&d->rc_query_work); + + /* stop streaming */ + for (i = d->num_adapters_initialized - 1; i >= 0; i--) { + if (d->adapter[i].active_fe != -1) + usb_urb_killv2(&d->adapter[i].stream); + } + + return 0; +} +EXPORT_SYMBOL(dvb_usbv2_suspend); + +int dvb_usbv2_resume(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + int i; + + pr_debug("%s:\n", __func__); + + /* start streaming */ + for (i = 0; i < d->num_adapters_initialized; i++) { + if (d->adapter[i].active_fe != -1) + usb_urb_submitv2(&d->adapter[i].stream, NULL); + } + + /* start remote controller poll */ + if (d->rc.query && !d->rc.bulk_mode) + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); + + return 0; +} +EXPORT_SYMBOL(dvb_usbv2_resume); + MODULE_VERSION("1.0"); MODULE_AUTHOR("Patrick Boettcher "); MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); From b00a901801f671a48feac6048faeafe0979760e6 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 11 Jun 2012 23:35:09 -0300 Subject: [PATCH 0256/5375] [media] dvb_usb_v2: Cypress firmware download module Firmware handling routines for various Cypress chips. Cypress AN2135 Cypress AN2235 Cypress FX2 These were split out from general DVB USB module by Patrick Boettcher. I did only small changes. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 4 + drivers/media/dvb/dvb-usb/Makefile | 2 + drivers/media/dvb/dvb-usb/dvb_usb_firmware.c | 125 +++++++++++++++++++ drivers/media/dvb/dvb-usb/dvb_usb_firmware.h | 31 +++++ 4 files changed, 162 insertions(+) create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_firmware.c create mode 100644 drivers/media/dvb/dvb-usb/dvb_usb_firmware.h diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 2f6973a24cc6..3e75fcdb33cc 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -28,6 +28,10 @@ config DVB_USB_V2 Say Y if you own a USB DVB device. +config DVB_USB_FIRMWARE + tristate "Firmware helper routines" + depends on DVB_USB + config DVB_USB_DEBUG bool "Enable extended debug support for all DVB-USB devices" depends on DVB_USB diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 3c73e7b2a9f8..a0f5be28ca72 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -4,6 +4,8 @@ obj-$(CONFIG_DVB_USB) += dvb-usb.o dvb_usbv2-objs = dvb_usb_init.o dvb_usb_urb.o dvb_usb_dvb.o dvb_usb_remote.o usb_urb.o obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o +obj-$(CONFIG_DVB_USB_FIRMWARE) += dvb_usb_firmware.o + dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c new file mode 100644 index 000000000000..61c3fe9a599e --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c @@ -0,0 +1,125 @@ +/* dvb_usb_firmware.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 + * and 2 based devices. + * + */ + +#include "dvb_usb.h" +#include "dvb_usb_firmware.h" + +struct usb_cypress_controller { + u8 id; + const char *name; /* name of the usb controller */ + u16 cs_reg; /* needs to be restarted, + * when the firmware has been downloaded */ +}; + +static const struct usb_cypress_controller cypress[] = { + { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 }, + { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 }, + { .id = CYPRESS_FX2, .name = "Cypress FX2", .cs_reg = 0xe600 }, +}; + +/* + * load a firmware packet to the device + */ +static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data, + u8 len) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); +} + +int usbv2_cypress_load_firmware(struct usb_device *udev, + const struct firmware *fw, int type) +{ + struct hexline hx; + u8 reset; + int ret, pos = 0; + + /* stop the CPU */ + reset = 1; + ret = usb_cypress_writemem(udev, cypress[type].cs_reg, &reset, 1); + if (ret != 1) + pr_err("%s: could not stop the USB controller CPU", + KBUILD_MODNAME); + + while ((ret = dvb_usbv2_get_hexline(fw, &hx, &pos)) > 0) { + pr_debug("%s: writing to address %04x (buffer: %02x %02x)\n", + __func__, hx.addr, hx.len, hx.chk); + + ret = usb_cypress_writemem(udev, hx.addr, hx.data, hx.len); + if (ret != hx.len) { + pr_err("%s: error while transferring firmware " \ + "(transferred size=%d, block size=%d)", + KBUILD_MODNAME, ret, hx.len); + ret = -EINVAL; + break; + } + } + if (ret < 0) { + pr_err("%s: firmware download failed at %d with %d", + KBUILD_MODNAME, pos, ret); + return ret; + } + + if (ret == 0) { + /* restart the CPU */ + reset = 0; + if (ret || usb_cypress_writemem( + udev, cypress[type].cs_reg, &reset, 1) != 1) { + pr_err("%s: could not restart the USB controller CPU", + KBUILD_MODNAME); + ret = -EINVAL; + } + } else + ret = -EIO; + + return ret; +} +EXPORT_SYMBOL(usbv2_cypress_load_firmware); + +int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, + int *pos) +{ + u8 *b = (u8 *) &fw->data[*pos]; + int data_offs = 4; + + if (*pos >= fw->size) + return 0; + + memset(hx, 0, sizeof(struct hexline)); + + hx->len = b[0]; + + if ((*pos + hx->len + 4) >= fw->size) + return -EINVAL; + + hx->addr = b[1] | (b[2] << 8); + hx->type = b[3]; + + if (hx->type == 0x04) { + /* b[4] and b[5] are the Extended linear address record data + * field */ + hx->addr |= (b[4] << 24) | (b[5] << 16); + /* + hx->len -= 2; + data_offs += 2; + */ + } + memcpy(hx->data, &b[data_offs], hx->len); + hx->chk = b[hx->len + data_offs]; + + *pos += hx->len + 5; + + return *pos; +} +EXPORT_SYMBOL(dvb_usbv2_get_hexline); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Cypress firmware download"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.h b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.h new file mode 100644 index 000000000000..358d9d0b1899 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/dvb_usb_firmware.h @@ -0,0 +1,31 @@ +/* dvb_usb_firmware.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 + * and 2 based devices. + * + */ + +#ifndef DVB_USB_FIRMWARE_H +#define DVB_USB_FIRMWARE_H + +#define CYPRESS_AN2135 0 +#define CYPRESS_AN2235 1 +#define CYPRESS_FX2 2 + +/* commonly used firmware download types and function */ +struct hexline { + u8 len; + u32 addr; + u8 type; + u8 data[255]; + u8 chk; +}; +extern int usbv2_cypress_load_firmware(struct usb_device *, + const struct firmware *, int); +extern int dvb_usbv2_get_hexline(const struct firmware *, + struct hexline *, int *); + +#endif From 2d2b37c75a4f5eb919c10674a8c2f0f5a3ac40ec Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 12 Jun 2012 01:05:20 -0300 Subject: [PATCH 0257/5375] [media] dvb_usb_v2: move few callbacks one level up Move frontend_attach, tuner_attach, frontend_ctrl and streaming_ctrl from adapter to device. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 12 ++++-------- drivers/media/dvb/dvb-usb/dvb_usb.h | 9 ++++----- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 24 ++++++++++++------------ 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 9d0bd9bed739..73ff4bbb89ce 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -1319,8 +1319,10 @@ static struct dvb_usb_device_properties af9015_props = { .firmware = "dvb-usb-af9015.fw", .download_firmware = af9015_download_firmware, - .read_config = af9015_read_config, .i2c_algo = &af9015_i2c_algo, + .read_config = af9015_read_config, + .frontend_attach = af9015_af9013_frontend_attach, + .tuner_attach = af9015_tuner_attach, .init = af9015_init, .get_rc_config = af9015_get_rc_config, .get_usb_stream_config = af9015_get_usb_stream_config, @@ -1333,13 +1335,7 @@ static struct dvb_usb_device_properties af9015_props = { .pid_filter_count = 32, .pid_filter = af9015_pid_filter, .pid_filter_ctrl = af9015_pid_filter_ctrl, - .frontend_attach = af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, }, - { - .frontend_attach = af9015_af9013_frontend_attach, - .tuner_attach = af9015_tuner_attach, - } }, }; @@ -1427,9 +1423,9 @@ MODULE_DEVICE_TABLE(usb, af9015_id_table); /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver af9015_usb_driver = { .name = KBUILD_MODNAME, + .id_table = af9015_id_table, .probe = dvb_usbv2_probe, .disconnect = dvb_usbv2_disconnect, - .id_table = af9015_id_table, .no_dynamic_id = 1, .soft_unbind = 1, }; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 7e4832664f5d..fd6237a3a4ce 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -100,10 +100,6 @@ struct dvb_usb_adapter_properties { int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); - int (*frontend_attach) (struct dvb_usb_adapter *); - int (*tuner_attach) (struct dvb_usb_adapter *); - int (*frontend_ctrl) (struct dvb_frontend *, int); - int (*streaming_ctrl) (struct dvb_usb_adapter *, int); int (*fe_ioctl_override) (struct dvb_frontend *, unsigned int, void *, unsigned int); @@ -189,7 +185,10 @@ struct dvb_usb_device_properties { int (*power_ctrl) (struct dvb_usb_device *, int); int (*read_config) (struct dvb_usb_device *d); int (*read_mac_address) (struct dvb_usb_device *, u8 []); - int (*tuner_attach) (struct dvb_frontend *); + int (*frontend_attach) (struct dvb_usb_adapter *); + int (*tuner_attach) (struct dvb_usb_adapter *); + int (*frontend_ctrl) (struct dvb_frontend *, int); + int (*streaming_ctrl) (struct dvb_usb_adapter *, int); #define WARM 0 #define COLD 1 diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index a08d879fd177..11ac592270fe 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -80,8 +80,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) pr_debug("%s: stop feeding\n", __func__); usb_urb_killv2(&adap->stream); - if (adap->props.streaming_ctrl != NULL) { - ret = adap->props.streaming_ctrl(adap, 0); + if (adap->dev->props.streaming_ctrl != NULL) { + ret = adap->dev->props.streaming_ctrl(adap, 0); if (ret < 0) { pr_err("%s: error while stopping stream\n", KBUILD_MODNAME); @@ -157,8 +157,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } } pr_debug("%s: start feeding\n", __func__); - if (adap->props.streaming_ctrl != NULL) { - ret = adap->props.streaming_ctrl(adap, 1); + if (adap->dev->props.streaming_ctrl != NULL) { + ret = adap->dev->props.streaming_ctrl(adap, 1); if (ret < 0) { pr_err("%s: error while enabling fifo\n", KBUILD_MODNAME); @@ -279,8 +279,8 @@ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) if (ret < 0) goto err; - if (adap->props.frontend_ctrl) { - ret = adap->props.frontend_ctrl(fe, 1); + if (adap->dev->props.frontend_ctrl) { + ret = adap->dev->props.frontend_ctrl(fe, 1); if (ret < 0) goto err; } @@ -310,8 +310,8 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) goto err; } - if (adap->props.frontend_ctrl) { - ret = adap->props.frontend_ctrl(fe, 0); + if (adap->dev->props.frontend_ctrl) { + ret = adap->dev->props.frontend_ctrl(fe, 0); if (ret < 0) goto err; } @@ -337,8 +337,8 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) memset(adap->fe, 0, sizeof(adap->fe)); adap->active_fe = -1; - if (adap->props.frontend_attach) { - ret = adap->props.frontend_attach(adap); + if (adap->dev->props.frontend_attach) { + ret = adap->dev->props.frontend_attach(adap); if (ret < 0) { pr_debug("%s: frontend_attach() failed=%d\n", __func__, ret); @@ -350,8 +350,8 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) goto err; } - if (adap->props.tuner_attach) { - ret = adap->props.tuner_attach(adap); + if (adap->dev->props.tuner_attach) { + ret = adap->dev->props.tuner_attach(adap); if (ret < 0) { pr_debug("%s: tuner_attach() failed=%d\n", __func__, ret); From acaec14f3e75735aa473f881e540cdc6e43fabcc Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 12 Jun 2012 01:34:22 -0300 Subject: [PATCH 0258/5375] [media] dvb_usb_v2: use keyword const for USB ID table Let optimize that code to the text segment. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index fd6237a3a4ce..b4438173b25c 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -32,7 +32,7 @@ struct dvb_usb_driver_info { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ .idVendor = (vend), \ .idProduct = (prod), \ - .driver_info = (kernel_ulong_t) &((struct dvb_usb_driver_info) { \ + .driver_info = (kernel_ulong_t) &((const struct dvb_usb_driver_info) { \ .props = (props_), \ .name = (name_), \ .rc_map = (rc), \ From 53dc194f0c0b29c085baf33225b0c549876ad5f7 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 12 Jun 2012 02:20:01 -0300 Subject: [PATCH 0259/5375] [media] af9015: suspend/resume Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 73ff4bbb89ce..a9d9f9a23450 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -1426,6 +1426,8 @@ static struct usb_driver af9015_usb_driver = { .id_table = af9015_id_table, .probe = dvb_usbv2_probe, .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, .no_dynamic_id = 1, .soft_unbind = 1, }; From f093c388ef8ceff605f267ae9bc212ad98543ce6 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 12 Jun 2012 16:25:01 -0300 Subject: [PATCH 0260/5375] [media] dvb_usb_v2: use pointers to properties Use pointers to properties as device and adapter properties are constant. No need to embed and copy those structures. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 4 +- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 64 ++++++++++---------- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 69 +++++++++++----------- drivers/media/dvb/dvb-usb/dvb_usb_remote.c | 6 +- drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 10 ++-- 5 files changed, 75 insertions(+), 78 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index b4438173b25c..a972de6f8486 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -270,7 +270,7 @@ struct dvb_usb_adapter { #define DVB_USB_ADAP_STATE_DVB 0x001 int state; struct dvb_usb_device *dev; - struct dvb_usb_adapter_properties props; + const struct dvb_usb_adapter_properties *props; struct usb_data_stream stream; u8 id; @@ -316,7 +316,7 @@ struct dvb_usb_adapter { * in size_of_priv of dvb_usb_properties). */ struct dvb_usb_device { - struct dvb_usb_device_properties props; + const struct dvb_usb_device_properties *props; const char *name; const char *rc_map; struct dvb_usb_rc rc; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 11ac592270fe..a0f76eb2b6db 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -41,13 +41,13 @@ int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) adap->stream.user_priv = adap; /* resolve USB stream configuration for buffer alloc */ - if (adap->dev->props.get_usb_stream_config) { - ret = adap->dev->props.get_usb_stream_config(NULL, + if (adap->dev->props->get_usb_stream_config) { + ret = adap->dev->props->get_usb_stream_config(NULL, &stream_props); if (ret < 0) return ret; } else { - stream_props = adap->props.stream; + stream_props = adap->props->stream; } /* FIXME: can be removed as set later in anyway */ @@ -80,8 +80,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) pr_debug("%s: stop feeding\n", __func__); usb_urb_killv2(&adap->stream); - if (adap->dev->props.streaming_ctrl != NULL) { - ret = adap->dev->props.streaming_ctrl(adap, 0); + if (adap->dev->props->streaming_ctrl != NULL) { + ret = adap->dev->props->streaming_ctrl(adap, 0); if (ret < 0) { pr_err("%s: error while stopping stream\n", KBUILD_MODNAME); @@ -97,10 +97,10 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid, dvbdmxfeed->index, onoff ? "on" : "off"); - if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && adap->pid_filtering && - adap->props.pid_filter != NULL) - adap->props.pid_filter(adap, dvbdmxfeed->index, + adap->props->pid_filter != NULL) + adap->props->pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); /* start the feed if this was the first feed and there is still a feed @@ -111,8 +111,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) unsigned int ts_props; /* resolve TS configuration */ - if (adap->dev->props.get_ts_config) { - ret = adap->dev->props.get_ts_config( + if (adap->dev->props->get_ts_config) { + ret = adap->dev->props->get_ts_config( adap->fe[adap->active_fe], &ts_props); if (ret < 0) @@ -129,14 +129,14 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) adap->stream.complete = dvb_usb_data_complete; /* resolve USB stream configuration */ - if (adap->dev->props.get_usb_stream_config) { - ret = adap->dev->props.get_usb_stream_config( + if (adap->dev->props->get_usb_stream_config) { + ret = adap->dev->props->get_usb_stream_config( adap->fe[adap->active_fe], &stream_props); if (ret < 0) return ret; } else { - stream_props = adap->props.stream; + stream_props = adap->props->stream; } pr_debug("%s: submitting all URBs\n", __func__); @@ -144,11 +144,11 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) usb_urb_submitv2(&adap->stream, &stream_props); pr_debug("%s: controlling pid parser\n", __func__); - if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->props.caps & + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props->caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && - adap->props.pid_filter_ctrl != NULL) { - ret = adap->props.pid_filter_ctrl(adap, + adap->props->pid_filter_ctrl != NULL) { + ret = adap->props->pid_filter_ctrl(adap, adap->pid_filtering); if (ret < 0) { pr_err("%s: could not handle pid_parser\n", @@ -157,8 +157,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } } pr_debug("%s: start feeding\n", __func__); - if (adap->dev->props.streaming_ctrl != NULL) { - ret = adap->dev->props.streaming_ctrl(adap, 1); + if (adap->dev->props->streaming_ctrl != NULL) { + ret = adap->dev->props->streaming_ctrl(adap, 1); if (ret < 0) { pr_err("%s: error while enabling fifo\n", KBUILD_MODNAME); @@ -190,18 +190,18 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) { int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->name, - adap->dev->props.owner, + adap->dev->props->owner, &adap->dev->udev->dev, - adap->dev->props.adapter_nr); + adap->dev->props->adapter_nr); if (ret < 0) { pr_debug("%s: dvb_register_adapter failed=%d\n", __func__, ret); goto err; } adap->dvb_adap.priv = adap; - adap->dvb_adap.fe_ioctl_override = adap->props.fe_ioctl_override; + adap->dvb_adap.fe_ioctl_override = adap->props->fe_ioctl_override; - if (adap->dev->props.read_mac_address) { - if (adap->dev->props.read_mac_address(adap->dev, + if (adap->dev->props->read_mac_address) { + if (adap->dev->props->read_mac_address(adap->dev, adap->dvb_adap.proposed_mac) == 0) pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME, adap->dvb_adap.proposed_mac); @@ -279,8 +279,8 @@ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) if (ret < 0) goto err; - if (adap->dev->props.frontend_ctrl) { - ret = adap->dev->props.frontend_ctrl(fe, 1); + if (adap->dev->props->frontend_ctrl) { + ret = adap->dev->props->frontend_ctrl(fe, 1); if (ret < 0) goto err; } @@ -310,8 +310,8 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) goto err; } - if (adap->dev->props.frontend_ctrl) { - ret = adap->dev->props.frontend_ctrl(fe, 0); + if (adap->dev->props->frontend_ctrl) { + ret = adap->dev->props->frontend_ctrl(fe, 0); if (ret < 0) goto err; } @@ -337,8 +337,8 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) memset(adap->fe, 0, sizeof(adap->fe)); adap->active_fe = -1; - if (adap->dev->props.frontend_attach) { - ret = adap->dev->props.frontend_attach(adap); + if (adap->dev->props->frontend_attach) { + ret = adap->dev->props->frontend_attach(adap); if (ret < 0) { pr_debug("%s: frontend_attach() failed=%d\n", __func__, ret); @@ -350,8 +350,8 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) goto err; } - if (adap->dev->props.tuner_attach) { - ret = adap->dev->props.tuner_attach(adap); + if (adap->dev->props->tuner_attach) { + ret = adap->dev->props->tuner_attach(adap); if (ret < 0) { pr_debug("%s: tuner_attach() failed=%d\n", __func__, ret); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 60011f56cc90..be58b8422a33 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -30,14 +30,14 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d) const char *name; /* resolve firmware name */ - name = d->props.firmware; - if (d->props.get_firmware_name) { - ret = d->props.get_firmware_name(d, &name); + name = d->props->firmware; + if (d->props->get_firmware_name) { + ret = d->props->get_firmware_name(d, &name); if (ret < 0) goto err; } - if (!d->props.download_firmware) { + if (!d->props->download_firmware) { ret = -EINVAL; goto err; } @@ -54,7 +54,7 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d) pr_info("%s: downloading firmware from file '%s'\n", KBUILD_MODNAME, name); - ret = d->props.download_firmware(d, fw); + ret = d->props->download_firmware(d, fw); release_firmware(fw); @@ -71,13 +71,13 @@ static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) { int ret; - if (!d->props.i2c_algo) { + if (!d->props->i2c_algo) { ret = 0; goto err; } strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); - d->i2c_adap.algo = d->props.i2c_algo; + d->i2c_adap.algo = d->props->i2c_algo; d->i2c_adap.algo_data = NULL; d->i2c_adap.dev.parent = &d->udev->dev; @@ -113,9 +113,9 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) int ret, i, adapter_count; /* resolve adapter count */ - adapter_count = d->props.num_adapters; - if (d->props.get_adapter_count) { - ret = d->props.get_adapter_count(d); + adapter_count = d->props->num_adapters; + if (d->props->get_adapter_count) { + ret = d->props->get_adapter_count(d); if (ret < 0) goto err; @@ -125,28 +125,26 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) for (i = 0; i < adapter_count; i++) { adap = &d->adapter[i]; adap->dev = d; - adap->id = i; - - memcpy(&adap->props, &d->props.adapter[i], - sizeof(struct dvb_usb_adapter_properties)); + adap->id = i; + adap->props = &d->props->adapter[i]; /* speed - when running at FULL speed we need a HW PID filter */ if (d->udev->speed == USB_SPEED_FULL && - !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) { + !(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { pr_err("%s: this USB2.0 device cannot be run on a " \ "USB1.1 port (it lacks a hardware " \ "PID filter)\n", KBUILD_MODNAME); ret = -ENODEV; goto err; } else if ((d->udev->speed == USB_SPEED_FULL && - adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) || - (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { + adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || + (adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { pr_info("%s: will use the device's hardware PID " \ "filter (table count: %d)\n", KBUILD_MODNAME, - adap->props.pid_filter_count); + adap->props->pid_filter_count); adap->pid_filtering = 1; - adap->max_feed_count = adap->props.pid_filter_count; + adap->max_feed_count = adap->props->pid_filter_count; } else { pr_info("%s: will pass the complete MPEG2 transport " \ "stream to the software demuxer\n", @@ -156,11 +154,11 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) } if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && - adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) { + adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { pr_info("%s: pid filter enabled by module option\n", KBUILD_MODNAME); adap->pid_filtering = 1; - adap->max_feed_count = adap->props.pid_filter_count; + adap->max_feed_count = adap->props->pid_filter_count; } ret = dvb_usbv2_adapter_stream_init(adap); @@ -229,8 +227,8 @@ static int dvb_usbv2_init(struct dvb_usb_device *d) /* check the capabilities and set appropriate variables */ dvb_usbv2_device_power_ctrl(d, 1); - if (d->props.read_config) { - ret = d->props.read_config(d); + if (d->props->read_config) { + ret = d->props->read_config(d); if (ret < 0) goto err; } @@ -243,8 +241,8 @@ static int dvb_usbv2_init(struct dvb_usb_device *d) if (ret < 0) goto err; - if (d->props.init) { - ret = d->props.init(d); + if (d->props->init) { + ret = d->props->init(d); if (ret < 0) goto err; } @@ -274,8 +272,8 @@ int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */ pr_debug("%s: power control=%d\n", __func__, onoff); - if (d->props.power_ctrl) { - ret = d->props.power_ctrl(d, onoff); + if (d->props->power_ctrl) { + ret = d->props->power_ctrl(d, onoff); goto err; } } @@ -304,8 +302,8 @@ static void dvb_usbv2_init_work(struct work_struct *work) pr_debug("%s: work_pid=%d\n", __func__, d->work_pid); - if (d->props.size_of_priv) { - d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); + if (d->props->size_of_priv) { + d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL); if (!d->priv) { pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME); ret = -ENOMEM; @@ -313,8 +311,8 @@ static void dvb_usbv2_init_work(struct work_struct *work) } } - if (d->props.identify_state) { - ret = d->props.identify_state(d); + if (d->props->identify_state) { + ret = d->props->identify_state(d); if (ret == 0) { ; } else if (ret == COLD) { @@ -388,11 +386,10 @@ int dvb_usbv2_probe(struct usb_interface *intf, d->rc_map = driver_info->rc_map; d->udev = interface_to_usbdev(intf); d->intf = intf; - memcpy(&d->props, driver_info->props, - sizeof(struct dvb_usb_device_properties)); + d->props = driver_info->props; if (d->intf->cur_altsetting->desc.bInterfaceNumber != - d->props.bInterfaceNumber) { + d->props->bInterfaceNumber) { ret = -ENODEV; goto err_kfree; } @@ -428,8 +425,8 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) if (d->work_pid != current->pid) cancel_work_sync(&d->probe_work); - if (d->props.disconnect) - d->props.disconnect(d); + if (d->props->disconnect) + d->props->disconnect(d); name = d->name; dvb_usbv2_exit(d); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c index 4b7cd0e29bfa..f856ab6648c7 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c @@ -43,10 +43,10 @@ int dvb_usbv2_remote_init(struct dvb_usb_device *d) int ret; struct rc_dev *dev; - if (dvb_usbv2_disable_rc_polling || !d->props.get_rc_config) + if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) return 0; - ret = d->props.get_rc_config(d, &d->rc); + ret = d->props->get_rc_config(d, &d->rc); if (ret < 0) goto err; @@ -63,7 +63,7 @@ int dvb_usbv2_remote_init(struct dvb_usb_device *d) dev->input_phys = d->rc_phys; usb_to_input_id(d->udev, &dev->input_id); /* TODO: likely RC-core should took const char * */ - dev->driver_name = (char *) d->props.driver_name; + dev->driver_name = (char *) d->props->driver_name; dev->driver_type = d->rc.driver_type; dev->allowed_protos = d->rc.allowed_protos; dev->change_protocol = d->rc.change_protocol; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index a32722087a0c..75b7ac43810d 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -16,7 +16,7 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, if (!d || wbuf == NULL || wlen == 0) return -EINVAL; - if (d->props.generic_bulk_ctrl_endpoint == 0) { + if (d->props->generic_bulk_ctrl_endpoint == 0) { pr_err("%s: endpoint for generic control not specified\n", KBUILD_MODNAME); return -EINVAL; @@ -30,7 +30,7 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, 32, 1, wbuf, wlen, 0); ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint), wbuf, wlen, + d->props->generic_bulk_ctrl_endpoint), wbuf, wlen, &actlen, 2000); if (ret) @@ -45,9 +45,9 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, msleep(delay_ms); ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint_response ? - d->props.generic_bulk_ctrl_endpoint_response : - d->props.generic_bulk_ctrl_endpoint), + d->props->generic_bulk_ctrl_endpoint_response ? + d->props->generic_bulk_ctrl_endpoint_response : + d->props->generic_bulk_ctrl_endpoint), rbuf, rlen, &actlen, 2000); if (ret) From 3eee04722fa18f8e1db1730b2e508b6eb6f5336b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 12 Jun 2012 16:45:54 -0300 Subject: [PATCH 0261/5375] [media] ec168: convert to new DVB USB Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 +- drivers/media/dvb/dvb-usb/ec168.c | 315 +++++++++++++----------------- drivers/media/dvb/dvb-usb/ec168.h | 12 +- 3 files changed, 147 insertions(+), 182 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 3e75fcdb33cc..abbfd528a8db 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -374,7 +374,7 @@ config DVB_USB_FRIIO config DVB_USB_EC168 tristate "E3C EC168 DVB-T USB2.0 support" - depends on DVB_USB + depends on DVB_USB_V2 select DVB_EC100 select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE help diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c index b4989ba8897d..864195a56afb 100644 --- a/drivers/media/dvb/dvb-usb/ec168.c +++ b/drivers/media/dvb/dvb-usb/ec168.c @@ -29,17 +29,13 @@ module_param_named(debug, dvb_usb_ec168_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static struct ec100_config ec168_ec100_config; - -static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req) +static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) { int ret; unsigned int pipe; u8 request, requesttype; u8 *buf; - - switch (req->cmd) { case DOWNLOAD_FIRMWARE: case GPIO: @@ -83,15 +79,15 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req) if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { /* write */ memcpy(buf, req->data, req->size); - pipe = usb_sndctrlpipe(udev, 0); + pipe = usb_sndctrlpipe(d->udev, 0); } else { /* read */ - pipe = usb_rcvctrlpipe(udev, 0); + pipe = usb_rcvctrlpipe(d->udev, 0); } msleep(1); /* avoid I2C errors */ - ret = usb_control_msg(udev, pipe, request, requesttype, req->value, + ret = usb_control_msg(d->udev, pipe, request, requesttype, req->value, req->index, buf, req->size, EC168_USB_TIMEOUT); ec168_debug_dump(request, requesttype, req->value, req->index, buf, @@ -116,12 +112,9 @@ error: return ret; } -static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) -{ - return ec168_rw_udev(d->udev, req); -} - /* I2C */ +static struct ec100_config ec168_ec100_config; + static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { @@ -181,7 +174,6 @@ error: return i; } - static u32 ec168_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; @@ -193,6 +185,89 @@ static struct i2c_algorithm ec168_i2c_algo = { }; /* Callbacks for DVB USB */ +static int ec168_identify_state(struct dvb_usb_device *d) +{ + int ret; + u8 reply; + struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply}; + deb_info("%s:\n", __func__); + + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + deb_info("%s: reply:%02x\n", __func__, reply); + + if (reply == 0x01) + ret = WARM; + else + ret = COLD; + + return ret; +error: + deb_info("%s: failed:%d\n", __func__, ret); + return ret; +} + +static int ec168_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + int i, len, packets, remainder, ret; + u16 addr = 0x0000; /* firmware start address */ + struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL}; + deb_info("%s:\n", __func__); + + #define FW_PACKET_MAX_DATA 2048 + 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; + + req.size = len; + req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); + req.index = addr; + addr += FW_PACKET_MAX_DATA; + + ret = ec168_ctrl_msg(d, &req); + if (ret) { + err("firmware download failed:%d packet:%d", ret, i); + goto error; + } + } + req.size = 0; + + /* set "warm"? */ + req.cmd = SET_CONFIG; + req.value = 0; + req.index = 0x0001; + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + /* really needed - no idea what does */ + req.cmd = GPIO; + req.value = 0; + req.index = 0x0206; + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + /* activate tuner I2C? */ + req.cmd = WRITE_I2C; + req.value = 0; + req.index = 0x00c6; + ret = ec168_ctrl_msg(d, &req); + if (ret) + goto error; + + return ret; +error: + deb_info("%s: failed:%d\n", __func__, ret); + return ret; +} + static struct ec100_config ec168_ec100_config = { .demod_address = 0xff, /* not real address, demod is integrated */ }; @@ -200,9 +275,9 @@ static struct ec100_config ec168_ec100_config = { static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - adap->fe_adap[0].fe = dvb_attach(ec100_attach, &ec168_ec100_config, + adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config, &adap->dev->i2c_adap); - if (adap->fe_adap[0].fe == NULL) + if (adap->fe[0] == NULL) return -ENODEV; return 0; @@ -228,8 +303,9 @@ static struct mxl5005s_config ec168_mxl5003s_config = { static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - return dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, - &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; + return dvb_attach(mxl5005s_attach, adap->fe[0], + &adap->dev->i2c_adap, + &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; } static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) @@ -241,152 +317,27 @@ static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return ec168_ctrl_msg(adap->dev, &req); } -static int ec168_download_firmware(struct usb_device *udev, - const struct firmware *fw) -{ - int i, len, packets, remainder, ret; - u16 addr = 0x0000; /* firmware start address */ - struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL}; - deb_info("%s:\n", __func__); - - #define FW_PACKET_MAX_DATA 2048 - 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; - - req.size = len; - req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); - req.index = addr; - addr += FW_PACKET_MAX_DATA; - - ret = ec168_rw_udev(udev, &req); - if (ret) { - err("firmware download failed:%d packet:%d", ret, i); - goto error; - } - } - req.size = 0; - - /* set "warm"? */ - req.cmd = SET_CONFIG; - req.value = 0; - req.index = 0x0001; - ret = ec168_rw_udev(udev, &req); - if (ret) - goto error; - - /* really needed - no idea what does */ - req.cmd = GPIO; - req.value = 0; - req.index = 0x0206; - ret = ec168_rw_udev(udev, &req); - if (ret) - goto error; - - /* activate tuner I2C? */ - req.cmd = WRITE_I2C; - req.value = 0; - req.index = 0x00c6; - ret = ec168_rw_udev(udev, &req); - if (ret) - goto error; - - return ret; -error: - deb_info("%s: failed:%d\n", __func__, ret); - return ret; -} - -static int ec168_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, int *cold) -{ - int ret; - u8 reply; - struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply}; - deb_info("%s:\n", __func__); - - ret = ec168_rw_udev(udev, &req); - if (ret) - goto error; - - deb_info("%s: reply:%02x\n", __func__, reply); - - if (reply == 0x01) - *cold = 0; - else - *cold = 1; - - return ret; -error: - deb_info("%s: failed:%d\n", __func__, ret); - return ret; -} - /* DVB USB Driver stuff */ -static struct dvb_usb_device_properties ec168_properties; +/* bInterfaceNumber 0 is HID + * bInterfaceNumber 1 is DVB-T */ +static struct dvb_usb_device_properties ec168_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .bInterfaceNumber = 1, -static int ec168_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret; - deb_info("%s: interface:%d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); - - ret = dvb_usb_device_init(intf, &ec168_properties, THIS_MODULE, NULL, - adapter_nr); - if (ret) - goto error; - - return ret; -error: - deb_info("%s: failed:%d\n", __func__, ret); - return ret; -} - -#define E3C_EC168_1689 0 -#define E3C_EC168_FFFA 1 -#define E3C_EC168_FFFB 2 -#define E3C_EC168_1001 3 -#define E3C_EC168_1002 4 - -static struct usb_device_id ec168_id[] = { - [E3C_EC168_1689] = - {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168)}, - [E3C_EC168_FFFA] = - {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2)}, - [E3C_EC168_FFFB] = - {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3)}, - [E3C_EC168_1001] = - {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4)}, - [E3C_EC168_1002] = - {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5)}, - {} /* terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, ec168_id); - -static struct dvb_usb_device_properties ec168_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = ec168_download_firmware, + .identify_state = ec168_identify_state, .firmware = "dvb-usb-ec168.fw", - .no_reconnect = 1, + .download_firmware = ec168_download_firmware, - .size_of_priv = 0, + .i2c_algo = &ec168_i2c_algo, + .frontend_attach = ec168_ec100_frontend_attach, + .tuner_attach = ec168_mxl5003s_tuner_attach, + .streaming_ctrl = ec168_streaming_ctrl, .num_adapters = 1, .adapter = { { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = ec168_streaming_ctrl, - .frontend_attach = ec168_ec100_frontend_attach, - .tuner_attach = ec168_mxl5003s_tuner_attach, .stream = { .type = USB_BULK, .count = 6, @@ -397,35 +348,39 @@ static struct dvb_usb_device_properties ec168_properties = { } } }, - }}, } }, - - .identify_state = ec168_identify_state, - - .i2c_algo = &ec168_i2c_algo, - - .num_device_descs = 1, - .devices = { - { - .name = "E3C EC168 DVB-T USB2.0 reference design", - .cold_ids = { - &ec168_id[E3C_EC168_1689], - &ec168_id[E3C_EC168_FFFA], - &ec168_id[E3C_EC168_FFFB], - &ec168_id[E3C_EC168_1001], - &ec168_id[E3C_EC168_1002], - NULL}, - .warm_ids = {NULL}, - }, - } }; +static const struct dvb_usb_driver_info ec168_driver_info = { + .name = "E3C EC168 reference design", + .props = &ec168_props, +}; + +static const struct usb_device_id ec168_id[] = { + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5), + .driver_info = (kernel_ulong_t) &ec168_driver_info }, + {} +}; +MODULE_DEVICE_TABLE(usb, ec168_id); + static struct usb_driver ec168_driver = { - .name = "dvb_usb_ec168", - .probe = ec168_probe, - .disconnect = dvb_usb_device_exit, - .id_table = ec168_id, + .name = KBUILD_MODNAME, + .id_table = ec168_id, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, }; module_usb_driver(ec168_driver); diff --git a/drivers/media/dvb/dvb-usb/ec168.h b/drivers/media/dvb/dvb-usb/ec168.h index e7e0b831314e..b33267b0e5cb 100644 --- a/drivers/media/dvb/dvb-usb/ec168.h +++ b/drivers/media/dvb/dvb-usb/ec168.h @@ -23,7 +23,17 @@ #define EC168_H #define DVB_USB_LOG_PREFIX "ec168" -#include "dvb-usb.h" +#include "dvb_usb.h" + +#ifdef CONFIG_DVB_USB_DEBUG +#define dprintk(var, level, args...) \ + do { if ((var & level)) printk(args); } while (0) +#define DVB_USB_DEBUG_STATUS +#else +#define dprintk(args...) +#define debug_dump(b, l, func) +#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" +#endif #define deb_info(args...) dprintk(dvb_usb_ec168_debug, 0x01, args) #define deb_rc(args...) dprintk(dvb_usb_ec168_debug, 0x02, args) From ce6ea9a9424b5c511ea6d7b86081f01fa53d02b4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 12 Jun 2012 20:40:21 -0300 Subject: [PATCH 0262/5375] [media] ec168: switch Kernel pr_* logging Change logging. Some minor text and error number changes. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/ec168.c | 38 +++++++++++++++---------------- drivers/media/dvb/dvb-usb/ec168.h | 34 ++++++--------------------- 2 files changed, 25 insertions(+), 47 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c index 864195a56afb..717c66a4bddd 100644 --- a/drivers/media/dvb/dvb-usb/ec168.c +++ b/drivers/media/dvb/dvb-usb/ec168.c @@ -23,10 +23,6 @@ #include "ec100.h" #include "mxl5005s.h" -/* debug */ -static int dvb_usb_ec168_debug; -module_param_named(debug, dvb_usb_ec168_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) @@ -65,8 +61,8 @@ static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) request = DEMOD_RW; break; default: - err("unknown command:%02x", req->cmd); - ret = -EPERM; + pr_err("%s: unknown command=%02x\n", KBUILD_MODNAME, req->cmd); + ret = -EINVAL; goto error; } @@ -91,7 +87,7 @@ static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) req->index, buf, req->size, EC168_USB_TIMEOUT); ec168_debug_dump(request, requesttype, req->value, req->index, buf, - req->size, deb_xfer); + req->size); if (ret < 0) goto err_dealloc; @@ -108,7 +104,7 @@ static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) err_dealloc: kfree(buf); error: - deb_info("%s: failed:%d\n", __func__, ret); + pr_debug("%s: failed=%d\n", __func__, ret); return ret; } @@ -140,8 +136,9 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], ret = ec168_ctrl_msg(d, &req); i += 2; } else { - err("I2C read not implemented"); - ret = -ENOSYS; + pr_err("%s: I2C read not implemented\n", + KBUILD_MODNAME); + ret = -EOPNOTSUPP; i += 2; } } else { @@ -190,13 +187,13 @@ static int ec168_identify_state(struct dvb_usb_device *d) int ret; u8 reply; struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply}; - deb_info("%s:\n", __func__); + pr_debug("%s:\n", __func__); ret = ec168_ctrl_msg(d, &req); if (ret) goto error; - deb_info("%s: reply:%02x\n", __func__, reply); + pr_debug("%s: reply=%02x\n", __func__, reply); if (reply == 0x01) ret = WARM; @@ -205,7 +202,7 @@ static int ec168_identify_state(struct dvb_usb_device *d) return ret; error: - deb_info("%s: failed:%d\n", __func__, ret); + pr_debug("%s: failed=%d\n", __func__, ret); return ret; } @@ -215,7 +212,7 @@ static int ec168_download_firmware(struct dvb_usb_device *d, int i, len, packets, remainder, ret; u16 addr = 0x0000; /* firmware start address */ struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL}; - deb_info("%s:\n", __func__); + pr_debug("%s:\n", __func__); #define FW_PACKET_MAX_DATA 2048 packets = fw->size / FW_PACKET_MAX_DATA; @@ -232,7 +229,8 @@ static int ec168_download_firmware(struct dvb_usb_device *d, ret = ec168_ctrl_msg(d, &req); if (ret) { - err("firmware download failed:%d packet:%d", ret, i); + pr_err("%s: firmware download failed=%d packet=%d\n", + KBUILD_MODNAME, ret, i); goto error; } } @@ -264,7 +262,7 @@ static int ec168_download_firmware(struct dvb_usb_device *d, return ret; error: - deb_info("%s: failed:%d\n", __func__, ret); + pr_debug("%s: failed=%d\n", __func__, ret); return ret; } @@ -274,7 +272,7 @@ static struct ec100_config ec168_ec100_config = { static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) { - deb_info("%s:\n", __func__); + pr_debug("%s:\n", __func__); adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config, &adap->dev->i2c_adap); if (adap->fe[0] == NULL) @@ -302,7 +300,7 @@ static struct mxl5005s_config ec168_mxl5003s_config = { static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { - deb_info("%s:\n", __func__); + pr_debug("%s:\n", __func__); return dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; @@ -311,7 +309,7 @@ static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL}; - deb_info("%s: onoff:%d\n", __func__, onoff); + pr_debug("%s: onoff=%d\n", __func__, onoff); if (onoff) req.index = 0x0102; return ec168_ctrl_msg(adap->dev, &req); @@ -386,5 +384,5 @@ static struct usb_driver ec168_driver = { module_usb_driver(ec168_driver); MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("E3C EC168 DVB-T USB2.0 driver"); +MODULE_DESCRIPTION("E3C EC168 driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/ec168.h b/drivers/media/dvb/dvb-usb/ec168.h index b33267b0e5cb..9181236f6ebc 100644 --- a/drivers/media/dvb/dvb-usb/ec168.h +++ b/drivers/media/dvb/dvb-usb/ec168.h @@ -22,37 +22,17 @@ #ifndef EC168_H #define EC168_H -#define DVB_USB_LOG_PREFIX "ec168" #include "dvb_usb.h" -#ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var, level, args...) \ - do { if ((var & level)) printk(args); } while (0) -#define DVB_USB_DEBUG_STATUS -#else -#define dprintk(args...) -#define debug_dump(b, l, func) -#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" -#endif - -#define deb_info(args...) dprintk(dvb_usb_ec168_debug, 0x01, args) -#define deb_rc(args...) dprintk(dvb_usb_ec168_debug, 0x02, args) -#define deb_xfer(args...) dprintk(dvb_usb_ec168_debug, 0x04, args) -#define deb_reg(args...) dprintk(dvb_usb_ec168_debug, 0x08, args) -#define deb_i2c(args...) dprintk(dvb_usb_ec168_debug, 0x10, args) -#define deb_fw(args...) dprintk(dvb_usb_ec168_debug, 0x20, args) - -#define ec168_debug_dump(r, t, v, i, b, l, func) { \ - int loop_; \ - func("%02x %02x %02x %02x %02x %02x %02x %02x", \ - t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \ +#define ec168_debug_dump(r, t, v, i, b, l) { \ + char *direction; \ if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ - func(" >>> "); \ + direction = ">>>"; \ else \ - func(" <<< "); \ - for (loop_ = 0; loop_ < l; loop_++) \ - func("%02x ", b[loop_]); \ - func("\n");\ + direction = "<<<"; \ + pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s\n", \ + __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \ + l & 0xff, l >> 8, direction); \ } #define EC168_USB_TIMEOUT 1000 From d32be21800feb38d51a584437f1a5eb3f4126a17 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 12 Jun 2012 21:16:52 -0300 Subject: [PATCH 0263/5375] [media] dvb_usb_v2: do not check active fe when stop streaming Do not check active frontend as it could be already shutdown. Add some more debugs. It turns out that device is put sleep earlier than streaming is stopped in some cases. That is because streaming is running different task and there is no locking. Maybe some locking could be good idea to force stop streaming before device is shut down. I can guess there could be problems in someday cases like chip is sleep but streaming control is requested after that... Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 28 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index a0f76eb2b6db..f302e63a0d8f 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -68,11 +68,14 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; int newfeedcount, ret; - if (adap == NULL || adap->active_fe < 0) { + if (adap == NULL) { ret = -ENODEV; goto err; } + pr_debug("%s: adap=%d active_fe=%d\n", __func__, adap->id, + adap->active_fe); + newfeedcount = adap->feedcount + (onoff ? 1 : -1); /* stop feed before setting a new pid if there will be no pid anymore */ @@ -189,12 +192,15 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) { - int ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->name, - adap->dev->props->owner, - &adap->dev->udev->dev, - adap->dev->props->adapter_nr); + int ret; + pr_debug("%s: adap=%d\n", __func__, adap->id); + + ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->name, + adap->dev->props->owner, &adap->dev->udev->dev, + adap->dev->props->adapter_nr); if (ret < 0) { - pr_debug("%s: dvb_register_adapter failed=%d\n", __func__, ret); + pr_debug("%s: dvb_register_adapter() failed=%d\n", __func__, + ret); goto err; } adap->dvb_adap.priv = adap; @@ -258,6 +264,8 @@ err: int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) { + pr_debug("%s: adap=%d\n", __func__, adap->id); + if (adap->state & DVB_USB_ADAP_STATE_DVB) { pr_debug("%s: unregistering DVB part\n", __func__); dvb_net_release(&adap->dvb_net); @@ -274,6 +282,7 @@ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) { int ret; struct dvb_usb_adapter *adap = fe->dvb->priv; + pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); ret = dvb_usbv2_device_power_ctrl(adap->dev, 1); if (ret < 0) @@ -303,6 +312,7 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) { int ret; struct dvb_usb_adapter *adap = fe->dvb->priv; + pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); if (adap->fe_sleep[fe->id]) { ret = adap->fe_sleep[fe->id](fe); @@ -331,8 +341,7 @@ err: int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) { int ret, i, count_registered = 0; - - pr_debug("%s:\n", __func__); + pr_debug("%s: adap=%d\n", __func__, adap->id); memset(adap->fe, 0, sizeof(adap->fe)); adap->active_fe = -1; @@ -400,8 +409,7 @@ err: int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) { int i; - - pr_debug("%s:\n", __func__); + pr_debug("%s: adap=%d\n", __func__, adap->id); for (i = adap->num_frontends_initialized - 1; i >= 0; i--) { if (adap->fe[i]) { From 77e28ec27927dbb130d84a9fe7cbe85bf6bf47ea Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 12 Jun 2012 22:16:12 -0300 Subject: [PATCH 0264/5375] [media] ec168: re-implement firmware loading Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/ec168.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c index 717c66a4bddd..3ed80b01d5fa 100644 --- a/drivers/media/dvb/dvb-usb/ec168.c +++ b/drivers/media/dvb/dvb-usb/ec168.c @@ -209,31 +209,28 @@ error: static int ec168_download_firmware(struct dvb_usb_device *d, const struct firmware *fw) { - int i, len, packets, remainder, ret; - u16 addr = 0x0000; /* firmware start address */ + int ret, len, remaining; struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL}; pr_debug("%s:\n", __func__); - #define FW_PACKET_MAX_DATA 2048 - 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 LEN_MAX 2048 /* max packet size */ + for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { + len = remaining; + if (len > LEN_MAX) + len = LEN_MAX; req.size = len; - req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); - req.index = addr; - addr += FW_PACKET_MAX_DATA; + req.data = (u8 *) &fw->data[fw->size - remaining]; + req.index = fw->size - remaining; ret = ec168_ctrl_msg(d, &req); if (ret) { - pr_err("%s: firmware download failed=%d packet=%d\n", - KBUILD_MODNAME, ret, i); + pr_err("%s: firmware download failed=%d\n", + KBUILD_MODNAME, ret); goto error; } } + req.size = 0; /* set "warm"? */ From cb4f77a385c3a6037c2c14d4aede7257e8dd2a6c Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 12 Jun 2012 22:49:54 -0300 Subject: [PATCH 0265/5375] [media] au6610: convert to new DVB USB Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 +- drivers/media/dvb/dvb-usb/au6610.c | 99 ++++++++++-------------------- drivers/media/dvb/dvb-usb/au6610.h | 13 +--- 3 files changed, 36 insertions(+), 78 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index abbfd528a8db..fbca7a076236 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -173,7 +173,7 @@ config DVB_USB_GL861 config DVB_USB_AU6610 tristate "Alcor Micro AU6610 USB2.0 support" - depends on DVB_USB + depends on DVB_USB_V2 select DVB_ZL10353 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE help diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c index 16210c060302..aaa0fec7d6a8 100644 --- a/drivers/media/dvb/dvb-usb/au6610.c +++ b/drivers/media/dvb/dvb-usb/au6610.c @@ -22,10 +22,6 @@ #include "zl10353.h" #include "qt1010.h" -/* debug */ -static int dvb_usb_au6610_debug; -module_param_named(debug, dvb_usb_au6610_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, @@ -52,7 +48,7 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr, index += wbuf[1]; break; default: - warn("wlen = %x, aborting.", wlen); + pr_err("%s: wlen = %d, aborting\n", KBUILD_MODNAME, wlen); ret = -EINVAL; goto error; } @@ -140,9 +136,9 @@ static struct zl10353_config au6610_zl10353_config = { static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &au6610_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe_adap[0].fe == NULL) + if (adap->fe[0] == NULL) return -ENODEV; return 0; @@ -155,60 +151,30 @@ static struct qt1010_config au6610_qt1010_config = { static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(qt1010_attach, - adap->fe_adap[0].fe, &adap->dev->i2c_adap, + adap->fe[0], &adap->dev->i2c_adap, &au6610_qt1010_config) == NULL ? -ENODEV : 0; } -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties au6610_properties; - -static int au6610_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static int au6610_init(struct dvb_usb_device *d) { - struct dvb_usb_device *d; - struct usb_host_interface *alt; - int ret; - - if (intf->num_altsetting < AU6610_ALTSETTING_COUNT) - return -ENODEV; - - ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d, - adapter_nr); - if (ret == 0) { - alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING); - - if (alt == NULL) { - deb_info("%s: no alt found!\n", __func__); - return -ENODEV; - } - ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - } - - return ret; + /* TODO: this functionality belongs likely to the streaming control */ + /* bInterfaceNumber 0, bAlternateSetting 5 */ + return usb_set_interface(d->udev, 0, 5); } -static struct usb_device_id au6610_table [] = { - { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, au6610_table); +static struct dvb_usb_device_properties au6610_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, -static struct dvb_usb_device_properties au6610_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - - .size_of_priv = 0, + .i2c_algo = &au6610_i2c_algo, + .frontend_attach = au6610_zl10353_frontend_attach, + .tuner_attach = au6610_qt1010_tuner_attach, + .init = au6610_init, .num_adapters = 1, .adapter = { { - .num_frontends = 1, - .fe = {{ - .frontend_attach = au6610_zl10353_frontend_attach, - .tuner_attach = au6610_qt1010_tuner_attach, - .stream = { .type = USB_ISOC, .count = 5, @@ -221,27 +187,26 @@ static struct dvb_usb_device_properties au6610_properties = { } } }, - }}, - } - }, - - .i2c_algo = &au6610_i2c_algo, - - .num_device_descs = 1, - .devices = { - { - .name = "Sigmatek DVB-110 DVB-T USB2.0", - .cold_ids = {NULL}, - .warm_ids = {&au6610_table[0], NULL}, }, - } + }, }; +static const struct usb_device_id au6610_id_table[] = { + { DVB_USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110, + &au6610_props, "Sigmatek DVB-110", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, au6610_id_table); + static struct usb_driver au6610_driver = { - .name = "dvb_usb_au6610", - .probe = au6610_probe, - .disconnect = dvb_usb_device_exit, - .id_table = au6610_table, + .name = KBUILD_MODNAME, + .id_table = au6610_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, }; module_usb_driver(au6610_driver); diff --git a/drivers/media/dvb/dvb-usb/au6610.h b/drivers/media/dvb/dvb-usb/au6610.h index 7849abe2c614..ea337bfc00b1 100644 --- a/drivers/media/dvb/dvb-usb/au6610.h +++ b/drivers/media/dvb/dvb-usb/au6610.h @@ -18,13 +18,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef _DVB_USB_AU6610_H_ -#define _DVB_USB_AU6610_H_ - -#define DVB_USB_LOG_PREFIX "au6610" -#include "dvb-usb.h" - -#define deb_info(args...) dprintk(dvb_usb_au6610_debug, 0x01, args) +#ifndef AU6610_H +#define AU6610_H +#include "dvb_usb.h" #define AU6610_REQ_I2C_WRITE 0x14 #define AU6610_REQ_I2C_READ 0x13 @@ -33,7 +29,4 @@ #define AU6610_USB_TIMEOUT 1000 -#define AU6610_ALTSETTING_COUNT 6 -#define AU6610_ALTSETTING 5 - #endif From 877e0aa790727eb7ceae189a721798424d820a0c Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 12 Jun 2012 23:19:40 -0300 Subject: [PATCH 0266/5375] [media] dvb_usb_v2: move remote controller to the main file It is only three functions so move it to the main. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Makefile | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 3 - drivers/media/dvb/dvb-usb/dvb_usb_init.c | 103 +++++++++++++++++++++ 3 files changed, 104 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index a0f5be28ca72..490e2a295f3f 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -1,7 +1,7 @@ dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o obj-$(CONFIG_DVB_USB) += dvb-usb.o -dvb_usbv2-objs = dvb_usb_init.o dvb_usb_urb.o dvb_usb_dvb.o dvb_usb_remote.o usb_urb.o +dvb_usbv2-objs = dvb_usb_init.o dvb_usb_urb.o dvb_usb_dvb.o usb_urb.o obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o obj-$(CONFIG_DVB_USB_FIRMWARE) += dvb_usb_firmware.o diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index dcdccb7fde31..e1cff154c0ec 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -31,7 +31,4 @@ extern int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap); extern int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap); extern int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap); -extern int dvb_usbv2_remote_init(struct dvb_usb_device *); -extern int dvb_usbv2_remote_exit(struct dvb_usb_device *); - #endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index be58b8422a33..ecc6bd253497 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -12,6 +12,7 @@ * see Documentation/dvb/README.dvb-usb for more information */ #include "dvb_usb_common.h" +#include int dvb_usbv2_disable_rc_polling; module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644); @@ -107,6 +108,108 @@ static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) return 0; } +static void dvb_usb_read_remote_control(struct work_struct *work) +{ + struct dvb_usb_device *d = container_of(work, + struct dvb_usb_device, rc_query_work.work); + int ret; + + /* TODO: need a lock here. We can simply skip checking for the remote + control if we're busy. */ + + /* when the parameter has been set to 1 via sysfs while the + * driver was running, or when bulk mode is enabled after IR init + */ + if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) + return; + + ret = d->rc.query(d); + if (ret < 0) + pr_err("%s: error %d while querying for an remote control " \ + "event\n", KBUILD_MODNAME, ret); + + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); +} + +static int dvb_usbv2_remote_init(struct dvb_usb_device *d) +{ + int ret; + struct rc_dev *dev; + + if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) + return 0; + + ret = d->props->get_rc_config(d, &d->rc); + if (ret < 0) + goto err; + + dev = rc_allocate_device(); + if (!dev) { + ret = -ENOMEM; + goto err; + } + + dev->dev.parent = &d->udev->dev; + dev->input_name = "IR-receiver inside an USB DVB receiver"; + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + dev->input_phys = d->rc_phys; + usb_to_input_id(d->udev, &dev->input_id); + /* TODO: likely RC-core should took const char * */ + dev->driver_name = (char *) d->props->driver_name; + dev->driver_type = d->rc.driver_type; + dev->allowed_protos = d->rc.allowed_protos; + dev->change_protocol = d->rc.change_protocol; + dev->priv = d; + /* select used keymap */ + if (d->rc.map_name) + dev->map_name = d->rc.map_name; + else if (d->rc_map) + dev->map_name = d->rc_map; + else + dev->map_name = RC_MAP_EMPTY; /* keep rc enabled */ + + ret = rc_register_device(dev); + if (ret < 0) { + rc_free_device(dev); + goto err; + } + + d->input_dev = NULL; + d->rc_dev = dev; + + /* start polling if needed */ + if (d->rc.query && !d->rc.bulk_mode) { + /* initialize a work queue for handling polling */ + INIT_DELAYED_WORK(&d->rc_query_work, + dvb_usb_read_remote_control); + pr_info("%s: schedule remote query interval to %d msecs\n", + KBUILD_MODNAME, d->rc.interval); + schedule_delayed_work(&d->rc_query_work, + msecs_to_jiffies(d->rc.interval)); + } + + d->state |= DVB_USB_STATE_REMOTE; + + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) +{ + if (d->state & DVB_USB_STATE_REMOTE) { + cancel_delayed_work_sync(&d->rc_query_work); + rc_unregister_device(d->rc_dev); + } + + d->state &= ~DVB_USB_STATE_REMOTE; + + return 0; +} + static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) { struct dvb_usb_adapter *adap; From ab84f182f0cd49f9fe3fda90eb19d98d9e226933 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 13 Jun 2012 23:03:08 -0300 Subject: [PATCH 0267/5375] [media] ce6230: convert to new DVB USB Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 +- drivers/media/dvb/dvb-usb/ce6230.c | 110 +++++++++-------------------- drivers/media/dvb/dvb-usb/ce6230.h | 18 ++++- 3 files changed, 53 insertions(+), 77 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index fbca7a076236..52b3108601a6 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -360,7 +360,7 @@ config DVB_USB_AF9015 config DVB_USB_CE6230 tristate "Intel CE6230 DVB-T USB2.0 support" - depends on DVB_USB + depends on DVB_USB_V2 select DVB_ZL10353 select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE help diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c index fa637255729c..ee6a4019dd8e 100644 --- a/drivers/media/dvb/dvb-usb/ce6230.c +++ b/drivers/media/dvb/dvb-usb/ce6230.c @@ -31,7 +31,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static struct zl10353_config ce6230_zl10353_config; -static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req) +static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) { int ret; unsigned int pipe; @@ -71,15 +71,15 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req) if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { /* write */ memcpy(buf, req->data, req->data_len); - pipe = usb_sndctrlpipe(udev, 0); + pipe = usb_sndctrlpipe(d->udev, 0); } else { /* read */ - pipe = usb_rcvctrlpipe(udev, 0); + pipe = usb_rcvctrlpipe(d->udev, 0); } msleep(1); /* avoid I2C errors */ - ret = usb_control_msg(udev, pipe, request, requesttype, value, index, + ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index, buf, req->data_len, CE6230_USB_TIMEOUT); ce6230_debug_dump(request, requesttype, value, index, buf, @@ -99,11 +99,6 @@ error: return ret; } -static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) -{ - return ce6230_rw_udev(d->udev, req); -} - /* I2C */ static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) @@ -186,9 +181,9 @@ static struct zl10353_config ce6230_zl10353_config = { static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe_adap[0].fe == NULL) + if (adap->fe[0] == NULL) return -ENODEV; return 0; } @@ -214,7 +209,7 @@ static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { int ret; deb_info("%s:\n", __func__); - ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; return ret; } @@ -234,49 +229,20 @@ static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff) } /* DVB USB Driver stuff */ -static struct dvb_usb_device_properties ce6230_properties; +static struct dvb_usb_device_properties ce6230_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .bInterfaceNumber = 1, -static int ce6230_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret = 0; - struct dvb_usb_device *d = NULL; - - deb_info("%s: interface:%d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); - - if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { - ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE, - &d, adapter_nr); - if (ret) - err("init failed with error:%d\n", ret); - } - - return ret; -} - -static struct usb_device_id ce6230_table[] = { - { USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, ce6230_table); - -static struct dvb_usb_device_properties ce6230_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .no_reconnect = 1, - - .size_of_priv = 0, + .i2c_algo = &ce6230_i2c_algo, + .power_ctrl = ce6230_power_ctrl, + .frontend_attach = ce6230_zl10353_frontend_attach, + .tuner_attach = ce6230_mxl5003s_tuner_attach, .num_adapters = 1, .adapter = { { - .num_frontends = 1, - .fe = {{ - .frontend_attach = ce6230_zl10353_frontend_attach, - .tuner_attach = ce6230_mxl5003s_tuner_attach, .stream = { .type = USB_BULK, .count = 6, @@ -287,37 +253,31 @@ static struct dvb_usb_device_properties ce6230_properties = { } } }, - }}, } }, - - .power_ctrl = ce6230_power_ctrl, - - .i2c_algo = &ce6230_i2c_algo, - - .num_device_descs = 2, - .devices = { - { - .name = "Intel CE9500 reference design", - .cold_ids = {NULL}, - .warm_ids = {&ce6230_table[0], NULL}, - }, - { - .name = "AVerMedia A310 USB 2.0 DVB-T tuner", - .cold_ids = {NULL}, - .warm_ids = {&ce6230_table[1], NULL}, - }, - } }; -static struct usb_driver ce6230_driver = { - .name = "dvb_usb_ce6230", - .probe = ce6230_probe, - .disconnect = dvb_usb_device_exit, - .id_table = ce6230_table, +static const struct usb_device_id ce6230_id_table[] = { + { DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500, + &ce6230_props, "Intel CE9500 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310, + &ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, ce6230_id_table); + +static struct usb_driver ce6230_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = ce6230_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, }; -module_usb_driver(ce6230_driver); +module_usb_driver(ce6230_usb_driver); MODULE_AUTHOR("Antti Palosaari "); MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0"); diff --git a/drivers/media/dvb/dvb-usb/ce6230.h b/drivers/media/dvb/dvb-usb/ce6230.h index 97c42482ccb3..7c219539fbd8 100644 --- a/drivers/media/dvb/dvb-usb/ce6230.h +++ b/drivers/media/dvb/dvb-usb/ce6230.h @@ -23,7 +23,23 @@ #define _DVB_USB_CE6230_H_ #define DVB_USB_LOG_PREFIX "ce6230" -#include "dvb-usb.h" +#include "dvb_usb.h" + +#ifdef CONFIG_DVB_USB_DEBUG +#define dprintk(var, level, args...) \ + do { if ((var & level)) printk(args); } while (0) +#define DVB_USB_DEBUG_STATUS +#else +#define dprintk(args...) +#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" +#endif + +#undef err +#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef info +#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) #define deb_info(args...) dprintk(dvb_usb_ce6230_debug, 0x01, args) #define deb_rc(args...) dprintk(dvb_usb_ce6230_debug, 0x02, args) From ec04745790f47f23f558f07398fe69e963744f11 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 13 Jun 2012 23:33:16 -0300 Subject: [PATCH 0268/5375] [media] ce6230: various small changes Small changes like log writings. No functionality changes. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/ce6230.c | 70 +++++++++++++++--------------- drivers/media/dvb/dvb-usb/ce6230.h | 50 ++++++--------------- 2 files changed, 49 insertions(+), 71 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c index ee6a4019dd8e..b9197a58ba26 100644 --- a/drivers/media/dvb/dvb-usb/ce6230.c +++ b/drivers/media/dvb/dvb-usb/ce6230.c @@ -1,5 +1,5 @@ /* - * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver + * Intel CE6230 DVB USB driver * * Copyright (C) 2009 Antti Palosaari * @@ -20,18 +20,10 @@ */ #include "ce6230.h" -#include "zl10353.h" -#include "mxl5005s.h" -/* debug */ -static int dvb_usb_ce6230_debug; -module_param_named(debug, dvb_usb_ce6230_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static struct zl10353_config ce6230_zl10353_config; - -static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) +static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) { int ret; unsigned int pipe; @@ -57,8 +49,8 @@ static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); break; default: - err("unknown command:%02x", req->cmd); - ret = -EPERM; + pr_debug("%s: unknown command=%02x\n", __func__, req->cmd); + ret = -EINVAL; goto error; } @@ -80,13 +72,14 @@ static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) msleep(1); /* avoid I2C errors */ ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index, - buf, req->data_len, CE6230_USB_TIMEOUT); + buf, req->data_len, CE6230_USB_TIMEOUT); ce6230_debug_dump(request, requesttype, value, index, buf, - req->data_len, deb_xfer); + req->data_len); if (ret < 0) - deb_info("%s: usb_control_msg failed:%d\n", __func__, ret); + pr_err("%s: usb_control_msg() failed=%d\n", KBUILD_MODNAME, + ret); else ret = 0; @@ -100,17 +93,19 @@ error: } /* I2C */ -static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) +static struct zl10353_config ce6230_zl10353_config; + +static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i = 0; - struct req_t req; - int ret = 0; - memset(&req, 0, sizeof(req)); + int ret = 0, i = 0; + struct usb_req req; if (num > 2) - return -EINVAL; + return -EOPNOTSUPP; + + memset(&req, 0, sizeof(req)); if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; @@ -126,8 +121,9 @@ static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], req.data = &msg[i+1].buf[0]; ret = ce6230_ctrl_msg(d, &req); } else { - err("i2c read not implemented"); - ret = -EPERM; + pr_err("%s: I2C read not implemented\n", + KBUILD_MODNAME); + ret = -EOPNOTSUPP; } i += 2; } else { @@ -157,14 +153,14 @@ static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], return ret ? ret : i; } -static u32 ce6230_i2c_func(struct i2c_adapter *adapter) +static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; } -static struct i2c_algorithm ce6230_i2c_algo = { - .master_xfer = ce6230_i2c_xfer, - .functionality = ce6230_i2c_func, +static struct i2c_algorithm ce6230_i2c_algorithm = { + .master_xfer = ce6230_i2c_master_xfer, + .functionality = ce6230_i2c_functionality, }; /* Callbacks for DVB USB */ @@ -180,11 +176,13 @@ static struct zl10353_config ce6230_zl10353_config = { static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) { - deb_info("%s:\n", __func__); + pr_debug("%s:\n", __func__); + adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, &adap->dev->i2c_adap); if (adap->fe[0] == NULL) return -ENODEV; + return 0; } @@ -208,7 +206,9 @@ static struct mxl5005s_config ce6230_mxl5003s_config = { static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { int ret; - deb_info("%s:\n", __func__); + + pr_debug("%s:\n", __func__); + ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; return ret; @@ -217,13 +217,15 @@ static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; - deb_info("%s: onoff:%d\n", __func__, onoff); + + pr_debug("%s: onoff=%d\n", __func__, onoff); /* InterfaceNumber 1 / AlternateSetting 0 idle InterfaceNumber 1 / AlternateSetting 1 streaming */ ret = usb_set_interface(d->udev, 1, onoff); if (ret) - err("usb_set_interface failed with error:%d", ret); + pr_err("%s: usb_set_interface() failed=%d\n", KBUILD_MODNAME, + ret); return ret; } @@ -235,7 +237,7 @@ static struct dvb_usb_device_properties ce6230_props = { .adapter_nr = adapter_nr, .bInterfaceNumber = 1, - .i2c_algo = &ce6230_i2c_algo, + .i2c_algo = &ce6230_i2c_algorithm, .power_ctrl = ce6230_power_ctrl, .frontend_attach = ce6230_zl10353_frontend_attach, .tuner_attach = ce6230_mxl5003s_tuner_attach, @@ -280,5 +282,5 @@ static struct usb_driver ce6230_usb_driver = { module_usb_driver(ce6230_usb_driver); MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0"); +MODULE_DESCRIPTION("Intel CE6230 driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/ce6230.h b/drivers/media/dvb/dvb-usb/ce6230.h index 7c219539fbd8..42d754494a3a 100644 --- a/drivers/media/dvb/dvb-usb/ce6230.h +++ b/drivers/media/dvb/dvb-usb/ce6230.h @@ -1,5 +1,5 @@ /* - * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver + * Intel CE6230 DVB USB driver * * Copyright (C) 2009 Antti Palosaari * @@ -19,51 +19,27 @@ * */ -#ifndef _DVB_USB_CE6230_H_ -#define _DVB_USB_CE6230_H_ +#ifndef CE6230_H +#define CE6230_H -#define DVB_USB_LOG_PREFIX "ce6230" #include "dvb_usb.h" +#include "zl10353.h" +#include "mxl5005s.h" -#ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var, level, args...) \ - do { if ((var & level)) printk(args); } while (0) -#define DVB_USB_DEBUG_STATUS -#else -#define dprintk(args...) -#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" -#endif - -#undef err -#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef info -#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) -#undef warn -#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) - -#define deb_info(args...) dprintk(dvb_usb_ce6230_debug, 0x01, args) -#define deb_rc(args...) dprintk(dvb_usb_ce6230_debug, 0x02, args) -#define deb_xfer(args...) dprintk(dvb_usb_ce6230_debug, 0x04, args) -#define deb_reg(args...) dprintk(dvb_usb_ce6230_debug, 0x08, args) -#define deb_i2c(args...) dprintk(dvb_usb_ce6230_debug, 0x10, args) -#define deb_fw(args...) dprintk(dvb_usb_ce6230_debug, 0x20, args) - -#define ce6230_debug_dump(r, t, v, i, b, l, func) { \ - int loop_; \ - func("%02x %02x %02x %02x %02x %02x %02x %02x", \ - t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \ +#define ce6230_debug_dump(r, t, v, i, b, l) { \ + char *direction; \ if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ - func(" >>> "); \ + direction = ">>>"; \ else \ - func(" <<< "); \ - for (loop_ = 0; loop_ < l; loop_++) \ - func("%02x ", b[loop_]); \ - func("\n");\ + direction = "<<<"; \ + pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s [%d bytes]\n", \ + __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \ + l & 0xff, l >> 8, direction, l); \ } #define CE6230_USB_TIMEOUT 1000 -struct req_t { +struct usb_req { u8 cmd; /* [1] */ u16 value; /* [2|3] */ u16 index; /* [4|5] */ From 2cc53dc82868c8d425825dbfe6d6fbf6a972486d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 14 Jun 2012 02:44:47 -0300 Subject: [PATCH 0269/5375] [media] dvb_usb_v2: attach tuners later It is more than nice to have all those frontend pointers when attaching tuner to the frontend in question. Make that possible attaching tuners after dvb_register_frontend() Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index f302e63a0d8f..6149236e4ef8 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -359,15 +359,6 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) goto err; } - if (adap->dev->props->tuner_attach) { - ret = adap->dev->props->tuner_attach(adap); - if (ret < 0) { - pr_debug("%s: tuner_attach() failed=%d\n", __func__, - ret); - goto err_dvb_frontend_detach; - } - } - for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) { adap->fe[i]->id = i; @@ -387,6 +378,15 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) count_registered++; } + if (adap->dev->props->tuner_attach) { + ret = adap->dev->props->tuner_attach(adap); + if (ret < 0) { + pr_debug("%s: tuner_attach() failed=%d\n", __func__, + ret); + goto err_dvb_unregister_frontend; + } + } + adap->num_frontends_initialized = count_registered; return 0; From a4e7c51edd2e3fea22447ebd8d26c014a68b6a23 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 14 Jun 2012 04:56:09 -0300 Subject: [PATCH 0270/5375] [media] anysee: convert to new DVB USB Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 +- drivers/media/dvb/dvb-usb/anysee.c | 495 +++++++++++++---------------- drivers/media/dvb/dvb-usb/anysee.h | 26 +- 3 files changed, 245 insertions(+), 278 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 52b3108601a6..f172e1471877 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -320,7 +320,7 @@ config DVB_USB_CINERGY_T2 config DVB_USB_ANYSEE tristate "Anysee DVB-T/C USB2.0 support" - depends on DVB_USB + depends on DVB_USB_V2 select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 03c28655af1b..2a0798cfb365 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -32,6 +32,7 @@ */ #include "anysee.h" +#include "dvb-pll.h" #include "tda1002x.h" #include "mt352.h" #include "mt352_priv.h" @@ -47,9 +48,6 @@ static int dvb_usb_anysee_debug; module_param_named(debug, dvb_usb_anysee_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); -static int dvb_usb_anysee_delsys; -module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644); -MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static DEFINE_MUTEX(anysee_usb_mutex); @@ -64,15 +62,14 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, memcpy(&buf[0], sbuf, slen); buf[60] = state->seq++; - if (mutex_lock_interruptible(&anysee_usb_mutex) < 0) - return -EAGAIN; + mutex_lock(&anysee_usb_mutex); deb_xfer(">>> "); debug_dump(buf, slen, deb_xfer); /* We need receive one message more after dvb_usb_generic_rw due to weird transaction flow, which is 1 x send + 2 x receive. */ - ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); + ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); if (ret) goto error_unlock; @@ -91,7 +88,7 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, for (i = 0; i < 3; i++) { /* receive 2nd answer */ ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, - d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf), + d->props->generic_bulk_ctrl_endpoint), buf, sizeof(buf), &act_len, 2000); if (ret) { @@ -509,6 +506,32 @@ static struct cxd2820r_config anysee_cxd2820r_config = { * IOE[5] STV0903 1=enabled */ +static int anysee_read_config(struct dvb_usb_device *d) +{ + struct anysee_state *state = d->priv; + int ret; + u8 hw_info[3]; + + /* + * Check which hardware we have. + * We must do this call two times to get reliable values (hw/fw bug). + */ + ret = anysee_get_hw_info(d, hw_info); + if (ret) + goto error; + + ret = anysee_get_hw_info(d, hw_info); + if (ret) + goto error; + + /* Meaning of these info bytes are guessed. */ + info("firmware version:%d.%d hardware id:%d", + hw_info[1], hw_info[2], hw_info[0]); + + state->hw = hw_info[0]; +error: + return ret; +} /* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */ static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) @@ -536,7 +559,7 @@ static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) /* E30 Combo Plus */ /* E30 C Plus */ - if ((fe->id ^ dvb_usb_anysee_delsys) == 0) { + if (fe->id == 0) { /* disable DVB-T demod on IOD[0] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), 0x01); @@ -580,7 +603,7 @@ static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) /* E7 TC */ /* E7 PTC */ - if ((fe->id ^ dvb_usb_anysee_delsys) == 0) { + if (fe->id == 0) { /* disable DVB-T demod on IOD[6] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), 0x40); @@ -631,7 +654,6 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) { int ret; struct anysee_state *state = adap->dev->priv; - u8 hw_info[3]; u8 tmp; struct i2c_msg msg[2] = { { @@ -647,55 +669,24 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) } }; - /* detect hardware only once */ - if (adap->fe_adap[0].fe == NULL) { - /* Check which hardware we have. - * We must do this call two times to get reliable values - * (hw/fw bug). - */ - ret = anysee_get_hw_info(adap->dev, hw_info); - if (ret) - goto error; - - ret = anysee_get_hw_info(adap->dev, hw_info); - if (ret) - goto error; - - /* Meaning of these info bytes are guessed. */ - info("firmware version:%d.%d hardware id:%d", - hw_info[1], hw_info[2], hw_info[0]); - - state->hw = hw_info[0]; - } - - /* set current frondend ID for devices having two frondends */ - if (adap->fe_adap[0].fe) - state->fe_id++; - switch (state->hw) { case ANYSEE_HW_507T: /* 2 */ /* E30 */ - if (state->fe_id) - break; - /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(mt352_attach, + adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config, &adap->dev->i2c_adap); - if (adap->fe_adap[0].fe) + if (adap->fe[0]) break; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(zl10353_attach, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, &adap->dev->i2c_adap); break; case ANYSEE_HW_507CD: /* 6 */ /* E30 Plus */ - if (state->fe_id) - break; - /* enable DVB-T demod on IOD[0] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); if (ret) @@ -707,39 +698,33 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(zl10353_attach, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, &adap->dev->i2c_adap); break; case ANYSEE_HW_507DC: /* 10 */ /* E30 C Plus */ - if (state->fe_id) - break; - /* enable DVB-C demod on IOD[0] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); if (ret) goto error; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(tda10023_attach, + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48); break; case ANYSEE_HW_507SI: /* 11 */ /* E30 S2 Plus */ - if (state->fe_id) - break; - /* enable DVB-S/S2 demod on IOD[0] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); if (ret) goto error; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(cx24116_attach, + adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config, &adap->dev->i2c_adap); break; @@ -765,67 +750,64 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) if (ret) goto error; - if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) { - /* disable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), - 0x01); - if (ret) - goto error; + /* disable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), 0x01); + if (ret) + goto error; - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), - 0x20); - if (ret) - goto error; + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), 0x20); + if (ret) + goto error; - /* attach demod */ - if (tmp == 0xc7) { - /* TDA18212 config */ - adap->fe_adap[state->fe_id].fe = dvb_attach( - tda10023_attach, + /* attach demod */ + if (tmp == 0xc7) { + /* TDA18212 config */ + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_tda18212_config, &adap->dev->i2c_adap, 0x48); - } else { - /* PLL config */ - adap->fe_adap[state->fe_id].fe = dvb_attach( - tda10023_attach, + + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe[0]) + adap->fe[0]->ops.i2c_gate_ctrl = + anysee_i2c_gate_ctrl; + } else { + /* PLL config */ + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48); - } - } else { - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), - 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), - 0x01); - if (ret) - goto error; - - /* attach demod */ - if (tmp == 0xc7) { - /* TDA18212 config */ - adap->fe_adap[state->fe_id].fe = dvb_attach( - zl10353_attach, - &anysee_zl10353_tda18212_config2, - &adap->dev->i2c_adap); - } else { - /* PLL config */ - adap->fe_adap[state->fe_id].fe = dvb_attach( - zl10353_attach, - &anysee_zl10353_config, - &adap->dev->i2c_adap); - } } - /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + /* break out if first frontend attaching fails */ + if (!adap->fe[0]) + break; + + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); + if (ret) + goto error; + + /* attach demod */ if (tmp == 0xc7) { - if (adap->fe_adap[state->fe_id].fe) - adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl = - anysee_i2c_gate_ctrl; + /* TDA18212 config */ + adap->fe[1] = dvb_attach(zl10353_attach, + &anysee_zl10353_tda18212_config2, + &adap->dev->i2c_adap); + + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe[1]) + adap->fe[1]->ops.i2c_gate_ctrl = + anysee_i2c_gate_ctrl; + } else { + /* PLL config */ + adap->fe[1] = dvb_attach(zl10353_attach, + &anysee_zl10353_config, + &adap->dev->i2c_adap); } break; @@ -834,48 +816,47 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* E7 TC */ /* E7 PTC */ - if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) { - /* disable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), - 0x40); - if (ret) - goto error; + /* disable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), 0x40); + if (ret) + goto error; - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), - 0x20); - if (ret) - goto error; + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), 0x20); + if (ret) + goto error; - /* attach demod */ - adap->fe_adap[state->fe_id].fe = - dvb_attach(tda10023_attach, + /* attach demod */ + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_tda18212_config, &adap->dev->i2c_adap, 0x48); - } else { - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), - 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6), - 0x40); - if (ret) - goto error; - - /* attach demod */ - adap->fe_adap[state->fe_id].fe = - dvb_attach(zl10353_attach, - &anysee_zl10353_tda18212_config, - &adap->dev->i2c_adap); - } /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ - if (adap->fe_adap[state->fe_id].fe) - adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl = - anysee_i2c_gate_ctrl; + if (adap->fe[0]) + adap->fe[0]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl; + + /* break out if first frontend attaching fails */ + if (!adap->fe[0]) + break; + + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6), 0x40); + if (ret) + goto error; + + /* attach demod */ + adap->fe[1] = dvb_attach(zl10353_attach, + &anysee_zl10353_tda18212_config, + &adap->dev->i2c_adap); + + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe[1]) + adap->fe[1]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl; state->has_ci = true; @@ -885,16 +866,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* E7 S2 */ /* E7 PS2 */ - if (state->fe_id) - break; - /* enable DVB-S/S2 demod on IOE[5] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); if (ret) goto error; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(stv0900_attach, + adap->fe[0] = dvb_attach(stv0900_attach, &anysee_stv0900_config, &adap->dev->i2c_adap, 0); state->has_ci = true; @@ -903,16 +881,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) case ANYSEE_HW_508T2C: /* 20 */ /* E7 T2C */ - if (state->fe_id) - break; - /* enable DVB-T/T2/C demod on IOE[5] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); if (ret) goto error; /* attach demod */ - adap->fe_adap[state->fe_id].fe = dvb_attach(cxd2820r_attach, + adap->fe[0] = dvb_attach(cxd2820r_attach, &anysee_cxd2820r_config, &adap->dev->i2c_adap); state->has_ci = true; @@ -920,7 +895,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) break; } - if (!adap->fe_adap[0].fe) { + if (!adap->fe[0]) { /* we have no frontend :-( */ ret = -ENODEV; err("Unsupported Anysee version. " \ @@ -935,14 +910,14 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) struct anysee_state *state = adap->dev->priv; struct dvb_frontend *fe; int ret; - deb_info("%s: fe=%d\n", __func__, state->fe_id); + deb_info("%s: adap=%d\n", __func__, adap->id); switch (state->hw) { case ANYSEE_HW_507T: /* 2 */ /* E30 */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), NULL, DVB_PLL_THOMSON_DTT7579); break; @@ -950,7 +925,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579); @@ -959,7 +934,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 C Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); @@ -968,7 +943,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 S2 Plus */ /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe, + fe = dvb_attach(isl6423_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_isl6423_config); break; @@ -980,15 +955,30 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) * fails attach old simple PLL. */ /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, - &adap->dev->i2c_adap, &anysee_tda18212_config); - if (fe) + fe = dvb_attach(tda18212_attach, adap->fe[0], + &adap->dev->i2c_adap, &anysee_tda18212_config); + + if (fe && adap->fe[1]) { + /* attach tuner for 2nd FE */ + fe = dvb_attach(tda18212_attach, adap->fe[1], + &adap->dev->i2c_adap, + &anysee_tda18212_config); break; + } else if (fe) { + break; + } /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe, - (0xc0 >> 1), &adap->dev->i2c_adap, - DVB_PLL_SAMSUNG_DTOS403IH102A); + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), + &adap->dev->i2c_adap, + DVB_PLL_SAMSUNG_DTOS403IH102A); + + if (fe && adap->fe[1]) { + /* attach tuner for 2nd FE */ + fe = dvb_attach(dvb_pll_attach, adap->fe[0], + (0xc0 >> 1), &adap->dev->i2c_adap, + DVB_PLL_SAMSUNG_DTOS403IH102A); + } break; case ANYSEE_HW_508TC: /* 18 */ @@ -997,9 +987,15 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E7 PTC */ /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, + fe = dvb_attach(tda18212_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_tda18212_config); + if (fe) { + /* attach tuner for 2nd FE */ + fe = dvb_attach(tda18212_attach, adap->fe[1], + &adap->dev->i2c_adap, &anysee_tda18212_config); + } + break; case ANYSEE_HW_508S2: /* 19 */ case ANYSEE_HW_508PS2: /* 22 */ @@ -1007,12 +1003,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E7 PS2 */ /* attach tuner */ - fe = dvb_attach(stv6110_attach, adap->fe_adap[0].fe, + fe = dvb_attach(stv6110_attach, adap->fe[0], &anysee_stv6110_config, &adap->dev->i2c_adap); if (fe) { /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe, + fe = dvb_attach(isl6423_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_isl6423_config); } @@ -1022,7 +1018,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E7 T2C */ /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, + fe = dvb_attach(tda18212_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_tda18212_config2); break; @@ -1064,6 +1060,15 @@ static int anysee_rc_query(struct dvb_usb_device *d) return 0; } +static int anysee_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + rc->allowed_protos = RC_TYPE_NEC; + rc->query = anysee_rc_query; + rc->interval = 250; /* windows driver uses 500ms */ + + return 0; +} + static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot, int addr) { @@ -1245,6 +1250,14 @@ static int anysee_init(struct dvb_usb_device *d) struct anysee_state *state = d->priv; int ret; + /* There is one interface with two alternate settings. + Alternate setting 0 is for bulk transfer. + Alternate setting 1 is for isochronous transfer. + We use bulk transfer (alternate setting 0). */ + ret = usb_set_interface(d->udev, 0, 0); + if (ret) + return ret; + /* LED light */ ret = anysee_led_ctrl(d, 0x01, 0x03); if (ret) @@ -1267,80 +1280,34 @@ static int anysee_init(struct dvb_usb_device *d) return 0; } +static void anysee_disconnect(struct dvb_usb_device *d) +{ + return anysee_ci_release(d); +} + /* DVB USB Driver stuff */ -static struct dvb_usb_device_properties anysee_properties; +static struct dvb_usb_device_properties anysee_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct anysee_state), -static int anysee_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct dvb_usb_device *d; - struct usb_host_interface *alt; - int ret; + .generic_bulk_ctrl_endpoint = 0x01, + .generic_bulk_ctrl_endpoint_response = 0x81, - /* There is one interface with two alternate settings. - Alternate setting 0 is for bulk transfer. - Alternate setting 1 is for isochronous transfer. - We use bulk transfer (alternate setting 0). */ - if (intf->num_altsetting < 1) - return -ENODEV; - - /* - * Anysee is always warm (its USB-bridge, Cypress FX2, uploads - * firmware from eeprom). If dvb_usb_device_init() succeeds that - * means d is a valid pointer. - */ - ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d, - adapter_nr); - if (ret) - return ret; - - alt = usb_altnum_to_altsetting(intf, 0); - if (alt == NULL) { - deb_info("%s: no alt found!\n", __func__); - return -ENODEV; - } - - ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - if (ret) - return ret; - - return anysee_init(d); -} - -static void anysee_disconnect(struct usb_interface *intf) -{ - struct dvb_usb_device *d = usb_get_intfdata(intf); - - anysee_ci_release(d); - dvb_usb_device_exit(intf); - - return; -} - -static struct usb_device_id anysee_table[] = { - { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) }, - { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, anysee_table); - -static struct dvb_usb_device_properties anysee_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - - .size_of_priv = sizeof(struct anysee_state), + .i2c_algo = &anysee_i2c_algo, + .read_config = anysee_read_config, + .frontend_attach = anysee_frontend_attach, + .tuner_attach = anysee_tuner_attach, + .init = anysee_init, + .get_rc_config = anysee_get_rc_config, + .frontend_ctrl = anysee_frontend_ctrl, + .streaming_ctrl = anysee_streaming_ctrl, + .disconnect = anysee_disconnect, .num_adapters = 1, .adapter = { { - .num_frontends = 2, - .frontend_ctrl = anysee_frontend_ctrl, - .fe = { { - .streaming_ctrl = anysee_streaming_ctrl, - .frontend_attach = anysee_frontend_attach, - .tuner_attach = anysee_tuner_attach, .stream = { .type = USB_BULK, .count = 8, @@ -1350,56 +1317,32 @@ static struct dvb_usb_device_properties anysee_properties = { .buffersize = (16*512), } } - }, - }, { - .streaming_ctrl = anysee_streaming_ctrl, - .frontend_attach = anysee_frontend_attach, - .tuner_attach = anysee_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = (16*512), - } - } - }, - } }, + } } - }, - - .rc.core = { - .rc_codes = RC_MAP_ANYSEE, - .protocol = RC_TYPE_OTHER, - .module_name = "anysee", - .rc_query = anysee_rc_query, - .rc_interval = 250, /* windows driver uses 500ms */ - }, - - .i2c_algo = &anysee_i2c_algo, - - .generic_bulk_ctrl_endpoint = 1, - - .num_device_descs = 1, - .devices = { - { - .name = "Anysee DVB USB2.0", - .cold_ids = {NULL}, - .warm_ids = {&anysee_table[0], - &anysee_table[1], NULL}, - }, } }; -static struct usb_driver anysee_driver = { - .name = "dvb_usb_anysee", - .probe = anysee_probe, - .disconnect = anysee_disconnect, - .id_table = anysee_table, +static const struct usb_device_id anysee_id_table[] = { + { DVB_USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE, + &anysee_props, "Anysee", RC_MAP_ANYSEE) }, + { DVB_USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE, + &anysee_props, "Anysee", RC_MAP_ANYSEE) }, + { } +}; +MODULE_DEVICE_TABLE(usb, anysee_id_table); + +static struct usb_driver anysee_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = anysee_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, }; -module_usb_driver(anysee_driver); +module_usb_driver(anysee_usb_driver); MODULE_AUTHOR("Antti Palosaari "); MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0"); diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h index 8ac879431540..dc40dcf7c328 100644 --- a/drivers/media/dvb/dvb-usb/anysee.h +++ b/drivers/media/dvb/dvb-usb/anysee.h @@ -35,9 +35,26 @@ #define _DVB_USB_ANYSEE_H_ #define DVB_USB_LOG_PREFIX "anysee" -#include "dvb-usb.h" +#include "dvb_usb.h" #include "dvb_ca_en50221.h" +#ifdef CONFIG_DVB_USB_DEBUG +#define dprintk(var, level, args...) \ + do { if ((var & level)) printk(args); } while (0) +#define DVB_USB_DEBUG_STATUS +#else +#define dprintk(args...) +#define debug_dump(b, l, func) +#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" +#endif + +#define debug_dump(b, l, func) {\ + int loop_; \ + for (loop_ = 0; loop_ < l; loop_++) \ + func("%02x ", b[loop_]); \ + func("\n");\ +} + #define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) #define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) #define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args) @@ -45,6 +62,13 @@ #define deb_i2c(args...) dprintk(dvb_usb_anysee_debug, 0x10, args) #define deb_fw(args...) dprintk(dvb_usb_anysee_debug, 0x20, args) +#undef err +#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef info +#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) +#undef warn +#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg) + enum cmd { CMD_I2C_READ = 0x33, CMD_I2C_WRITE = 0x31, From c65bcb95beec39402cb574faa2e17aa1e56c1534 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 13 Jun 2012 18:24:32 -0300 Subject: [PATCH 0271/5375] [media] dvb_usb_v2: return the download ret in dvb_usb_download_firmware The first being this patch, no return value from dvb_usb_download_firmware causes system wide dead lock with COLD disconnect as system attempts to continue to warm state. Signed-off-by: Malcolm Priestley Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index ecc6bd253497..0ac1a72a7d81 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -62,7 +62,7 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d) if (ret < 0) goto err; - return 0; + return ret; err: pr_debug("%s: failed=%d\n", __func__, ret); return ret; From ffe4ac92ee5a4a0a236b9583c3173902e158e14b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 14 Jun 2012 20:07:02 -0300 Subject: [PATCH 0272/5375] [media] dvb_usb_v2: do not release USB interface when device reconnects USB core will call disconnect and remove driver for us as device will disconnect itself. After that it is loaded again as a new device but it is warm and no firmware loading needed. Reported-by: Malcolm Priestley Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 0ac1a72a7d81..e9bb006bb725 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -431,11 +431,24 @@ static void dvb_usbv2_init_work(struct work_struct *work) KBUILD_MODNAME, d->name); ret = dvb_usbv2_download_firmware(d); if (ret == 0) { + /* device is warm, continue initialization */ ; } else if (ret == RECONNECTS_USB) { - ret = 0; - goto exit_usb_driver_release_interface; + /* + * USB core will call disconnect() and then probe() + * as device reconnects itself from the USB bus. + * disconnect() will release all driver resources + * and probe() is called for 'new' device. As 'new' + * device is warm we should never go here again. + */ + return; } else { + /* Unexpected fatal error. We must unregister driver + * manually from the device, because device is already + * register by returning from probe() with success. + * usb_driver_release_interface() finally calls + * disconnect() in order to free resources. + */ goto err_usb_driver_release_interface; } } @@ -453,8 +466,7 @@ static void dvb_usbv2_init_work(struct work_struct *work) err_usb_driver_release_interface: pr_info("%s: '%s' error while loading driver (%d)\n", KBUILD_MODNAME, d->name, ret); -exit_usb_driver_release_interface: - /* it finally calls .disconnect() which frees mem */ + /* it finally calls disconnect() which frees mem */ usb_driver_release_interface(to_usb_driver(d->intf->dev.driver), d->intf); pr_debug("%s: failed=%d\n", __func__, ret); From 6e3a5daa6ee7a0eae3b2161ed4783fee547654c2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 15 Jun 2012 00:29:36 -0300 Subject: [PATCH 0273/5375] [media] dvb_usb_v2: try to remove all adapters on exit It did not removed adapter on error case as .num_adapters_initialized was set after success adapter initialization. It should be safe to try remove all possible adapters in any-case. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index e9bb006bb725..cea334331508 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -294,7 +294,9 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) { int i; - for (i = d->num_adapters_initialized - 1; i >= 0; i--) { + pr_debug("%s:\n", __func__); + + for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); dvb_usbv2_adapter_stream_exit(&d->adapter[i]); From ad2618393168a72f079265023ddc68f2a89ccc9f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 15 Jun 2012 00:52:42 -0300 Subject: [PATCH 0274/5375] [media] dvb_usb_v2: simplify remote init/exit logic Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 1 - drivers/media/dvb/dvb-usb/dvb_usb_init.c | 11 ++++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index a972de6f8486..62097f38bb16 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -328,7 +328,6 @@ struct dvb_usb_device { #define DVB_USB_STATE_INIT 0x000 #define DVB_USB_STATE_I2C 0x001 #define DVB_USB_STATE_DVB 0x002 -#define DVB_USB_STATE_REMOTE 0x004 int state; int powered; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index cea334331508..5da4233501f0 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -137,6 +137,8 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) int ret; struct rc_dev *dev; + pr_debug("%s:\n", __func__); + if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) return 0; @@ -190,8 +192,6 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) msecs_to_jiffies(d->rc.interval)); } - d->state |= DVB_USB_STATE_REMOTE; - return 0; err: pr_debug("%s: failed=%d\n", __func__, ret); @@ -200,13 +200,14 @@ err: static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) { - if (d->state & DVB_USB_STATE_REMOTE) { + pr_debug("%s:\n", __func__); + + if (d->rc_dev) { cancel_delayed_work_sync(&d->rc_query_work); rc_unregister_device(d->rc_dev); + d->rc_dev = NULL; } - d->state &= ~DVB_USB_STATE_REMOTE; - return 0; } From d70521a396cecb11dc8bd4212d2502dc797d3d67 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 15 Jun 2012 01:38:28 -0300 Subject: [PATCH 0275/5375] [media] dvb_usb_v2: get rid of dvb_usb_device state Remove state from struct dvb_usb_device as we can live without. Add some debug logs. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 6 ----- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 32 +++++++++--------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 62097f38bb16..8ec8deefaf6a 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -324,12 +324,6 @@ struct dvb_usb_device { struct work_struct probe_work; pid_t work_pid; struct usb_interface *intf; - -#define DVB_USB_STATE_INIT 0x000 -#define DVB_USB_STATE_I2C 0x001 -#define DVB_USB_STATE_DVB 0x002 - int state; - int powered; /* locking */ diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 5da4233501f0..1297b95aff48 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -72,26 +72,24 @@ static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) { int ret; - if (!d->props->i2c_algo) { - ret = 0; - goto err; - } + pr_debug("%s:\n", __func__); + + if (!d->props->i2c_algo) + return 0; strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name)); d->i2c_adap.algo = d->props->i2c_algo; - d->i2c_adap.algo_data = NULL; d->i2c_adap.dev.parent = &d->udev->dev; - i2c_set_adapdata(&d->i2c_adap, d); ret = i2c_add_adapter(&d->i2c_adap); if (ret < 0) { - pr_err("%s: i2c_add_adapter() failed\n", KBUILD_MODNAME); + d->i2c_adap.algo = NULL; + pr_err("%s: i2c_add_adapter() failed=%d\n", KBUILD_MODNAME, + ret); goto err; } - d->state |= DVB_USB_STATE_I2C; - return 0; err: pr_debug("%s: failed=%d\n", __func__, ret); @@ -100,10 +98,10 @@ err: static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) { - if (d->state & DVB_USB_STATE_I2C) - i2c_del_adapter(&d->i2c_adap); + pr_debug("%s:\n", __func__); - d->state &= ~DVB_USB_STATE_I2C; + if (d->i2c_adap.algo) + i2c_del_adapter(&d->i2c_adap); return 0; } @@ -282,7 +280,6 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) adap->dvb_adap.mfe_shared = 1; d->num_adapters_initialized++; - d->state |= DVB_USB_STATE_DVB; } return 0; @@ -304,7 +301,6 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) } d->num_adapters_initialized = 0; - d->state &= ~DVB_USB_STATE_DVB; return 0; } @@ -312,12 +308,11 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) /* general initialization functions */ static int dvb_usbv2_exit(struct dvb_usb_device *d) { - pr_debug("%s: state before exiting everything: %x\n", __func__, d->state); + pr_debug("%s:\n", __func__); + dvb_usbv2_remote_exit(d); dvb_usbv2_adapter_exit(d); dvb_usbv2_i2c_exit(d); - pr_debug("%s: state should be zero now: %x\n", __func__, d->state); - d->state = DVB_USB_STATE_INIT; kfree(d->priv); kfree(d); @@ -328,9 +323,6 @@ static int dvb_usbv2_init(struct dvb_usb_device *d) { int ret = 0; - d->state = DVB_USB_STATE_INIT; - - /* check the capabilities and set appropriate variables */ dvb_usbv2_device_power_ctrl(d, 1); if (d->props->read_config) { From 6dca4ea3ecb3d33ce49a9bb7d1f40a75bbea8aec Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 15 Jun 2012 02:10:50 -0300 Subject: [PATCH 0276/5375] [media] dvb_usb_v2: move fe_ioctl_override() callback Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 5 ++--- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 1 - drivers/media/dvb/dvb-usb/dvb_usb_init.c | 2 ++ 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 8ec8deefaf6a..98504b59b102 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -100,9 +100,6 @@ struct dvb_usb_adapter_properties { int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); - int (*fe_ioctl_override) (struct dvb_frontend *, - unsigned int, void *, unsigned int); - struct usb_data_stream_properties stream; }; @@ -189,6 +186,8 @@ struct dvb_usb_device_properties { int (*tuner_attach) (struct dvb_usb_adapter *); int (*frontend_ctrl) (struct dvb_frontend *, int); int (*streaming_ctrl) (struct dvb_usb_adapter *, int); + int (*fe_ioctl_override) (struct dvb_frontend *, + unsigned int, void *, unsigned int); #define WARM 0 #define COLD 1 diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 6149236e4ef8..d436a1582022 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -204,7 +204,6 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) goto err; } adap->dvb_adap.priv = adap; - adap->dvb_adap.fe_ioctl_override = adap->props->fe_ioctl_override; if (adap->dev->props->read_mac_address) { if (adap->dev->props->read_mac_address(adap->dev, diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 1297b95aff48..e393fb557398 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -279,6 +279,8 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) if (adap->fe[1]) adap->dvb_adap.mfe_shared = 1; + adap->dvb_adap.fe_ioctl_override = d->props->fe_ioctl_override; + d->num_adapters_initialized++; } From dd5e52cdf9e2518e79b634fa2ae1cc86e37cff14 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 15 Jun 2012 20:46:44 -0300 Subject: [PATCH 0277/5375] [media] dvb_usb_v2: remove num_frontends_initialized from dvb_usb_adapter We can live easily without that variable. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 1 - drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 98504b59b102..6392fd3d4164 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -288,7 +288,6 @@ struct dvb_usb_adapter { int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); int active_fe; - int num_frontends_initialized; }; /** diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index d436a1582022..bc94874039e8 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -386,8 +386,6 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) } } - adap->num_frontends_initialized = count_registered; - return 0; err_dvb_unregister_frontend: @@ -410,14 +408,12 @@ int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) int i; pr_debug("%s: adap=%d\n", __func__, adap->id); - for (i = adap->num_frontends_initialized - 1; i >= 0; i--) { + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { if (adap->fe[i]) { dvb_unregister_frontend(adap->fe[i]); dvb_frontend_detach(adap->fe[i]); } } - adap->num_frontends_initialized = 0; - return 0; } From ddee56943ab6df098e411fe943c2a52063fba0a5 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 15 Jun 2012 21:17:04 -0300 Subject: [PATCH 0278/5375] [media] dvb_usb_v2: .read_mac_address() callback changes Give DVB adapter as a parameter for callback. MAC address is adapter property and it could be (at least in theory) there is devices having multiple adapters and all has own MAC. Also add error handling. If callback fails error is returned which leads device unregister. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 6392fd3d4164..e7015ce5b3b4 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -181,7 +181,7 @@ struct dvb_usb_device_properties { int (*power_ctrl) (struct dvb_usb_device *, int); int (*read_config) (struct dvb_usb_device *d); - int (*read_mac_address) (struct dvb_usb_device *, u8 []); + int (*read_mac_address) (struct dvb_usb_adapter *, u8 []); int (*frontend_attach) (struct dvb_usb_adapter *); int (*tuner_attach) (struct dvb_usb_adapter *); int (*frontend_ctrl) (struct dvb_frontend *, int); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index bc94874039e8..3cbae02ea51e 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -203,22 +203,21 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) ret); goto err; } + adap->dvb_adap.priv = adap; if (adap->dev->props->read_mac_address) { - if (adap->dev->props->read_mac_address(adap->dev, - adap->dvb_adap.proposed_mac) == 0) - pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME, - adap->dvb_adap.proposed_mac); - else - pr_err("%s: MAC address reading failed\n", - KBUILD_MODNAME); - } + ret = adap->dev->props->read_mac_address(adap, + adap->dvb_adap.proposed_mac); + if (ret < 0) + goto err_dmx; + pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME, + adap->dvb_adap.proposed_mac); + } adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; adap->demux.priv = adap; - adap->demux.filternum = 0; if (adap->demux.filternum < adap->max_feed_count) adap->demux.filternum = adap->max_feed_count; From 12077a3aa4bfc1fb5ca779dcc6b3a1f45a475736 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 16 Jun 2012 13:56:37 -0300 Subject: [PATCH 0279/5375] [media] dvb_usb_v2: add macros to fill USB stream properties Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 34 ++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index e7015ce5b3b4..56df13fbc05e 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -22,11 +22,29 @@ #include "dmxdev.h" #include "dvb-usb-ids.h" -struct dvb_usb_driver_info { - const char *name; - const char *rc_map; - const struct dvb_usb_device_properties *props; -}; +#define DVB_USB_STREAM_BULK(endpoint_, count_, size_) { \ + .type = USB_BULK, \ + .count = count_, \ + .endpoint = endpoint_, \ + .u = { \ + .bulk = { \ + .buffersize = size_, \ + } \ + } \ +} + +#define DVB_USB_STREAM_ISOC(endpoint_, count_, frames_, size_, interval_) { \ + .type = USB_ISOC, \ + .count = count_, \ + .endpoint = endpoint_, \ + .u = { \ + .isoc = { \ + .framesperurb = frames_, \ + .framesize = size_,\ + .interval = interval_, \ + } \ + } \ +} #define DVB_USB_DEVICE(vend, prod, props_, name_, rc) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ @@ -38,6 +56,12 @@ struct dvb_usb_driver_info { .rc_map = (rc), \ }) +struct dvb_usb_driver_info { + const char *name; + const char *rc_map; + const struct dvb_usb_device_properties *props; +}; + struct dvb_usb_device; struct dvb_usb_adapter; struct usb_data_stream; From 6400a8c5afb54a1018c4d01b7f1ad28c4e0ef659 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 16 Jun 2012 16:02:57 -0300 Subject: [PATCH 0280/5375] [media] dvb_usb_v2: change USB stream config logic Initial / default USB stream configuration is now set always as a dvb_usb_device_properties. Dynamic configuration is done top of that if callback .get_usb_stream_config() exists. Default values are set when callback is called so callback needs only change values that are different than default. In addition of that define two macros DVB_USB_STREAM_BULK() and DVB_USB_STREAM_ISOC() for filling struct usb_data_stream_properties Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 21 ++++++--------------- drivers/media/dvb/dvb-usb/usb_urb.c | 2 +- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index e1cff154c0ec..c94a900c3264 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -17,7 +17,7 @@ extern int dvb_usbv2_disable_rc_polling; extern int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff); extern int usb_urb_initv2(struct usb_data_stream *stream, - struct usb_data_stream_properties *props); + const struct usb_data_stream_properties *props); extern int usb_urb_exitv2(struct usb_data_stream *stream); extern int usb_urb_submitv2(struct usb_data_stream *stream, struct usb_data_stream_properties *props); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 3cbae02ea51e..484114cbd0ba 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -34,31 +34,20 @@ static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) { - int ret; - struct usb_data_stream_properties stream_props; + pr_debug("%s: adap=%d\n", __func__, adap->id); adap->stream.udev = adap->dev->udev; adap->stream.user_priv = adap; - - /* resolve USB stream configuration for buffer alloc */ - if (adap->dev->props->get_usb_stream_config) { - ret = adap->dev->props->get_usb_stream_config(NULL, - &stream_props); - if (ret < 0) - return ret; - } else { - stream_props = adap->props->stream; - } - - /* FIXME: can be removed as set later in anyway */ adap->stream.complete = dvb_usb_data_complete; - return usb_urb_initv2(&adap->stream, &stream_props); + return usb_urb_initv2(&adap->stream, &adap->props->stream); } int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) { + pr_debug("%s: adap=%d\n", __func__, adap->id); usb_urb_exitv2(&adap->stream); + return 0; } @@ -133,6 +122,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) /* resolve USB stream configuration */ if (adap->dev->props->get_usb_stream_config) { + memcpy(&stream_props, &adap->props->stream, + sizeof(struct usb_data_stream_properties)); ret = adap->dev->props->get_usb_stream_config( adap->fe[adap->active_fe], &stream_props); diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c index 16e9fa03c847..32e80be2168d 100644 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -306,7 +306,7 @@ int usb_urb_reconfig(struct usb_data_stream *stream, } int usb_urb_initv2(struct usb_data_stream *stream, - struct usb_data_stream_properties *props) + const struct usb_data_stream_properties *props) { int ret; From 1a590010a262b0797a4a42287959107d2c41c8ca Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 16 Jun 2012 16:25:22 -0300 Subject: [PATCH 0281/5375] [media] af9015: update USB streaming configuration logic Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index a9d9f9a23450..a429c24d8b30 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -602,22 +602,8 @@ error: static int af9015_get_usb_stream_config(struct dvb_frontend *fe, struct usb_data_stream_properties *stream) { - struct dvb_usb_adapter *adap; - - deb_info("%s: fe=%p\n", __func__, fe); - - stream->type = USB_BULK; - stream->count = 8; - stream->endpoint = 0x84; - stream->u.bulk.buffersize = TS_USB20_FRAME_SIZE; - - if (fe == NULL) - return 0; - - adap = fe->dvb->priv; - - if (adap->id == 1) - stream->endpoint = 0x85; + struct dvb_usb_adapter *adap = fe->dvb->priv; + deb_info("%s: adap=%d\n", __func__, adap->id); if (adap->dev->udev->speed == USB_SPEED_FULL) stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE; @@ -1335,6 +1321,10 @@ static struct dvb_usb_device_properties af9015_props = { .pid_filter_count = 32, .pid_filter = af9015_pid_filter, .pid_filter_ctrl = af9015_pid_filter_ctrl, + + .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE), + }, { + .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE), }, }, }; From f89f9ff883cc5233933ef0b61845fc795ffa18d5 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 16 Jun 2012 17:58:53 -0300 Subject: [PATCH 0282/5375] [media] dvb_usb_v2: helper macros for device/adapter/frontend pointers Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 56df13fbc05e..fadc0f988efe 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -22,6 +22,14 @@ #include "dmxdev.h" #include "dvb-usb-ids.h" +/* helper macros for every DVB USB driver use */ +#define adap_to_d(adap) ((adap)->dev) +#define adap_to_priv(adap) (adap_to_d(adap)->priv) +#define fe_to_adap(fe) ((struct dvb_usb_adapter *) ((fe)->dvb->priv)) +#define fe_to_d(fe) (adap_to_d(fe_to_adap(fe))) +#define fe_to_priv(fe) (fe_to_d(fe)->priv) +#define d_to_priv(d) (d->priv) + #define DVB_USB_STREAM_BULK(endpoint_, count_, size_) { \ .type = USB_BULK, \ .count = count_, \ From e80896616c11f4c0a0bc17ebd87b86da194b859a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 16 Jun 2012 18:13:06 -0300 Subject: [PATCH 0283/5375] [media] af9015: use helper macros for some pointers Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 97 ++++++++++++++---------------- 1 file changed, 45 insertions(+), 52 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index a429c24d8b30..0f87eafae2d2 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -36,7 +36,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) #define BUF_LEN 63 #define REQ_HDR_LEN 8 /* send header size */ #define ACK_HDR_LEN 2 /* rece header size */ - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); int ret, wlen, rlen; u8 buf[BUF_LEN]; u8 write = 1; @@ -146,7 +146,7 @@ static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, u8 val) { - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; if (addr == state->af9013_config[0].i2c_addr || @@ -159,7 +159,7 @@ static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, u8 *val) { - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; if (addr == state->af9013_config[0].i2c_addr || @@ -205,7 +205,7 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); int ret = 0, i = 0; u16 addr; u8 uninitialized_var(mbox), addr_len; @@ -346,7 +346,7 @@ static int af9015_identify_state(struct dvb_usb_device *d) static int af9015_download_firmware(struct dvb_usb_device *d, const struct firmware *fw) { - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); int i, len, remaining, ret; struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; u16 checksum = 0; @@ -394,7 +394,7 @@ error: /* hash (and dump) eeprom */ static int af9015_eeprom_hash(struct dvb_usb_device *d) { - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); int ret; static const unsigned int eeprom_size = 256; unsigned int reg; @@ -436,7 +436,7 @@ free: static int af9015_read_config(struct dvb_usb_device *d) { - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); int ret; u8 val, i, offset = 0; struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val}; @@ -602,10 +602,9 @@ error: static int af9015_get_usb_stream_config(struct dvb_frontend *fe, struct usb_data_stream_properties *stream) { - struct dvb_usb_adapter *adap = fe->dvb->priv; - deb_info("%s: adap=%d\n", __func__, adap->id); + deb_info("%s: adap=%d\n", __func__, fe_to_adap(fe)->id); - if (adap->dev->udev->speed == USB_SPEED_FULL) + if (fe_to_d(fe)->udev->speed == USB_SPEED_FULL) stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE; return 0; @@ -613,7 +612,7 @@ static int af9015_get_usb_stream_config(struct dvb_frontend *fe, static int af9015_get_adapter_count(struct dvb_usb_device *d) { - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); return state->dual_mode + 1; } @@ -621,13 +620,12 @@ static int af9015_get_adapter_count(struct dvb_usb_device *d) static int af9015_af9013_set_frontend(struct dvb_frontend *fe) { int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *state = adap->dev->priv; + struct af9015_state *state = fe_to_priv(fe); if (mutex_lock_interruptible(&state->fe_mutex)) return -EAGAIN; - ret = state->set_frontend[adap->id](fe); + ret = state->set_frontend[fe_to_adap(fe)->id](fe); mutex_unlock(&state->fe_mutex); @@ -639,13 +637,12 @@ static int af9015_af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) { int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *state = adap->dev->priv; + struct af9015_state *state = fe_to_priv(fe); if (mutex_lock_interruptible(&state->fe_mutex)) return -EAGAIN; - ret = state->read_status[adap->id](fe, status); + ret = state->read_status[fe_to_adap(fe)->id](fe, status); mutex_unlock(&state->fe_mutex); @@ -656,13 +653,12 @@ static int af9015_af9013_read_status(struct dvb_frontend *fe, static int af9015_af9013_init(struct dvb_frontend *fe) { int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *state = adap->dev->priv; + struct af9015_state *state = fe_to_priv(fe); if (mutex_lock_interruptible(&state->fe_mutex)) return -EAGAIN; - ret = state->init[adap->id](fe); + ret = state->init[fe_to_adap(fe)->id](fe); mutex_unlock(&state->fe_mutex); @@ -673,13 +669,12 @@ static int af9015_af9013_init(struct dvb_frontend *fe) static int af9015_af9013_sleep(struct dvb_frontend *fe) { int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *state = adap->dev->priv; + struct af9015_state *state = fe_to_priv(fe); if (mutex_lock_interruptible(&state->fe_mutex)) return -EAGAIN; - ret = state->sleep[adap->id](fe); + ret = state->sleep[fe_to_adap(fe)->id](fe); mutex_unlock(&state->fe_mutex); @@ -690,13 +685,12 @@ static int af9015_af9013_sleep(struct dvb_frontend *fe) static int af9015_tuner_init(struct dvb_frontend *fe) { int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *state = adap->dev->priv; + struct af9015_state *state = fe_to_priv(fe); if (mutex_lock_interruptible(&state->fe_mutex)) return -EAGAIN; - ret = state->tuner_init[adap->id](fe); + ret = state->tuner_init[fe_to_adap(fe)->id](fe); mutex_unlock(&state->fe_mutex); @@ -707,13 +701,12 @@ static int af9015_tuner_init(struct dvb_frontend *fe) static int af9015_tuner_sleep(struct dvb_frontend *fe) { int ret; - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct af9015_state *state = adap->dev->priv; + struct af9015_state *state = fe_to_priv(fe); if (mutex_lock_interruptible(&state->fe_mutex)) return -EAGAIN; - ret = state->tuner_sleep[adap->id](fe); + ret = state->tuner_sleep[fe_to_adap(fe)->id](fe); mutex_unlock(&state->fe_mutex); @@ -722,7 +715,7 @@ static int af9015_tuner_sleep(struct dvb_frontend *fe) static int af9015_copy_firmware(struct dvb_usb_device *d) { - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); int ret; u8 fw_params[4]; u8 val, i; @@ -804,7 +797,7 @@ exit: static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) { int ret; - struct af9015_state *state = adap->dev->priv; + struct af9015_state *state = adap_to_priv(adap); if (adap->id == 0) { state->af9013_config[0].ts_mode = AF9013_TS_USB; @@ -819,7 +812,7 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) /* copy firmware to 2nd demodulator */ if (state->dual_mode) { - ret = af9015_copy_firmware(adap->dev); + ret = af9015_copy_firmware(adap_to_d(adap)); if (ret) { err("firmware copy to 2nd frontend " \ "failed, will disable it"); @@ -833,7 +826,7 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) /* attach demodulator */ adap->fe[0] = dvb_attach(af9013_attach, - &state->af9013_config[adap->id], &adap->dev->i2c_adap); + &state->af9013_config[adap->id], &adap_to_d(adap)->i2c_adap); /* * AF9015 firmware does not like if it gets interrupted by I2C adapter @@ -928,7 +921,7 @@ static struct mxl5007t_config af9015_mxl5007t_config = { static int af9015_tuner_attach(struct dvb_usb_adapter *adap) { - struct af9015_state *state = adap->dev->priv; + struct af9015_state *state = adap_to_priv(adap); int ret; deb_info("%s:\n", __func__); @@ -936,50 +929,50 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) case AF9013_TUNER_MT2060: case AF9013_TUNER_MT2060_2: ret = dvb_attach(mt2060_attach, adap->fe[0], - &adap->dev->i2c_adap, &af9015_mt2060_config, + &adap_to_d(adap)->i2c_adap, &af9015_mt2060_config, state->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: ret = dvb_attach(qt1010_attach, adap->fe[0], - &adap->dev->i2c_adap, + &adap_to_d(adap)->i2c_adap, &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0, - &adap->dev->i2c_adap, + &adap_to_d(adap)->i2c_adap, &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18218: ret = dvb_attach(tda18218_attach, adap->fe[0], - &adap->dev->i2c_adap, + &adap_to_d(adap)->i2c_adap, &af9015_tda18218_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5003D: ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap->dev->i2c_adap, + &adap_to_d(adap)->i2c_adap, &af9015_mxl5003_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: ret = dvb_attach(mxl5005s_attach, adap->fe[0], - &adap->dev->i2c_adap, + &adap_to_d(adap)->i2c_adap, &af9015_mxl5005_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_ENV77H11D5: ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0, - &adap->dev->i2c_adap, + &adap_to_d(adap)->i2c_adap, DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MC44S803: ret = dvb_attach(mc44s803_attach, adap->fe[0], - &adap->dev->i2c_adap, + &adap_to_d(adap)->i2c_adap, &af9015_mc44s803_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5007T: ret = dvb_attach(mxl5007t_attach, adap->fe[0], - &adap->dev->i2c_adap, + &adap_to_d(adap)->i2c_adap, 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_UNKNOWN: @@ -1010,9 +1003,9 @@ static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) deb_info("%s: onoff:%d\n", __func__, onoff); if (onoff) - ret = af9015_set_reg_bit(adap->dev, 0xd503, 0); + ret = af9015_set_reg_bit(adap_to_d(adap), 0xd503, 0); else - ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0); + ret = af9015_clear_reg_bit(adap_to_d(adap), 0xd503, 0); return ret; } @@ -1026,16 +1019,16 @@ static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", __func__, index, pid, onoff); - ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff)); + ret = af9015_write_reg(adap_to_d(adap), 0xd505, (pid & 0xff)); if (ret) goto error; - ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8)); + ret = af9015_write_reg(adap_to_d(adap), 0xd506, (pid >> 8)); if (ret) goto error; idx = ((index & 0x1f) | (1 << 5)); - ret = af9015_write_reg(adap->dev, 0xd504, idx); + ret = af9015_write_reg(adap_to_d(adap), 0xd504, idx); error: return ret; @@ -1043,7 +1036,7 @@ error: static int af9015_init_endpoint(struct dvb_usb_device *d) { - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); int ret; u16 frame_size; u8 packet_size; @@ -1128,7 +1121,7 @@ error: static int af9015_init(struct dvb_usb_device *d) { - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); int ret; deb_info("%s:\n", __func__); @@ -1180,7 +1173,7 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { static int af9015_rc_query(struct dvb_usb_device *d) { - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); int ret; u8 buf[17]; @@ -1249,7 +1242,7 @@ error: static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { - struct af9015_state *state = d->priv; + struct af9015_state *state = d_to_priv(d); u16 vid = le16_to_cpu(d->udev->descriptor.idVendor); if (state->ir_mode == AF9015_IR_MODE_DISABLED) From 191f79a4d78292a82f9be9cc6c9c974365792f8f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 17 Jun 2012 00:27:00 -0300 Subject: [PATCH 0284/5375] [media] dvb_usb_v2: use lock to sync feed and frontend control There was synchronization problem when streaming was stopped. Frontend was ran down before stream which causes problems. Use mutex to synchronization. Now it looks like that: LOCK start frontend UNLOCK LOCK start streaming [...] stop streaming UNLOCK LOCK stop frontend UNLOCK Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 3 +++ drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 26 ++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index fadc0f988efe..6bd27e511102 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -309,6 +309,9 @@ struct dvb_usb_adapter { int feedcount; int max_feed_count; + /* sync frontend and streaming as those are different tasks */ + struct mutex sync_mutex; + /* dvb */ struct dvb_adapter dvb_adap; struct dmxdev dmxdev; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 484114cbd0ba..97b509332430 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -77,9 +77,10 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) if (ret < 0) { pr_err("%s: error while stopping stream\n", KBUILD_MODNAME); - return ret; + goto err_mutex_unlock; } } + mutex_unlock(&adap->sync_mutex); } adap->feedcount = newfeedcount; @@ -95,12 +96,14 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) adap->props->pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); - /* start the feed if this was the first feed and there is still a feed + /* + * Start the feed if this was the first feed and there is still a feed * for reception. */ if (adap->feedcount == onoff && adap->feedcount > 0) { struct usb_data_stream_properties stream_props; unsigned int ts_props; + mutex_lock(&adap->sync_mutex); /* resolve TS configuration */ if (adap->dev->props->get_ts_config) { @@ -108,7 +111,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) adap->fe[adap->active_fe], &ts_props); if (ret < 0) - return ret; + goto err_mutex_unlock; } else { ts_props = 0; /* normal 188 payload only TS */ } @@ -128,13 +131,12 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) adap->fe[adap->active_fe], &stream_props); if (ret < 0) - return ret; + goto err_mutex_unlock; } else { stream_props = adap->props->stream; } pr_debug("%s: submitting all URBs\n", __func__); - usb_urb_submitv2(&adap->stream, &stream_props); pr_debug("%s: controlling pid parser\n", __func__); @@ -147,7 +149,7 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) if (ret < 0) { pr_err("%s: could not handle pid_parser\n", KBUILD_MODNAME); - return ret; + goto err_mutex_unlock; } } pr_debug("%s: start feeding\n", __func__); @@ -156,12 +158,15 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) if (ret < 0) { pr_err("%s: error while enabling fifo\n", KBUILD_MODNAME); - return ret; + goto err_mutex_unlock; } } } + return 0; +err_mutex_unlock: + mutex_unlock(&adap->sync_mutex); err: pr_debug("%s: failed=%d\n", __func__, ret); return ret; @@ -238,6 +243,7 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) goto err_net_init; } + mutex_init(&adap->sync_mutex); adap->state |= DVB_USB_ADAP_STATE_DVB; return 0; @@ -271,6 +277,7 @@ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) { int ret; struct dvb_usb_adapter *adap = fe->dvb->priv; + mutex_lock(&adap->sync_mutex); pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); ret = dvb_usbv2_device_power_ctrl(adap->dev, 1); @@ -290,9 +297,11 @@ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) } adap->active_fe = fe->id; + mutex_unlock(&adap->sync_mutex); return 0; err: + mutex_unlock(&adap->sync_mutex); pr_debug("%s: failed=%d\n", __func__, ret); return ret; } @@ -301,6 +310,7 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) { int ret; struct dvb_usb_adapter *adap = fe->dvb->priv; + mutex_lock(&adap->sync_mutex); pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); if (adap->fe_sleep[fe->id]) { @@ -320,9 +330,11 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) goto err; adap->active_fe = -1; + mutex_unlock(&adap->sync_mutex); return 0; err: + mutex_unlock(&adap->sync_mutex); pr_debug("%s: failed=%d\n", __func__, ret); return ret; } From 5da2aecb46597c2b4a3dee2eb78863fee0c8354e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 17 Jun 2012 23:15:03 -0300 Subject: [PATCH 0285/5375] [media] af9035: convert to new DVB USB Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 +- drivers/media/dvb/dvb-usb/af9035.c | 753 ++++++++++++----------------- drivers/media/dvb/dvb-usb/af9035.h | 6 +- 3 files changed, 300 insertions(+), 461 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index f172e1471877..bf7e7222e4e3 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -448,7 +448,7 @@ config DVB_USB_RTL28XXU config DVB_USB_AF9035 tristate "Afatech AF9035 DVB-T USB2.0 support" - depends on DVB_USB + depends on DVB_USB_V2 select DVB_AF9033 select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c index e83b39d3993c..ba2a0c1a65a2 100644 --- a/drivers/media/dvb/dvb-usb/af9035.c +++ b/drivers/media/dvb/dvb-usb/af9035.c @@ -22,9 +22,6 @@ #include "af9035.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static DEFINE_MUTEX(af9035_usb_mutex); -static struct dvb_usb_device_properties af9035_properties[2]; -static int af9035_properties_count = ARRAY_SIZE(af9035_properties); static u16 af9035_checksum(const u8 *buf, size_t len) { @@ -42,17 +39,16 @@ static u16 af9035_checksum(const u8 *buf, size_t len) return checksum; } -static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req) +static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) { #define BUF_LEN 64 #define REQ_HDR_LEN 4 /* send header size */ #define ACK_HDR_LEN 3 /* rece header size */ #define CHECKSUM_LEN 2 #define USB_TIMEOUT 2000 - - int ret, msg_len, act_len; + struct state *state = d_to_priv(d); + int ret, wlen, rlen; u8 buf[BUF_LEN]; - static u8 seq; /* packet sequence number */ u16 checksum, tmp_checksum; /* buffer overflow check */ @@ -63,62 +59,41 @@ static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req) return -EINVAL; } - if (mutex_lock_interruptible(&af9035_usb_mutex) < 0) - return -EAGAIN; - buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1; buf[1] = req->mbox; buf[2] = req->cmd; - buf[3] = seq++; - if (req->wlen) - memcpy(&buf[4], req->wbuf, req->wlen); + buf[3] = state->seq++; + memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen); + + wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN; + rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN; /* calc and add checksum */ checksum = af9035_checksum(buf, buf[0] - 1); buf[buf[0] - 1] = (checksum >> 8); buf[buf[0] - 0] = (checksum & 0xff); - msg_len = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN ; + /* no ack for these packets */ + if (req->cmd == CMD_FW_DL) + rlen = 0; - /* send req */ - ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, - &act_len, USB_TIMEOUT); - if (ret < 0) - err("bulk message failed=%d (%d/%d)", ret, msg_len, act_len); - else - if (act_len != msg_len) - ret = -EIO; /* all data is not send */ - if (ret < 0) - goto err_mutex_unlock; + ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen, 0); + if (ret) + goto err; /* no ack for those packets */ if (req->cmd == CMD_FW_DL) - goto exit_mutex_unlock; - - /* receive ack and data if read req */ - msg_len = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN; - ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, - &act_len, USB_TIMEOUT); - if (ret < 0) { - err("recv bulk message failed=%d", ret); - ret = -EIO; - goto err_mutex_unlock; - } - - if (act_len != msg_len) { - err("recv bulk message truncated (%d != %d)", act_len, msg_len); - ret = -EIO; - goto err_mutex_unlock; - } + goto exit; /* verify checksum */ - checksum = af9035_checksum(buf, act_len - 2); - tmp_checksum = (buf[act_len - 2] << 8) | buf[act_len - 1]; + checksum = af9035_checksum(buf, rlen - 2); + tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1]; if (tmp_checksum != checksum) { - err("%s: command=%02x checksum mismatch (%04x != %04x)", - __func__, req->cmd, tmp_checksum, checksum); + pr_err("%s: command=%02x checksum mismatch (%04x != %04x)\n", + KBUILD_MODNAME, req->cmd, tmp_checksum, + checksum); ret = -EIO; - goto err_mutex_unlock; + goto err; } /* check status */ @@ -126,16 +101,18 @@ static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req) pr_debug("%s: command=%02x failed fw error=%d\n", __func__, req->cmd, buf[2]); ret = -EIO; - goto err_mutex_unlock; + goto err; } /* read request, copy returned data to return buf */ if (req->rlen) memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen); -err_mutex_unlock: -exit_mutex_unlock: - mutex_unlock(&af9035_usb_mutex); +exit: + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); return ret; } @@ -155,7 +132,7 @@ static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) wbuf[5] = (reg >> 0) & 0xff; memcpy(&wbuf[6], val, len); - return af9035_ctrl_msg(d->udev, &req); + return af9035_ctrl_msg(d, &req); } /* read multiple registers */ @@ -165,7 +142,7 @@ static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) u8 mbox = (reg >> 16) & 0xff; struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val }; - return af9035_ctrl_msg(d->udev, &req); + return af9035_ctrl_msg(d, &req); } /* write single register */ @@ -205,7 +182,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct state *state = d->priv; + struct state *state = d_to_priv(d); int ret; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) @@ -249,7 +226,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, buf[3] = 0x00; /* reg addr MSB */ buf[4] = 0x00; /* reg addr LSB */ memcpy(&buf[5], msg[0].buf, msg[0].len); - ret = af9035_ctrl_msg(d->udev, &req); + ret = af9035_ctrl_msg(d, &req); } } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) { if (msg[0].len > 40) { @@ -272,7 +249,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, buf[3] = 0x00; /* reg addr MSB */ buf[4] = 0x00; /* reg addr LSB */ memcpy(&buf[5], msg[0].buf, msg[0].len); - ret = af9035_ctrl_msg(d->udev, &req); + ret = af9035_ctrl_msg(d, &req); } } else { /* @@ -301,87 +278,7 @@ static struct i2c_algorithm af9035_i2c_algo = { .functionality = af9035_i2c_functionality, }; -#define AF9035_POLL 250 -static int af9035_rc_query(struct dvb_usb_device *d) -{ - unsigned int key; - unsigned char b[4]; - int ret; - struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b }; - - ret = af9035_ctrl_msg(d->udev, &req); - if (ret < 0) - goto err; - - if ((b[2] + b[3]) == 0xff) { - if ((b[0] + b[1]) == 0xff) { - /* NEC */ - key = b[0] << 8 | b[2]; - } else { - /* ext. NEC */ - key = b[0] << 16 | b[1] << 8 | b[2]; - } - } else { - key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; - } - - rc_keydown(d->rc_dev, key, 0); - -err: - /* ignore errors */ - return 0; -} - -static int af9035_init(struct dvb_usb_device *d) -{ - struct state *state = d->priv; - int ret, i; - u16 frame_size = 87 * 188 / 4; - u8 packet_size = 512 / 4; - struct reg_val_mask tab[] = { - { 0x80f99d, 0x01, 0x01 }, - { 0x80f9a4, 0x01, 0x01 }, - { 0x00dd11, 0x00, 0x20 }, - { 0x00dd11, 0x00, 0x40 }, - { 0x00dd13, 0x00, 0x20 }, - { 0x00dd13, 0x00, 0x40 }, - { 0x00dd11, 0x20, 0x20 }, - { 0x00dd88, (frame_size >> 0) & 0xff, 0xff}, - { 0x00dd89, (frame_size >> 8) & 0xff, 0xff}, - { 0x00dd0c, packet_size, 0xff}, - { 0x00dd11, state->dual_mode << 6, 0x40 }, - { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff}, - { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff}, - { 0x00dd0d, packet_size, 0xff }, - { 0x80f9a3, 0x00, 0x01 }, - { 0x80f9cd, 0x00, 0x01 }, - { 0x80f99d, 0x00, 0x01 }, - { 0x80f9a4, 0x00, 0x01 }, - }; - - pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n", - __func__, d->udev->speed, frame_size, packet_size); - - /* init endpoints */ - for (i = 0; i < ARRAY_SIZE(tab); i++) { - ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val, - tab[i].mask); - if (ret < 0) - goto err; - } - - return 0; - -err: - pr_debug("%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) +static int af9035_identify_state(struct dvb_usb_device *d) { int ret; u8 wbuf[1] = { 1 }; @@ -389,18 +286,18 @@ static int af9035_identify_state(struct usb_device *udev, struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf, sizeof(rbuf), rbuf }; - ret = af9035_ctrl_msg(udev, &req); + ret = af9035_ctrl_msg(d, &req); if (ret < 0) goto err; pr_debug("%s: reply=%02x %02x %02x %02x\n", __func__, rbuf[0], rbuf[1], rbuf[2], rbuf[3]); if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3]) - *cold = 0; + ret = WARM; else - *cold = 1; + ret = COLD; - return 0; + return ret; err: pr_debug("%s: failed=%d\n", __func__, ret); @@ -408,7 +305,7 @@ err: return ret; } -static int af9035_download_firmware(struct usb_device *udev, +static int af9035_download_firmware(struct dvb_usb_device *d, const struct firmware *fw) { int ret, i, j, len; @@ -455,7 +352,7 @@ static int af9035_download_firmware(struct usb_device *udev, /* download begin packet */ req.cmd = CMD_FW_DL_BEGIN; - ret = af9035_ctrl_msg(udev, &req); + ret = af9035_ctrl_msg(d, &req); if (ret < 0) goto err; @@ -467,14 +364,14 @@ static int af9035_download_firmware(struct usb_device *udev, req_fw_dl.wlen = len; req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i + HDR_SIZE + hdr_data_len - j]; - ret = af9035_ctrl_msg(udev, &req_fw_dl); + ret = af9035_ctrl_msg(d, &req_fw_dl); if (ret < 0) goto err; } /* download end packet */ req.cmd = CMD_FW_DL_END; - ret = af9035_ctrl_msg(udev, &req); + ret = af9035_ctrl_msg(d, &req); if (ret < 0) goto err; @@ -485,24 +382,24 @@ static int af9035_download_firmware(struct usb_device *udev, /* firmware loaded, request boot */ req.cmd = CMD_FW_BOOT; - ret = af9035_ctrl_msg(udev, &req); + ret = af9035_ctrl_msg(d, &req); if (ret < 0) goto err; /* ensure firmware starts */ wbuf[0] = 1; - ret = af9035_ctrl_msg(udev, &req_fw_ver); + ret = af9035_ctrl_msg(d, &req_fw_ver); if (ret < 0) goto err; if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { - info("firmware did not run"); + pr_err("%s: firmware did not run\n", KBUILD_MODNAME); ret = -ENODEV; goto err; } - info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2], - rbuf[3]); + pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME, + rbuf[0], rbuf[1], rbuf[2], rbuf[3]); return 0; @@ -512,7 +409,7 @@ err: return ret; } -static int af9035_download_firmware_it9135(struct usb_device *udev, +static int af9035_download_firmware_it9135(struct dvb_usb_device *d, const struct firmware *fw) { int ret, i, i_prev; @@ -545,7 +442,7 @@ static int af9035_download_firmware_it9135(struct usb_device *udev, req_fw_dl.wlen = i - i_prev; req_fw_dl.wbuf = (u8 *) &fw->data[i_prev]; i_prev = i; - ret = af9035_ctrl_msg(udev, &req_fw_dl); + ret = af9035_ctrl_msg(d, &req_fw_dl); if (ret < 0) goto err; @@ -555,24 +452,24 @@ static int af9035_download_firmware_it9135(struct usb_device *udev, /* firmware loaded, request boot */ req.cmd = CMD_FW_BOOT; - ret = af9035_ctrl_msg(udev, &req); + ret = af9035_ctrl_msg(d, &req); if (ret < 0) goto err; /* ensure firmware starts */ wbuf[0] = 1; - ret = af9035_ctrl_msg(udev, &req_fw_ver); + ret = af9035_ctrl_msg(d, &req_fw_ver); if (ret < 0) goto err; if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { - info("firmware did not run"); + pr_err("%s: firmware did not run\n", KBUILD_MODNAME); ret = -ENODEV; goto err; } - info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2], - rbuf[3]); + pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME, + rbuf[0], rbuf[1], rbuf[2], rbuf[3]); return 0; @@ -582,10 +479,9 @@ err: return ret; } -/* abuse that callback as there is no better one for reading eeprom */ -static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +static int af9035_read_config(struct dvb_usb_device *d) { - struct state *state = d->priv; + struct state *state = d_to_priv(d); int ret, i, eeprom_shift = 0; u8 tmp; u16 tmp16; @@ -598,7 +494,7 @@ static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) state->dual_mode = tmp; pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode); - for (i = 0; i < af9035_properties[0].num_adapters; i++) { + for (i = 0; i < state->dual_mode + 1; i++) { /* tuner */ ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp); if (ret < 0) @@ -615,8 +511,8 @@ static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) state->af9033_config[i].spec_inv = 1; break; default: - warn("tuner ID=%02x not supported, please report!", - tmp); + pr_info("%s: tuner ID=%02x not supported, please " \ + "report!", KBUILD_MODNAME, tmp); }; /* tuner IF frequency */ @@ -644,35 +540,9 @@ static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) tmp = (tmp >> 0) & 0x0f; - for (i = 0; i < af9035_properties[0].num_adapters; i++) + for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) state->af9033_config[i].clock = clock_lut[tmp]; - ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp); - if (ret < 0) - goto err; - pr_debug("%s: ir_mode=%02x\n", __func__, tmp); - - /* don't activate rc if in HID mode or if not available */ - if (tmp == 5) { - ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp); - if (ret < 0) - goto err; - pr_debug("%s: ir_type=%02x\n", __func__, tmp); - - switch (tmp) { - case 0: /* NEC */ - default: - d->props.rc.core.protocol = RC_TYPE_NEC; - d->props.rc.core.allowed_protos = RC_TYPE_NEC; - break; - case 1: /* RC6 */ - d->props.rc.core.protocol = RC_TYPE_RC6; - d->props.rc.core.allowed_protos = RC_TYPE_RC6; - break; - } - d->props.rc.core.rc_query = af9035_rc_query; - } - return 0; err: @@ -681,10 +551,9 @@ err: return ret; } -/* abuse that callback as there is no better one for reading eeprom */ -static int af9035_read_mac_address_it9135(struct dvb_usb_device *d, u8 mac[6]) +static int af9035_read_config_it9135(struct dvb_usb_device *d) { - struct state *state = d->priv; + struct state *state = d_to_priv(d); int ret, i; u8 tmp; @@ -697,7 +566,7 @@ static int af9035_read_mac_address_it9135(struct dvb_usb_device *d, u8 mac[6]) tmp = (tmp >> 0) & 0x0f; - for (i = 0; i < af9035_properties[0].num_adapters; i++) + for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) state->af9033_config[i].clock = clock_lut_it9135[tmp]; return 0; @@ -775,7 +644,7 @@ err: static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) { - struct state *state = d->priv; + struct state *state = d_to_priv(d); switch (state->af9033_config[0].tuner) { case AF9033_TUNER_FC0011: @@ -805,7 +674,8 @@ static int af9035_frontend_callback(void *adapter_priv, int component, static int af9035_frontend_attach(struct dvb_usb_adapter *adap) { - struct state *state = adap->dev->priv; + struct state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); int ret; if (!state->af9033_config[adap->id].tuner) { @@ -818,28 +688,28 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL; - ret = af9035_wr_reg(adap->dev, 0x00417f, + ret = af9035_wr_reg(d, 0x00417f, state->af9033_config[1].i2c_addr); if (ret < 0) goto err; - ret = af9035_wr_reg(adap->dev, 0x00d81a, + ret = af9035_wr_reg(d, 0x00d81a, state->dual_mode); if (ret < 0) goto err; } /* attach demodulator */ - adap->fe_adap[0].fe = dvb_attach(af9033_attach, - &state->af9033_config[adap->id], &adap->dev->i2c_adap); - if (adap->fe_adap[0].fe == NULL) { + adap->fe[0] = dvb_attach(af9033_attach, + &state->af9033_config[adap->id], &d->i2c_adap); + if (adap->fe[0] == NULL) { ret = -ENODEV; goto err; } /* disable I2C-gate */ - adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL; - adap->fe_adap[0].fe->callback = af9035_frontend_callback; + adap->fe[0]->ops.i2c_gate_ctrl = NULL; + adap->fe[0]->callback = af9035_frontend_callback; return 0; @@ -873,7 +743,8 @@ static struct tda18218_config af9035_tda18218_config = { static int af9035_tuner_attach(struct dvb_usb_adapter *adap) { - struct state *state = adap->dev->priv; + struct state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); int ret; struct dvb_frontend *fe; @@ -883,93 +754,93 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) AF9035 gpiot2 = TUA9001 RXEN */ /* configure gpiot2 and gpiot2 as output */ - ret = af9035_wr_reg_mask(adap->dev, 0x00d8ec, 0x01, 0x01); + ret = af9035_wr_reg_mask(d, 0x00d8ec, 0x01, 0x01); if (ret < 0) goto err; - ret = af9035_wr_reg_mask(adap->dev, 0x00d8ed, 0x01, 0x01); + ret = af9035_wr_reg_mask(d, 0x00d8ed, 0x01, 0x01); if (ret < 0) goto err; - ret = af9035_wr_reg_mask(adap->dev, 0x00d8e8, 0x01, 0x01); + ret = af9035_wr_reg_mask(d, 0x00d8e8, 0x01, 0x01); if (ret < 0) goto err; - ret = af9035_wr_reg_mask(adap->dev, 0x00d8e9, 0x01, 0x01); + ret = af9035_wr_reg_mask(d, 0x00d8e9, 0x01, 0x01); if (ret < 0) goto err; /* reset tuner */ - ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x00, 0x01); + ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x00, 0x01); if (ret < 0) goto err; usleep_range(2000, 20000); - ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x01, 0x01); + ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x01, 0x01); if (ret < 0) goto err; /* activate tuner RX */ /* TODO: use callback for TUA9001 RXEN */ - ret = af9035_wr_reg_mask(adap->dev, 0x00d8eb, 0x01, 0x01); + ret = af9035_wr_reg_mask(d, 0x00d8eb, 0x01, 0x01); if (ret < 0) goto err; /* attach tuner */ - fe = dvb_attach(tua9001_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, &af9035_tua9001_config); + fe = dvb_attach(tua9001_attach, adap->fe[0], + &d->i2c_adap, &af9035_tua9001_config); break; case AF9033_TUNER_FC0011: - fe = dvb_attach(fc0011_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, &af9035_fc0011_config); + fe = dvb_attach(fc0011_attach, adap->fe[0], + &d->i2c_adap, &af9035_fc0011_config); break; case AF9033_TUNER_MXL5007T: - ret = af9035_wr_reg(adap->dev, 0x00d8e0, 1); + ret = af9035_wr_reg(d, 0x00d8e0, 1); if (ret < 0) goto err; - ret = af9035_wr_reg(adap->dev, 0x00d8e1, 1); + ret = af9035_wr_reg(d, 0x00d8e1, 1); if (ret < 0) goto err; - ret = af9035_wr_reg(adap->dev, 0x00d8df, 0); + ret = af9035_wr_reg(d, 0x00d8df, 0); if (ret < 0) goto err; msleep(30); - ret = af9035_wr_reg(adap->dev, 0x00d8df, 1); + ret = af9035_wr_reg(d, 0x00d8df, 1); if (ret < 0) goto err; msleep(300); - ret = af9035_wr_reg(adap->dev, 0x00d8c0, 1); + ret = af9035_wr_reg(d, 0x00d8c0, 1); if (ret < 0) goto err; - ret = af9035_wr_reg(adap->dev, 0x00d8c1, 1); + ret = af9035_wr_reg(d, 0x00d8c1, 1); if (ret < 0) goto err; - ret = af9035_wr_reg(adap->dev, 0x00d8bf, 0); + ret = af9035_wr_reg(d, 0x00d8bf, 0); if (ret < 0) goto err; - ret = af9035_wr_reg(adap->dev, 0x00d8b4, 1); + ret = af9035_wr_reg(d, 0x00d8b4, 1); if (ret < 0) goto err; - ret = af9035_wr_reg(adap->dev, 0x00d8b5, 1); + ret = af9035_wr_reg(d, 0x00d8b5, 1); if (ret < 0) goto err; - ret = af9035_wr_reg(adap->dev, 0x00d8b3, 1); + ret = af9035_wr_reg(d, 0x00d8b3, 1); if (ret < 0) goto err; /* attach tuner */ - fe = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, 0x60, &af9035_mxl5007t_config); + fe = dvb_attach(mxl5007t_attach, adap->fe[0], + &d->i2c_adap, 0x60, &af9035_mxl5007t_config); break; case AF9033_TUNER_TDA18218: /* attach tuner */ - fe = dvb_attach(tda18218_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, &af9035_tda18218_config); + fe = dvb_attach(tda18218_attach, adap->fe[0], + &d->i2c_adap, &af9035_tda18218_config); break; default: fe = NULL; @@ -988,233 +859,40 @@ err: return ret; } -enum af9035_id_entry { - AF9035_15A4_9035, - AF9035_15A4_1000, - AF9035_15A4_1001, - AF9035_15A4_1002, - AF9035_15A4_1003, - AF9035_0CCD_0093, - AF9035_07CA_A835, - AF9035_07CA_B835, - AF9035_07CA_1867, - AF9035_07CA_A867, - AF9035_07CA_0825, -}; - -static struct usb_device_id af9035_id[] = { - [AF9035_15A4_9035] = { - USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035)}, - [AF9035_15A4_1000] = { - USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000)}, - [AF9035_15A4_1001] = { - USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001)}, - [AF9035_15A4_1002] = { - USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002)}, - [AF9035_15A4_1003] = { - USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003)}, - [AF9035_0CCD_0093] = { - USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK)}, - [AF9035_07CA_A835] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835)}, - [AF9035_07CA_B835] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835)}, - [AF9035_07CA_1867] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867)}, - [AF9035_07CA_A867] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867)}, - [AF9035_07CA_0825] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR)}, - {}, -}; - -MODULE_DEVICE_TABLE(usb, af9035_id); - -static struct dvb_usb_device_properties af9035_properties[] = { - { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = af9035_download_firmware, - .firmware = "dvb-usb-af9035-02.fw", - .no_reconnect = 1, - - .size_of_priv = sizeof(struct state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = { - { - .frontend_attach = af9035_frontend_attach, - .tuner_attach = af9035_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x84, - .u = { - .bulk = { - .buffersize = (87 * 188), - } - } - } - } - } - } - }, - - .identify_state = af9035_identify_state, - .read_mac_address = af9035_read_mac_address, - - .i2c_algo = &af9035_i2c_algo, - - .rc.core = { - .protocol = RC_TYPE_UNKNOWN, - .module_name = "af9035", - .rc_query = NULL, - .rc_interval = AF9035_POLL, - .allowed_protos = RC_TYPE_UNKNOWN, - .rc_codes = RC_MAP_EMPTY, - }, - .num_device_descs = 5, - .devices = { - { - .name = "Afatech AF9035 reference design", - .cold_ids = { - &af9035_id[AF9035_15A4_9035], - &af9035_id[AF9035_15A4_1000], - &af9035_id[AF9035_15A4_1001], - &af9035_id[AF9035_15A4_1002], - &af9035_id[AF9035_15A4_1003], - }, - }, { - .name = "TerraTec Cinergy T Stick", - .cold_ids = { - &af9035_id[AF9035_0CCD_0093], - }, - }, { - .name = "AVerMedia AVerTV Volar HD/PRO (A835)", - .cold_ids = { - &af9035_id[AF9035_07CA_A835], - &af9035_id[AF9035_07CA_B835], - }, - }, { - .name = "AVerMedia HD Volar (A867)", - .cold_ids = { - &af9035_id[AF9035_07CA_1867], - &af9035_id[AF9035_07CA_A867], - }, - }, { - .name = "AVerMedia Twinstar (A825)", - .cold_ids = { - &af9035_id[AF9035_07CA_0825], - }, - }, - } - }, - { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = af9035_download_firmware_it9135, - .firmware = "dvb-usb-it9135-01.fw", - .no_reconnect = 1, - - .size_of_priv = sizeof(struct state), - - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = { - { - .frontend_attach = af9035_frontend_attach, - .tuner_attach = af9035_tuner_attach, - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x84, - .u = { - .bulk = { - .buffersize = (87 * 188), - } - } - } - } - } - } - }, - - .identify_state = af9035_identify_state, - .read_mac_address = af9035_read_mac_address_it9135, - - .i2c_algo = &af9035_i2c_algo, - - .num_device_descs = 0, /* disabled as no support for IT9135 */ - .devices = { - { - .name = "ITE Tech. IT9135 reference design", - }, - } - }, -}; - -static int af9035_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static int af9035_init(struct dvb_usb_device *d) { + struct state *state = d_to_priv(d); int ret, i; - struct dvb_usb_device *d = NULL; - struct usb_device *udev; - bool found; + u16 frame_size = 87 * 188 / 4; + u8 packet_size = 512 / 4; + struct reg_val_mask tab[] = { + { 0x80f99d, 0x01, 0x01 }, + { 0x80f9a4, 0x01, 0x01 }, + { 0x00dd11, 0x00, 0x20 }, + { 0x00dd11, 0x00, 0x40 }, + { 0x00dd13, 0x00, 0x20 }, + { 0x00dd13, 0x00, 0x40 }, + { 0x00dd11, 0x20, 0x20 }, + { 0x00dd88, (frame_size >> 0) & 0xff, 0xff}, + { 0x00dd89, (frame_size >> 8) & 0xff, 0xff}, + { 0x00dd0c, packet_size, 0xff}, + { 0x00dd11, state->dual_mode << 6, 0x40 }, + { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff}, + { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff}, + { 0x00dd0d, packet_size, 0xff }, + { 0x80f9a3, 0x00, 0x01 }, + { 0x80f9cd, 0x00, 0x01 }, + { 0x80f99d, 0x00, 0x01 }, + { 0x80f9a4, 0x00, 0x01 }, + }; - pr_debug("%s: interface=%d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); + pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n", + __func__, d->udev->speed, frame_size, packet_size); - /* interface 0 is used by DVB-T receiver and - interface 1 is for remote controller (HID) */ - if (intf->cur_altsetting->desc.bInterfaceNumber != 0) - return 0; - - /* Dynamic USB ID support. Replaces first device ID with current one. */ - udev = interface_to_usbdev(intf); - - for (i = 0, found = false; i < ARRAY_SIZE(af9035_id) - 1; i++) { - if (af9035_id[i].idVendor == - le16_to_cpu(udev->descriptor.idVendor) && - af9035_id[i].idProduct == - le16_to_cpu(udev->descriptor.idProduct)) { - found = true; - break; - } - } - - if (!found) { - pr_debug("%s: using dynamic ID %04x:%04x\n", __func__, - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - af9035_properties[0].devices[0].cold_ids[0]->idVendor = - le16_to_cpu(udev->descriptor.idVendor); - af9035_properties[0].devices[0].cold_ids[0]->idProduct = - le16_to_cpu(udev->descriptor.idProduct); - } - - - for (i = 0; i < af9035_properties_count; i++) { - ret = dvb_usb_device_init(intf, &af9035_properties[i], - THIS_MODULE, &d, adapter_nr); - - if (ret == -ENODEV) - continue; - else - break; - } - - if (ret < 0) - goto err; - - if (d) { - ret = af9035_init(d); + /* init endpoints */ + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val, + tab[i].mask); if (ret < 0) goto err; } @@ -1227,12 +905,175 @@ err: return ret; } -/* usb specific object needed to register this driver with the usb subsystem */ +static int af9035_rc_query(struct dvb_usb_device *d) +{ + unsigned int key; + unsigned char b[4]; + int ret; + struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b }; + + ret = af9035_ctrl_msg(d, &req); + if (ret < 0) + goto err; + + if ((b[2] + b[3]) == 0xff) { + if ((b[0] + b[1]) == 0xff) { + /* NEC */ + key = b[0] << 8 | b[2]; + } else { + /* ext. NEC */ + key = b[0] << 16 | b[1] << 8 | b[2]; + } + } else { + key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; + } + + rc_keydown(d->rc_dev, key, 0); + +err: + /* ignore errors */ + return 0; +} + +static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) +{ + int ret; + u8 tmp; + + ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp); + if (ret < 0) + goto err; + + pr_debug("%s: ir_mode=%02x\n", __func__, tmp); + + /* don't activate rc if in HID mode or if not available */ + if (tmp == 5) { + ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp); + if (ret < 0) + goto err; + + pr_debug("%s: ir_type=%02x\n", __func__, tmp); + + switch (tmp) { + case 0: /* NEC */ + default: + rc->allowed_protos = RC_TYPE_NEC; + break; + case 1: /* RC6 */ + rc->allowed_protos = RC_TYPE_RC6; + break; + } + + rc->query = af9035_rc_query; + rc->interval = 500; + } + + return 0; + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + + return ret; +} + +/* interface 0 is used by DVB-T receiver and + interface 1 is for remote controller (HID) */ +static const struct dvb_usb_device_properties af9035_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .identify_state = af9035_identify_state, + .firmware = "dvb-usb-af9035-02.fw", + .download_firmware = af9035_download_firmware, + + .i2c_algo = &af9035_i2c_algo, + .read_config = af9035_read_config, + .frontend_attach = af9035_frontend_attach, + .tuner_attach = af9035_tuner_attach, + .init = af9035_init, + .get_rc_config = af9035_get_rc_config, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), + }, { + .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), + }, + }, +}; + +static const struct dvb_usb_device_properties it9135_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .identify_state = af9035_identify_state, + .firmware = "dvb-usb-it9135-01.fw", + .download_firmware = af9035_download_firmware_it9135, + + .i2c_algo = &af9035_i2c_algo, + .read_config = af9035_read_config_it9135, + .frontend_attach = af9035_frontend_attach, + .tuner_attach = af9035_tuner_attach, + .init = af9035_init, + .get_rc_config = af9035_get_rc_config, + + .num_adapters = 1, + .adapter = { + { + .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), + }, { + .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), + }, + }, +}; + +static const struct usb_device_id af9035_id_table[] = { + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003, + &af9035_props, "Afatech AF9035 reference design", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK, + &af9035_props, "TerraTec Cinergy T Stick", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835, + &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835, + &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867, + &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867, + &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR, + &af9035_props, "AVerMedia Twinstar (A825)", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, af9035_id_table); + static struct usb_driver af9035_usb_driver = { - .name = "dvb_usb_af9035", - .probe = af9035_usb_probe, - .disconnect = dvb_usb_device_exit, - .id_table = af9035_id, + .name = KBUILD_MODNAME, + .id_table = af9035_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, }; module_usb_driver(af9035_usb_driver); diff --git a/drivers/media/dvb/dvb-usb/af9035.h b/drivers/media/dvb/dvb-usb/af9035.h index 481a1a43dd2a..59ff69ede0f0 100644 --- a/drivers/media/dvb/dvb-usb/af9035.h +++ b/drivers/media/dvb/dvb-usb/af9035.h @@ -22,10 +22,7 @@ #ifndef AF9035_H #define AF9035_H -/* prefix for dvb-usb log writings */ -#define DVB_USB_LOG_PREFIX "af9035" - -#include "dvb-usb.h" +#include "dvb_usb.h" #include "af9033.h" #include "tua9001.h" #include "fc0011.h" @@ -53,6 +50,7 @@ struct usb_req { }; struct state { + u8 seq; /* packet sequence number */ bool dual_mode; struct af9033_config af9033_config[2]; From 4edcf22bf2cf5fe679dd51c6d0f092f1fabdff1e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 17 Jun 2012 23:42:11 -0300 Subject: [PATCH 0286/5375] [media] dvb_usb_v2: git rid of dvb_usb_adapter state variable We can live without it easily. Also USB data stream complete callback checks for feedcount seems to be quite redundant so remove those also. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 3 --- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 30 +++++++++++-------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 6bd27e511102..933d69004ab7 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -297,9 +297,6 @@ struct usb_data_stream { * @stream: the usb data stream. */ struct dvb_usb_adapter { -#define DVB_USB_ADAP_STATE_INIT 0x000 -#define DVB_USB_ADAP_STATE_DVB 0x001 - int state; struct dvb_usb_device *dev; const struct dvb_usb_adapter_properties *props; struct usb_data_stream stream; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 97b509332430..9e1bf03e03b3 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -8,28 +8,25 @@ */ #include "dvb_usb_common.h" -static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, - size_t length) +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf, + size_t len) { struct dvb_usb_adapter *adap = stream->user_priv; - if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) - dvb_dmx_swfilter(&adap->demux, buffer, length); + dvb_dmx_swfilter(&adap->demux, buf, len); } -static void dvb_usb_data_complete_204(struct usb_data_stream *stream, - u8 *buffer, size_t length) +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf, + size_t len) { struct dvb_usb_adapter *adap = stream->user_priv; - if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) - dvb_dmx_swfilter_204(&adap->demux, buffer, length); + dvb_dmx_swfilter_204(&adap->demux, buf, len); } -static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, - u8 *buffer, size_t length) +static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf, + size_t len) { struct dvb_usb_adapter *adap = stream->user_priv; - if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) - dvb_dmx_swfilter_raw(&adap->demux, buffer, length); + dvb_dmx_swfilter_raw(&adap->demux, buf, len); } int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) @@ -244,9 +241,8 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) } mutex_init(&adap->sync_mutex); - adap->state |= DVB_USB_ADAP_STATE_DVB; - return 0; + return 0; err_net_init: dvb_dmxdev_release(&adap->dmxdev); err_dmx_dev: @@ -254,6 +250,7 @@ err_dmx_dev: err_dmx: dvb_unregister_adapter(&adap->dvb_adap); err: + adap->dvb_adap.priv = NULL; return ret; } @@ -261,15 +258,14 @@ int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) { pr_debug("%s: adap=%d\n", __func__, adap->id); - if (adap->state & DVB_USB_ADAP_STATE_DVB) { - pr_debug("%s: unregistering DVB part\n", __func__); + if (adap->dvb_adap.priv) { dvb_net_release(&adap->dvb_net); adap->demux.dmx.close(&adap->demux.dmx); dvb_dmxdev_release(&adap->dmxdev); dvb_dmx_release(&adap->demux); dvb_unregister_adapter(&adap->dvb_adap); - adap->state &= ~DVB_USB_ADAP_STATE_DVB; } + return 0; } From 05cd62e0f858d45f46e51e2a0db679c30bc8af2d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 18 Jun 2012 19:39:02 -0300 Subject: [PATCH 0287/5375] [media] anysee: use DVB USB macros Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/anysee.c | 189 +++++++++++++---------------- 1 file changed, 82 insertions(+), 107 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 2a0798cfb365..2655034b86a9 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -55,7 +55,7 @@ static DEFINE_MUTEX(anysee_usb_mutex); static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, u8 *rbuf, u8 rlen) { - struct anysee_state *state = d->priv; + struct anysee_state *state = d_to_priv(d); int act_len, ret, i; u8 buf[64]; @@ -191,7 +191,7 @@ static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00}; deb_info("%s: onoff:%02x\n", __func__, onoff); - return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0); + return anysee_ctrl_msg(adap_to_d(adap), buf, sizeof(buf), NULL, 0); } static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval) @@ -508,7 +508,7 @@ static struct cxd2820r_config anysee_cxd2820r_config = { static int anysee_read_config(struct dvb_usb_device *d) { - struct anysee_state *state = d->priv; + struct anysee_state *state = d_to_priv(d); int ret; u8 hw_info[3]; @@ -536,16 +536,14 @@ error: /* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */ static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { - struct dvb_usb_adapter *adap = fe->dvb->priv; - /* enable / disable tuner access on IOE[4] */ - return anysee_wr_reg_mask(adap->dev, REG_IOE, (enable << 4), 0x10); + return anysee_wr_reg_mask(fe_to_d(fe), REG_IOE, (enable << 4), 0x10); } static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) { - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct anysee_state *state = adap->dev->priv; + struct anysee_state *state = fe_to_priv(fe); + struct dvb_usb_device *d = fe_to_d(fe); int ret; deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); @@ -561,38 +559,32 @@ static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) if (fe->id == 0) { /* disable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), - 0x01); + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01); if (ret) goto error; /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), - 0x20); + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); if (ret) goto error; /* enable DVB-C tuner on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), - 0x01); + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01); if (ret) goto error; } else { /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), - 0x20); + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); if (ret) goto error; /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), - 0x01); + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); if (ret) goto error; /* enable DVB-T tuner on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), - 0x01); + ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01); if (ret) goto error; } @@ -605,38 +597,32 @@ static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) if (fe->id == 0) { /* disable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), - 0x40); + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40); if (ret) goto error; /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), - 0x20); + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); if (ret) goto error; /* enable IF route on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), - 0x01); + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01); if (ret) goto error; } else { /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), - 0x20); + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); if (ret) goto error; /* enable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6), - 0x40); + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40); if (ret) goto error; /* enable IF route on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), - 0x01); + ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01); if (ret) goto error; } @@ -652,8 +638,9 @@ error: static int anysee_frontend_attach(struct dvb_usb_adapter *adap) { + struct anysee_state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); int ret; - struct anysee_state *state = adap->dev->priv; u8 tmp; struct i2c_msg msg[2] = { { @@ -674,58 +661,58 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* E30 */ /* attach demod */ - adap->fe[0] = dvb_attach(mt352_attach, - &anysee_mt352_config, &adap->dev->i2c_adap); + adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config, + &d->i2c_adap); if (adap->fe[0]) break; /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, - &anysee_zl10353_config, &adap->dev->i2c_adap); + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, + &d->i2c_adap); break; case ANYSEE_HW_507CD: /* 6 */ /* E30 Plus */ /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); if (ret) goto error; /* enable transport stream on IOA[7] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (0 << 7), 0x80); + ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); if (ret) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, - &anysee_zl10353_config, &adap->dev->i2c_adap); + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, + &d->i2c_adap); break; case ANYSEE_HW_507DC: /* 10 */ /* E30 C Plus */ /* enable DVB-C demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); if (ret) goto error; /* attach demod */ adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48); + &anysee_tda10023_config, &d->i2c_adap, 0x48); break; case ANYSEE_HW_507SI: /* 11 */ /* E30 S2 Plus */ /* enable DVB-S/S2 demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); if (ret) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(cx24116_attach, - &anysee_cx24116_config, &adap->dev->i2c_adap); + adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config, + &d->i2c_adap); break; case ANYSEE_HW_507FA: /* 15 */ @@ -733,30 +720,30 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* E30 C Plus */ /* enable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10); + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 4), 0x10); if (ret) goto error; /* probe TDA18212 */ tmp = 0; - ret = i2c_transfer(&adap->dev->i2c_adap, msg, 2); + ret = i2c_transfer(&d->i2c_adap, msg, 2); if (ret == 2 && tmp == 0xc7) deb_info("%s: TDA18212 found\n", __func__); else tmp = 0; /* disable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10); + ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 4), 0x10); if (ret) goto error; /* disable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), 0x01); + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01); if (ret) goto error; /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), 0x20); + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); if (ret) goto error; @@ -765,7 +752,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* TDA18212 config */ adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_tda18212_config, - &adap->dev->i2c_adap, 0x48); + &d->i2c_adap, 0x48); /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ if (adap->fe[0]) @@ -775,7 +762,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* PLL config */ adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_config, - &adap->dev->i2c_adap, 0x48); + &d->i2c_adap, 0x48); } /* break out if first frontend attaching fails */ @@ -783,12 +770,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) break; /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), 0x20); + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); if (ret) goto error; /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01); if (ret) goto error; @@ -797,7 +784,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* TDA18212 config */ adap->fe[1] = dvb_attach(zl10353_attach, &anysee_zl10353_tda18212_config2, - &adap->dev->i2c_adap); + &d->i2c_adap); /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ if (adap->fe[1]) @@ -807,7 +794,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* PLL config */ adap->fe[1] = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &adap->dev->i2c_adap); + &d->i2c_adap); } break; @@ -817,19 +804,19 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* E7 PTC */ /* disable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), 0x40); + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40); if (ret) goto error; /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), 0x20); + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20); if (ret) goto error; /* attach demod */ adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_tda18212_config, - &adap->dev->i2c_adap, 0x48); + &d->i2c_adap, 0x48); /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ if (adap->fe[0]) @@ -840,19 +827,19 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) break; /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), 0x20); + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20); if (ret) goto error; /* enable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6), 0x40); + ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40); if (ret) goto error; /* attach demod */ adap->fe[1] = dvb_attach(zl10353_attach, &anysee_zl10353_tda18212_config, - &adap->dev->i2c_adap); + &d->i2c_adap); /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ if (adap->fe[1]) @@ -867,13 +854,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* E7 PS2 */ /* enable DVB-S/S2 demod on IOE[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20); if (ret) goto error; /* attach demod */ adap->fe[0] = dvb_attach(stv0900_attach, - &anysee_stv0900_config, &adap->dev->i2c_adap, 0); + &anysee_stv0900_config, &d->i2c_adap, 0); state->has_ci = true; @@ -882,13 +869,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* E7 T2C */ /* enable DVB-T/T2/C demod on IOE[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); + ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20); if (ret) goto error; /* attach demod */ adap->fe[0] = dvb_attach(cxd2820r_attach, - &anysee_cxd2820r_config, &adap->dev->i2c_adap); + &anysee_cxd2820r_config, &d->i2c_adap); state->has_ci = true; @@ -907,7 +894,8 @@ error: static int anysee_tuner_attach(struct dvb_usb_adapter *adap) { - struct anysee_state *state = adap->dev->priv; + struct anysee_state *state = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); struct dvb_frontend *fe; int ret; deb_info("%s: adap=%d\n", __func__, adap->id); @@ -917,34 +905,32 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], - (0xc2 >> 1), NULL, DVB_PLL_THOMSON_DTT7579); + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), NULL, + DVB_PLL_THOMSON_DTT7579); break; case ANYSEE_HW_507CD: /* 6 */ /* E30 Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], - (0xc2 >> 1), &adap->dev->i2c_adap, - DVB_PLL_THOMSON_DTT7579); + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), + &d->i2c_adap, DVB_PLL_THOMSON_DTT7579); break; case ANYSEE_HW_507DC: /* 10 */ /* E30 C Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], - (0xc0 >> 1), &adap->dev->i2c_adap, - DVB_PLL_SAMSUNG_DTOS403IH102A); + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), + &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); break; case ANYSEE_HW_507SI: /* 11 */ /* E30 S2 Plus */ /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe[0], - &adap->dev->i2c_adap, &anysee_isl6423_config); + fe = dvb_attach(isl6423_attach, adap->fe[0], &d->i2c_adap, + &anysee_isl6423_config); break; case ANYSEE_HW_507FA: /* 15 */ @@ -955,14 +941,13 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) * fails attach old simple PLL. */ /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], - &adap->dev->i2c_adap, &anysee_tda18212_config); + fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, + &anysee_tda18212_config); if (fe && adap->fe[1]) { /* attach tuner for 2nd FE */ fe = dvb_attach(tda18212_attach, adap->fe[1], - &adap->dev->i2c_adap, - &anysee_tda18212_config); + &d->i2c_adap, &anysee_tda18212_config); break; } else if (fe) { break; @@ -970,13 +955,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* attach tuner */ fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), - &adap->dev->i2c_adap, - DVB_PLL_SAMSUNG_DTOS403IH102A); + &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); if (fe && adap->fe[1]) { /* attach tuner for 2nd FE */ fe = dvb_attach(dvb_pll_attach, adap->fe[0], - (0xc0 >> 1), &adap->dev->i2c_adap, + (0xc0 >> 1), &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); } @@ -987,13 +971,13 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E7 PTC */ /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], - &adap->dev->i2c_adap, &anysee_tda18212_config); + fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, + &anysee_tda18212_config); if (fe) { /* attach tuner for 2nd FE */ fe = dvb_attach(tda18212_attach, adap->fe[1], - &adap->dev->i2c_adap, &anysee_tda18212_config); + &d->i2c_adap, &anysee_tda18212_config); } break; @@ -1004,12 +988,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* attach tuner */ fe = dvb_attach(stv6110_attach, adap->fe[0], - &anysee_stv6110_config, &adap->dev->i2c_adap); + &anysee_stv6110_config, &d->i2c_adap); if (fe) { /* attach LNB controller */ fe = dvb_attach(isl6423_attach, adap->fe[0], - &adap->dev->i2c_adap, &anysee_isl6423_config); + &d->i2c_adap, &anysee_isl6423_config); } break; @@ -1018,8 +1002,8 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E7 T2C */ /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], - &adap->dev->i2c_adap, &anysee_tda18212_config2); + fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap, + &anysee_tda18212_config2); break; default: @@ -1131,7 +1115,7 @@ static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot) { struct dvb_usb_device *d = ci->data; int ret; - struct anysee_state *state = d->priv; + struct anysee_state *state = d_to_priv(d); state->ci_cam_ready = jiffies + msecs_to_jiffies(1000); @@ -1182,7 +1166,7 @@ static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, int open) { struct dvb_usb_device *d = ci->data; - struct anysee_state *state = d->priv; + struct anysee_state *state = d_to_priv(d); int ret; u8 tmp; @@ -1201,7 +1185,7 @@ static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, static int anysee_ci_init(struct dvb_usb_device *d) { - struct anysee_state *state = d->priv; + struct anysee_state *state = d_to_priv(d); int ret; state->ci.owner = THIS_MODULE; @@ -1236,7 +1220,7 @@ static int anysee_ci_init(struct dvb_usb_device *d) static void anysee_ci_release(struct dvb_usb_device *d) { - struct anysee_state *state = d->priv; + struct anysee_state *state = d_to_priv(d); /* detach CI */ if (state->has_ci) @@ -1247,7 +1231,7 @@ static void anysee_ci_release(struct dvb_usb_device *d) static int anysee_init(struct dvb_usb_device *d) { - struct anysee_state *state = d->priv; + struct anysee_state *state = d_to_priv(d); int ret; /* There is one interface with two alternate settings. @@ -1308,16 +1292,7 @@ static struct dvb_usb_device_properties anysee_props = { .num_adapters = 1, .adapter = { { - .stream = { - .type = USB_BULK, - .count = 8, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = (16*512), - } - } - } + .stream = DVB_USB_STREAM_BULK(0x82, 8, 16 * 512), } } }; From a1da814642fcf7b5f0e28928d809c47d7c689585 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 18 Jun 2012 19:44:08 -0300 Subject: [PATCH 0288/5375] [media] au6610: use DVB USB macros Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/au6610.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c index aaa0fec7d6a8..05f2a8628142 100644 --- a/drivers/media/dvb/dvb-usb/au6610.c +++ b/drivers/media/dvb/dvb-usb/au6610.c @@ -137,7 +137,7 @@ static struct zl10353_config au6610_zl10353_config = { static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) { adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config, - &adap->dev->i2c_adap); + &adap_to_d(adap)->i2c_adap); if (adap->fe[0] == NULL) return -ENODEV; @@ -150,9 +150,9 @@ static struct qt1010_config au6610_qt1010_config = { static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) { - return dvb_attach(qt1010_attach, - adap->fe[0], &adap->dev->i2c_adap, - &au6610_qt1010_config) == NULL ? -ENODEV : 0; + return dvb_attach(qt1010_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, + &au6610_qt1010_config) == NULL ? -ENODEV : 0; } static int au6610_init(struct dvb_usb_device *d) @@ -175,18 +175,7 @@ static struct dvb_usb_device_properties au6610_props = { .num_adapters = 1, .adapter = { { - .stream = { - .type = USB_ISOC, - .count = 5, - .endpoint = 0x82, - .u = { - .isoc = { - .framesperurb = 40, - .framesize = 942, - .interval = 1, - } - } - }, + .stream = DVB_USB_STREAM_ISOC(0x82, 5, 40, 942, 1), }, }, }; From 232b6968b1296ccd4086867c9890b6f55a65256e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 18 Jun 2012 19:50:16 -0300 Subject: [PATCH 0289/5375] [media] ce6230: use DVB USB macros Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/ce6230.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c index b9197a58ba26..84ff4a96ca4e 100644 --- a/drivers/media/dvb/dvb-usb/ce6230.c +++ b/drivers/media/dvb/dvb-usb/ce6230.c @@ -179,7 +179,7 @@ static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) pr_debug("%s:\n", __func__); adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, - &adap->dev->i2c_adap); + &adap_to_d(adap)->i2c_adap); if (adap->fe[0] == NULL) return -ENODEV; @@ -209,7 +209,8 @@ static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) pr_debug("%s:\n", __func__); - ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], + &adap_to_d(adap)->i2c_adap, &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; return ret; } @@ -251,7 +252,7 @@ static struct dvb_usb_device_properties ce6230_props = { .endpoint = 0x82, .u = { .bulk = { - .buffersize = (16*512), + .buffersize = (16 * 512), } } }, From 2731d4ed77e3a58cd44584e3741c8f3e30956e9b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 18 Jun 2012 19:58:44 -0300 Subject: [PATCH 0290/5375] [media] ec168: use DVB UDB macros Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/ec168.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c index 3ed80b01d5fa..c05f09c529e3 100644 --- a/drivers/media/dvb/dvb-usb/ec168.c +++ b/drivers/media/dvb/dvb-usb/ec168.c @@ -271,7 +271,7 @@ static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) { pr_debug("%s:\n", __func__); adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config, - &adap->dev->i2c_adap); + &adap_to_d(adap)->i2c_adap); if (adap->fe[0] == NULL) return -ENODEV; @@ -299,7 +299,7 @@ static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { pr_debug("%s:\n", __func__); return dvb_attach(mxl5005s_attach, adap->fe[0], - &adap->dev->i2c_adap, + &adap_to_d(adap)->i2c_adap, &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; } @@ -309,7 +309,7 @@ static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) pr_debug("%s: onoff=%d\n", __func__, onoff); if (onoff) req.index = 0x0102; - return ec168_ctrl_msg(adap->dev, &req); + return ec168_ctrl_msg(adap_to_d(adap), &req); } /* DVB USB Driver stuff */ @@ -333,16 +333,7 @@ static struct dvb_usb_device_properties ec168_props = { .num_adapters = 1, .adapter = { { - .stream = { - .type = USB_BULK, - .count = 6, - .endpoint = 0x82, - .u = { - .bulk = { - .buffersize = (32*512), - } - } - }, + .stream = DVB_USB_STREAM_BULK(0x82, 6, 32 * 512), } }, }; From ec0dd2f20cb46c3c1fb8a746983c1fe395fd4af3 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 18 Jun 2012 20:09:07 -0300 Subject: [PATCH 0291/5375] [media] dvb_usb_v2: use container_of() for adapter to device We dont need that pointer as we can use container_of() macro thus remove it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 4 +- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 53 +++++++++++++----------- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 1 - 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 933d69004ab7..6b6b7dab8ae4 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -23,7 +23,8 @@ #include "dvb-usb-ids.h" /* helper macros for every DVB USB driver use */ -#define adap_to_d(adap) ((adap)->dev) +#define adap_to_d(adap) (container_of(adap, struct dvb_usb_device, \ + adapter[adap->id])) #define adap_to_priv(adap) (adap_to_d(adap)->priv) #define fe_to_adap(fe) ((struct dvb_usb_adapter *) ((fe)->dvb->priv)) #define fe_to_d(fe) (adap_to_d(fe_to_adap(fe))) @@ -297,7 +298,6 @@ struct usb_data_stream { * @stream: the usb data stream. */ struct dvb_usb_adapter { - struct dvb_usb_device *dev; const struct dvb_usb_adapter_properties *props; struct usb_data_stream stream; u8 id; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 9e1bf03e03b3..27139a2c8d4a 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -33,7 +33,7 @@ int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) { pr_debug("%s: adap=%d\n", __func__, adap->id); - adap->stream.udev = adap->dev->udev; + adap->stream.udev = adap_to_d(adap)->udev; adap->stream.user_priv = adap; adap->stream.complete = dvb_usb_data_complete; @@ -52,6 +52,7 @@ int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) { struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; + struct dvb_usb_device *d = adap_to_d(adap); int newfeedcount, ret; if (adap == NULL) { @@ -69,8 +70,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) pr_debug("%s: stop feeding\n", __func__); usb_urb_killv2(&adap->stream); - if (adap->dev->props->streaming_ctrl != NULL) { - ret = adap->dev->props->streaming_ctrl(adap, 0); + if (d->props->streaming_ctrl != NULL) { + ret = d->props->streaming_ctrl(adap, 0); if (ret < 0) { pr_err("%s: error while stopping stream\n", KBUILD_MODNAME); @@ -103,9 +104,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) mutex_lock(&adap->sync_mutex); /* resolve TS configuration */ - if (adap->dev->props->get_ts_config) { - ret = adap->dev->props->get_ts_config( - adap->fe[adap->active_fe], + if (d->props->get_ts_config) { + ret = d->props->get_ts_config(adap->fe[adap->active_fe], &ts_props); if (ret < 0) goto err_mutex_unlock; @@ -121,10 +121,10 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) adap->stream.complete = dvb_usb_data_complete; /* resolve USB stream configuration */ - if (adap->dev->props->get_usb_stream_config) { + if (d->props->get_usb_stream_config) { memcpy(&stream_props, &adap->props->stream, sizeof(struct usb_data_stream_properties)); - ret = adap->dev->props->get_usb_stream_config( + ret = d->props->get_usb_stream_config( adap->fe[adap->active_fe], &stream_props); if (ret < 0) @@ -150,8 +150,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } } pr_debug("%s: start feeding\n", __func__); - if (adap->dev->props->streaming_ctrl != NULL) { - ret = adap->dev->props->streaming_ctrl(adap, 1); + if (d->props->streaming_ctrl != NULL) { + ret = d->props->streaming_ctrl(adap, 1); if (ret < 0) { pr_err("%s: error while enabling fifo\n", KBUILD_MODNAME); @@ -186,11 +186,11 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) { int ret; + struct dvb_usb_device *d = adap_to_d(adap); pr_debug("%s: adap=%d\n", __func__, adap->id); - ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->name, - adap->dev->props->owner, &adap->dev->udev->dev, - adap->dev->props->adapter_nr); + ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner, + &d->udev->dev, d->props->adapter_nr); if (ret < 0) { pr_debug("%s: dvb_register_adapter() failed=%d\n", __func__, ret); @@ -199,8 +199,8 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->dvb_adap.priv = adap; - if (adap->dev->props->read_mac_address) { - ret = adap->dev->props->read_mac_address(adap, + if (d->props->read_mac_address) { + ret = d->props->read_mac_address(adap, adap->dvb_adap.proposed_mac); if (ret < 0) goto err_dmx; @@ -273,15 +273,16 @@ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) { int ret; struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); mutex_lock(&adap->sync_mutex); pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); - ret = dvb_usbv2_device_power_ctrl(adap->dev, 1); + ret = dvb_usbv2_device_power_ctrl(d, 1); if (ret < 0) goto err; - if (adap->dev->props->frontend_ctrl) { - ret = adap->dev->props->frontend_ctrl(fe, 1); + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 1); if (ret < 0) goto err; } @@ -306,6 +307,7 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) { int ret; struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); mutex_lock(&adap->sync_mutex); pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); @@ -315,13 +317,13 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) goto err; } - if (adap->dev->props->frontend_ctrl) { - ret = adap->dev->props->frontend_ctrl(fe, 0); + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 0); if (ret < 0) goto err; } - ret = dvb_usbv2_device_power_ctrl(adap->dev, 0); + ret = dvb_usbv2_device_power_ctrl(d, 0); if (ret < 0) goto err; @@ -338,13 +340,14 @@ err: int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) { int ret, i, count_registered = 0; + struct dvb_usb_device *d = adap_to_d(adap); pr_debug("%s: adap=%d\n", __func__, adap->id); memset(adap->fe, 0, sizeof(adap->fe)); adap->active_fe = -1; - if (adap->dev->props->frontend_attach) { - ret = adap->dev->props->frontend_attach(adap); + if (d->props->frontend_attach) { + ret = d->props->frontend_attach(adap); if (ret < 0) { pr_debug("%s: frontend_attach() failed=%d\n", __func__, ret); @@ -375,8 +378,8 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) count_registered++; } - if (adap->dev->props->tuner_attach) { - ret = adap->dev->props->tuner_attach(adap); + if (d->props->tuner_attach) { + ret = d->props->tuner_attach(adap); if (ret < 0) { pr_debug("%s: tuner_attach() failed=%d\n", __func__, ret); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index e393fb557398..2624daa94b4f 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -226,7 +226,6 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) for (i = 0; i < adapter_count; i++) { adap = &d->adapter[i]; - adap->dev = d; adap->id = i; adap->props = &d->props->adapter[i]; From b905a2a13307035a4a5c9a93a3607e51e6736db2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 18 Jun 2012 22:54:16 -0300 Subject: [PATCH 0292/5375] [media] dvb_usb_v2: merge get_ts_config() to get_usb_stream_config() Piggypag TS type callback to USB stream callback and change callback name slightly to fit better. Both of those are rather rare callback and has a relation. Transport Stream, TS, is input stream and USB stream is output stream of DVB USB bridge. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 4 +-- drivers/media/dvb/dvb-usb/dvb_usb.h | 10 +++---- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 39 +++++++++++-------------- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 0f87eafae2d2..101b399e76a1 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -599,7 +599,7 @@ error: return ret; } -static int af9015_get_usb_stream_config(struct dvb_frontend *fe, +static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, struct usb_data_stream_properties *stream) { deb_info("%s: adap=%d\n", __func__, fe_to_adap(fe)->id); @@ -1304,7 +1304,7 @@ static struct dvb_usb_device_properties af9015_props = { .tuner_attach = af9015_tuner_attach, .init = af9015_init, .get_rc_config = af9015_get_rc_config, - .get_usb_stream_config = af9015_get_usb_stream_config, + .get_stream_config = af9015_get_stream_config, .get_adapter_count = af9015_get_adapter_count, .adapter = { diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 6b6b7dab8ae4..3a54fc3da702 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -124,8 +124,6 @@ struct dvb_usb_adapter_properties { #define DVB_USB_ADAP_HAS_PID_FILTER 0x01 #define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 #define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 -#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 -#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD 0x10 int caps; int size_of_priv; @@ -228,9 +226,11 @@ struct dvb_usb_device_properties { int (*init) (struct dvb_usb_device *); void (*disconnect) (struct dvb_usb_device *); int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *); - int (*get_usb_stream_config) (struct dvb_frontend *, +#define DVB_USB_FE_TS_TYPE_188 0 +#define DVB_USB_FE_TS_TYPE_204 1 +#define DVB_USB_FE_TS_TYPE_RAW 2 + int (*get_stream_config) (struct dvb_frontend *, u8 *, struct usb_data_stream_properties *); - int (*get_ts_config) (struct dvb_frontend *, unsigned int *); struct i2c_algorithm *i2c_algo; @@ -301,7 +301,7 @@ struct dvb_usb_adapter { const struct dvb_usb_adapter_properties *props; struct usb_data_stream stream; u8 id; - + u8 ts_type; int pid_filtering; int feedcount; int max_feed_count; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index 27139a2c8d4a..f87319c788c0 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -100,39 +100,34 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) */ if (adap->feedcount == onoff && adap->feedcount > 0) { struct usb_data_stream_properties stream_props; - unsigned int ts_props; mutex_lock(&adap->sync_mutex); - /* resolve TS configuration */ - if (d->props->get_ts_config) { - ret = d->props->get_ts_config(adap->fe[adap->active_fe], - &ts_props); - if (ret < 0) - goto err_mutex_unlock; - } else { - ts_props = 0; /* normal 188 payload only TS */ - } - - if (ts_props & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) - adap->stream.complete = dvb_usb_data_complete_204; - else if (ts_props & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD) - adap->stream.complete = dvb_usb_data_complete_raw; - else - adap->stream.complete = dvb_usb_data_complete; - - /* resolve USB stream configuration */ - if (d->props->get_usb_stream_config) { + /* resolve input and output streaming paramters */ + if (d->props->get_stream_config) { memcpy(&stream_props, &adap->props->stream, sizeof(struct usb_data_stream_properties)); - ret = d->props->get_usb_stream_config( + ret = d->props->get_stream_config( adap->fe[adap->active_fe], - &stream_props); + &adap->ts_type, &stream_props); if (ret < 0) goto err_mutex_unlock; } else { stream_props = adap->props->stream; } + switch (adap->ts_type) { + case DVB_USB_FE_TS_TYPE_204: + adap->stream.complete = dvb_usb_data_complete_204; + break; + case DVB_USB_FE_TS_TYPE_RAW: + adap->stream.complete = dvb_usb_data_complete_raw; + break; + case DVB_USB_FE_TS_TYPE_188: + default: + adap->stream.complete = dvb_usb_data_complete; + break; + } + pr_debug("%s: submitting all URBs\n", __func__); usb_urb_submitv2(&adap->stream, &stream_props); From a0921af7eb2eced1639fc1e1befdf703e7bec95a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 18 Jun 2012 23:42:53 -0300 Subject: [PATCH 0293/5375] [media] dvb_usb_v2: use identify_state() to resolve firmware name Merge get_firmware_name() to identify_state(). It is wise to resolve firmware name in that routine as it does decision wether or not to load firmware at all. It is one very rarely needed callback less. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 2 +- drivers/media/dvb/dvb-usb/af9035.c | 2 +- drivers/media/dvb/dvb-usb/dvb_usb.h | 11 ++-- drivers/media/dvb/dvb-usb/dvb_usb_init.c | 74 +++++++++++------------- drivers/media/dvb/dvb-usb/ec168.c | 2 +- 5 files changed, 40 insertions(+), 51 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 101b399e76a1..6cecd755f1d9 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -324,7 +324,7 @@ static struct i2c_algorithm af9015_i2c_algo = { .functionality = af9015_i2c_func, }; -static int af9015_identify_state(struct dvb_usb_device *d) +static int af9015_identify_state(struct dvb_usb_device *d, const char **name) { int ret; u8 reply; diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c index ba2a0c1a65a2..b030055d14a3 100644 --- a/drivers/media/dvb/dvb-usb/af9035.c +++ b/drivers/media/dvb/dvb-usb/af9035.c @@ -278,7 +278,7 @@ static struct i2c_algorithm af9035_i2c_algo = { .functionality = af9035_i2c_functionality, }; -static int af9035_identify_state(struct dvb_usb_device *d) +static int af9035_identify_state(struct dvb_usb_device *d, const char **name) { int ret; u8 wbuf[1] = { 1 }; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 3a54fc3da702..aecba307105e 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -197,12 +197,13 @@ struct dvb_usb_device_properties { struct module *owner; short *adapter_nr; u8 bInterfaceNumber; - int size_of_priv; +#define WARM 0 +#define COLD 1 + int (*identify_state) (struct dvb_usb_device *, const char **); const char *firmware; - int (*get_firmware_name) (struct dvb_usb_device *, const char **); -#define RECONNECTS_USB 1 +#define RECONNECTS_USB 1 int (*download_firmware) (struct dvb_usb_device *, const struct firmware *); @@ -219,10 +220,6 @@ struct dvb_usb_device_properties { int (*streaming_ctrl) (struct dvb_usb_adapter *, int); int (*fe_ioctl_override) (struct dvb_frontend *, unsigned int, void *, unsigned int); - -#define WARM 0 -#define COLD 1 - int (*identify_state) (struct dvb_usb_device *); int (*init) (struct dvb_usb_device *); void (*disconnect) (struct dvb_usb_device *); int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 2624daa94b4f..24e1f2970d8e 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -24,19 +24,10 @@ module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a" \ " PID filter, if any (default: 0)."); -static int dvb_usbv2_download_firmware(struct dvb_usb_device *d) +static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name) { int ret; - const struct firmware *fw = NULL; - const char *name; - - /* resolve firmware name */ - name = d->props->firmware; - if (d->props->get_firmware_name) { - ret = d->props->get_firmware_name(d, &name); - if (ret < 0) - goto err; - } + const struct firmware *fw; if (!d->props->download_firmware) { ret = -EINVAL; @@ -395,7 +386,6 @@ static void dvb_usbv2_init_work(struct work_struct *work) int ret; struct dvb_usb_device *d = container_of(work, struct dvb_usb_device, probe_work); - bool cold = false; d->work_pid = current->pid; @@ -411,40 +401,42 @@ static void dvb_usbv2_init_work(struct work_struct *work) } if (d->props->identify_state) { - ret = d->props->identify_state(d); + const char *name = NULL; + ret = d->props->identify_state(d, &name); if (ret == 0) { ; } else if (ret == COLD) { - cold = true; - ret = 0; - } else { - goto err_usb_driver_release_interface; - } - } + pr_info("%s: found a '%s' in cold state\n", + KBUILD_MODNAME, d->name); - if (cold) { - pr_info("%s: found a '%s' in cold state\n", - KBUILD_MODNAME, d->name); - ret = dvb_usbv2_download_firmware(d); - if (ret == 0) { - /* device is warm, continue initialization */ - ; - } else if (ret == RECONNECTS_USB) { - /* - * USB core will call disconnect() and then probe() - * as device reconnects itself from the USB bus. - * disconnect() will release all driver resources - * and probe() is called for 'new' device. As 'new' - * device is warm we should never go here again. - */ - return; + if (!name) + name = d->props->firmware; + + ret = dvb_usbv2_download_firmware(d, name); + if (ret == 0) { + /* device is warm, continue initialization */ + ; + } else if (ret == RECONNECTS_USB) { + /* + * USB core will call disconnect() and then + * probe() as device reconnects itself from the + * USB bus. disconnect() will release all driver + * resources and probe() is called for 'new' + * device. As 'new' device is warm we should + * never go here again. + */ + return; + } else { + /* Unexpected error. We must unregister driver + * manually from the device, because device is + * already register by returning from probe() + * with success. usb_driver_release_interface() + * finally calls disconnect() in order to free + * resources. + */ + goto err_usb_driver_release_interface; + } } else { - /* Unexpected fatal error. We must unregister driver - * manually from the device, because device is already - * register by returning from probe() with success. - * usb_driver_release_interface() finally calls - * disconnect() in order to free resources. - */ goto err_usb_driver_release_interface; } } diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c index c05f09c529e3..1fb84728a27d 100644 --- a/drivers/media/dvb/dvb-usb/ec168.c +++ b/drivers/media/dvb/dvb-usb/ec168.c @@ -182,7 +182,7 @@ static struct i2c_algorithm ec168_i2c_algo = { }; /* Callbacks for DVB USB */ -static int ec168_identify_state(struct dvb_usb_device *d) +static int ec168_identify_state(struct dvb_usb_device *d, const char **name) { int ret; u8 reply; From 5cd983200ae8cba06d6ff5f515f741a654b62cf1 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 19 Jun 2012 20:03:02 -0300 Subject: [PATCH 0294/5375] [media] dvb_usb_v2: remove num_adapters_initialized variable We can live easily without it so remove it, make code and binary few bytes smaller. >From struct dvb_usb_device variable int num_adapters_initialized. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 1 - drivers/media/dvb/dvb-usb/dvb_usb_init.c | 14 ++++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index aecba307105e..2bef8f4ab71a 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -360,7 +360,6 @@ struct dvb_usb_device { struct mutex i2c_mutex; struct i2c_adapter i2c_adap; - int num_adapters_initialized; struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; /* remote control */ diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c index 24e1f2970d8e..1d92d831ab27 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c @@ -270,8 +270,6 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) adap->dvb_adap.mfe_shared = 1; adap->dvb_adap.fe_ioctl_override = d->props->fe_ioctl_override; - - d->num_adapters_initialized++; } return 0; @@ -292,8 +290,6 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) dvb_usbv2_adapter_stream_exit(&d->adapter[i]); } - d->num_adapters_initialized = 0; - return 0; } @@ -551,8 +547,9 @@ int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) cancel_delayed_work_sync(&d->rc_query_work); /* stop streaming */ - for (i = d->num_adapters_initialized - 1; i >= 0; i--) { - if (d->adapter[i].active_fe != -1) + for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { + if (d->adapter[i].dvb_adap.priv && + d->adapter[i].active_fe != -1) usb_urb_killv2(&d->adapter[i].stream); } @@ -568,8 +565,9 @@ int dvb_usbv2_resume(struct usb_interface *intf) pr_debug("%s:\n", __func__); /* start streaming */ - for (i = 0; i < d->num_adapters_initialized; i++) { - if (d->adapter[i].active_fe != -1) + for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) { + if (d->adapter[i].dvb_adap.priv && + d->adapter[i].active_fe != -1) usb_urb_submitv2(&d->adapter[i].stream, NULL); } From 62a5f449cab52a458120ba5b046675ee2f81000f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 19 Jun 2012 21:47:42 -0300 Subject: [PATCH 0295/5375] [media] dvb_usb_v2: refactor dvb_usb_ctrl_feed() logic Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_dvb.c | 88 +++++++++++-------------- 2 files changed, 39 insertions(+), 51 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 2bef8f4ab71a..a87a9ff579c4 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -300,7 +300,7 @@ struct dvb_usb_adapter { u8 id; u8 ts_type; int pid_filtering; - int feedcount; + int feed_count; int max_feed_count; /* sync frontend and streaming as those are different tasks */ diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c index f87319c788c0..384fe8eec21f 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c @@ -49,58 +49,54 @@ int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) } /* does the complete input transfer handling */ -static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) +static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int count) { struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; struct dvb_usb_device *d = adap_to_d(adap); - int newfeedcount, ret; + int ret; + pr_debug("%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: " \ + "%04x (%04d) at index %d '%s'\n", __func__, adap->id, + adap->active_fe, dvbdmxfeed->type, + adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, + dvbdmxfeed->pid, dvbdmxfeed->index, + (count == 1) ? "on" : "off"); - if (adap == NULL) { - ret = -ENODEV; - goto err; - } + if (adap->active_fe == -1) + return -EINVAL; - pr_debug("%s: adap=%d active_fe=%d\n", __func__, adap->id, - adap->active_fe); + adap->feed_count += count; - newfeedcount = adap->feedcount + (onoff ? 1 : -1); - - /* stop feed before setting a new pid if there will be no pid anymore */ - if (newfeedcount == 0) { + /* stop feeding if it is last pid */ + if (adap->feed_count == 0) { pr_debug("%s: stop feeding\n", __func__); usb_urb_killv2(&adap->stream); - if (d->props->streaming_ctrl != NULL) { + if (d->props->streaming_ctrl) { ret = d->props->streaming_ctrl(adap, 0); if (ret < 0) { - pr_err("%s: error while stopping stream\n", - KBUILD_MODNAME); + pr_err("%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); goto err_mutex_unlock; } } mutex_unlock(&adap->sync_mutex); } - adap->feedcount = newfeedcount; - - /* activate the pid on the device specific pid_filter */ - pr_debug("%s: setting pid (%s): %5d %04x at index %d '%s'\n", __func__, - adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, - dvbdmxfeed->pid, dvbdmxfeed->index, - onoff ? "on" : "off"); + /* activate the pid on the device pid filter */ if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && adap->pid_filtering && - adap->props->pid_filter != NULL) - adap->props->pid_filter(adap, dvbdmxfeed->index, - dvbdmxfeed->pid, onoff); + adap->props->pid_filter) + ret = adap->props->pid_filter(adap, dvbdmxfeed->index, + dvbdmxfeed->pid, (count == 1) ? 1 : 0); + if (ret < 0) + pr_err("%s: pid_filter() failed=%d\n", + KBUILD_MODNAME, ret); - /* - * Start the feed if this was the first feed and there is still a feed - * for reception. - */ - if (adap->feedcount == onoff && adap->feedcount > 0) { + /* start feeding if it is first pid */ + if (adap->feed_count == 1 && count == 1) { struct usb_data_stream_properties stream_props; mutex_lock(&adap->sync_mutex); + pr_debug("%s: start feeding\n", __func__); /* resolve input and output streaming paramters */ if (d->props->get_stream_config) { @@ -128,54 +124,46 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) break; } - pr_debug("%s: submitting all URBs\n", __func__); usb_urb_submitv2(&adap->stream, &stream_props); - pr_debug("%s: controlling pid parser\n", __func__); if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && adap->props->caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && - adap->props->pid_filter_ctrl != NULL) { + adap->props->pid_filter_ctrl) { ret = adap->props->pid_filter_ctrl(adap, adap->pid_filtering); if (ret < 0) { - pr_err("%s: could not handle pid_parser\n", - KBUILD_MODNAME); - goto err_mutex_unlock; - } - } - pr_debug("%s: start feeding\n", __func__); - if (d->props->streaming_ctrl != NULL) { - ret = d->props->streaming_ctrl(adap, 1); - if (ret < 0) { - pr_err("%s: error while enabling fifo\n", - KBUILD_MODNAME); + pr_err("%s: pid_filter_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); goto err_mutex_unlock; } } + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl(adap, 1); + if (ret < 0) { + pr_err("%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } } return 0; err_mutex_unlock: mutex_unlock(&adap->sync_mutex); -err: pr_debug("%s: failed=%d\n", __func__, ret); return ret; } static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { - pr_debug("%s: start pid=%04x feedtype=%d\n", __func__, dvbdmxfeed->pid, - dvbdmxfeed->type); return dvb_usb_ctrl_feed(dvbdmxfeed, 1); } static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { - pr_debug("%s: stop pid=%04x feedtype=%d\n", __func__, dvbdmxfeed->pid, - dvbdmxfeed->type); - return dvb_usb_ctrl_feed(dvbdmxfeed, 0); + return dvb_usb_ctrl_feed(dvbdmxfeed, -1); } int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) From 41a0abf7100928b412be4d35d62fd77c83064a9b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 19 Jun 2012 22:21:34 -0300 Subject: [PATCH 0296/5375] [media] dvb_usb_v2: merge files dvb_usb_init.c and dvb_usb_dvb.c Merge files dvb_usb_init.c and dvb_usb_dvb.c to dvb_usb_core.c. It is still under 1000 lines of code after all the optimization so put it one file. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Makefile | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 12 - .../{dvb_usb_init.c => dvb_usb_core.c} | 442 +++++++++++++++++- 3 files changed, 419 insertions(+), 37 deletions(-) rename drivers/media/dvb/dvb-usb/{dvb_usb_init.c => dvb_usb_core.c} (59%) diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 490e2a295f3f..50f506e0632a 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -1,7 +1,7 @@ dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o obj-$(CONFIG_DVB_USB) += dvb-usb.o -dvb_usbv2-objs = dvb_usb_init.o dvb_usb_urb.o dvb_usb_dvb.o usb_urb.o +dvb_usbv2-objs = dvb_usb_core.o dvb_usb_urb.o usb_urb.o obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o obj-$(CONFIG_DVB_USB_FIRMWARE) += dvb_usb_firmware.o diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index c94a900c3264..80c8bd3079c5 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -11,11 +11,7 @@ #include "dvb_usb.h" -extern int dvb_usbv2_disable_rc_polling; - /* commonly used methods */ -extern int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff); - extern int usb_urb_initv2(struct usb_data_stream *stream, const struct usb_data_stream_properties *props); extern int usb_urb_exitv2(struct usb_data_stream *stream); @@ -23,12 +19,4 @@ extern int usb_urb_submitv2(struct usb_data_stream *stream, struct usb_data_stream_properties *props); extern int usb_urb_killv2(struct usb_data_stream *stream); -extern int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap); -extern int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap); - -extern int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap); -extern int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap); -extern int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap); -extern int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap); - #endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_core.c similarity index 59% rename from drivers/media/dvb/dvb-usb/dvb_usb_init.c rename to drivers/media/dvb/dvb-usb/dvb_usb_core.c index 1d92d831ab27..f3e1ec2c473e 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_core.c @@ -200,6 +200,424 @@ static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) return 0; } +static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter(&adap->demux, buf, len); +} + +static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter_204(&adap->demux, buf, len); +} + +static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf, + size_t len) +{ + struct dvb_usb_adapter *adap = stream->user_priv; + dvb_dmx_swfilter_raw(&adap->demux, buf, len); +} + +int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) +{ + pr_debug("%s: adap=%d\n", __func__, adap->id); + + adap->stream.udev = adap_to_d(adap)->udev; + adap->stream.user_priv = adap; + adap->stream.complete = dvb_usb_data_complete; + + return usb_urb_initv2(&adap->stream, &adap->props->stream); +} + +int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) +{ + pr_debug("%s: adap=%d\n", __func__, adap->id); + usb_urb_exitv2(&adap->stream); + + return 0; +} + +static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, + int count) +{ + struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + pr_debug("%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: " \ + "%04x (%04d) at index %d '%s'\n", __func__, adap->id, + adap->active_fe, dvbdmxfeed->type, + adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, + dvbdmxfeed->pid, dvbdmxfeed->index, + (count == 1) ? "on" : "off"); + + if (adap->active_fe == -1) + return -EINVAL; + + adap->feed_count += count; + + /* stop feeding if it is last pid */ + if (adap->feed_count == 0) { + pr_debug("%s: stop feeding\n", __func__); + usb_urb_killv2(&adap->stream); + + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl(adap, 0); + if (ret < 0) { + pr_err("%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } + mutex_unlock(&adap->sync_mutex); + } + + /* activate the pid on the device pid filter */ + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->pid_filtering && + adap->props->pid_filter) + ret = adap->props->pid_filter(adap, dvbdmxfeed->index, + dvbdmxfeed->pid, (count == 1) ? 1 : 0); + if (ret < 0) + pr_err("%s: pid_filter() failed=%d\n", + KBUILD_MODNAME, ret); + + /* start feeding if it is first pid */ + if (adap->feed_count == 1 && count == 1) { + struct usb_data_stream_properties stream_props; + mutex_lock(&adap->sync_mutex); + pr_debug("%s: start feeding\n", __func__); + + /* resolve input and output streaming paramters */ + if (d->props->get_stream_config) { + memcpy(&stream_props, &adap->props->stream, + sizeof(struct usb_data_stream_properties)); + ret = d->props->get_stream_config( + adap->fe[adap->active_fe], + &adap->ts_type, &stream_props); + if (ret < 0) + goto err_mutex_unlock; + } else { + stream_props = adap->props->stream; + } + + switch (adap->ts_type) { + case DVB_USB_FE_TS_TYPE_204: + adap->stream.complete = dvb_usb_data_complete_204; + break; + case DVB_USB_FE_TS_TYPE_RAW: + adap->stream.complete = dvb_usb_data_complete_raw; + break; + case DVB_USB_FE_TS_TYPE_188: + default: + adap->stream.complete = dvb_usb_data_complete; + break; + } + + usb_urb_submitv2(&adap->stream, &stream_props); + + if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && + adap->props->caps & + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && + adap->props->pid_filter_ctrl) { + ret = adap->props->pid_filter_ctrl(adap, + adap->pid_filtering); + if (ret < 0) { + pr_err("%s: pid_filter_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } + + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl(adap, 1); + if (ret < 0) { + pr_err("%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + goto err_mutex_unlock; + } + } + } + + return 0; +err_mutex_unlock: + mutex_unlock(&adap->sync_mutex); + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + return dvb_usb_ctrl_feed(dvbdmxfeed, 1); +} + +static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + return dvb_usb_ctrl_feed(dvbdmxfeed, -1); +} + +int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) +{ + int ret; + struct dvb_usb_device *d = adap_to_d(adap); + pr_debug("%s: adap=%d\n", __func__, adap->id); + + ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner, + &d->udev->dev, d->props->adapter_nr); + if (ret < 0) { + pr_debug("%s: dvb_register_adapter() failed=%d\n", __func__, + ret); + goto err; + } + + adap->dvb_adap.priv = adap; + + if (d->props->read_mac_address) { + ret = d->props->read_mac_address(adap, + adap->dvb_adap.proposed_mac); + if (ret < 0) + goto err_dmx; + + pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME, + adap->dvb_adap.proposed_mac); + } + + adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + adap->demux.priv = adap; + adap->demux.filternum = 0; + if (adap->demux.filternum < adap->max_feed_count) + adap->demux.filternum = adap->max_feed_count; + adap->demux.feednum = adap->demux.filternum; + adap->demux.start_feed = dvb_usb_start_feed; + adap->demux.stop_feed = dvb_usb_stop_feed; + adap->demux.write_to_decoder = NULL; + ret = dvb_dmx_init(&adap->demux); + if (ret < 0) { + pr_err("%s: dvb_dmx_init() failed=%d\n", KBUILD_MODNAME, ret); + goto err_dmx; + } + + adap->dmxdev.filternum = adap->demux.filternum; + adap->dmxdev.demux = &adap->demux.dmx; + adap->dmxdev.capabilities = 0; + ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); + if (ret < 0) { + pr_err("%s: dvb_dmxdev_init() failed=%d\n", KBUILD_MODNAME, + ret); + goto err_dmx_dev; + } + + ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); + if (ret < 0) { + pr_err("%s: dvb_net_init() failed=%d\n", KBUILD_MODNAME, ret); + goto err_net_init; + } + + mutex_init(&adap->sync_mutex); + + return 0; +err_net_init: + dvb_dmxdev_release(&adap->dmxdev); +err_dmx_dev: + dvb_dmx_release(&adap->demux); +err_dmx: + dvb_unregister_adapter(&adap->dvb_adap); +err: + adap->dvb_adap.priv = NULL; + return ret; +} + +int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) +{ + pr_debug("%s: adap=%d\n", __func__, adap->id); + + if (adap->dvb_adap.priv) { + dvb_net_release(&adap->dvb_net); + adap->demux.dmx.close(&adap->demux.dmx); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + dvb_unregister_adapter(&adap->dvb_adap); + } + + return 0; +} + +int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + + if (onoff) + d->powered++; + else + d->powered--; + + if (d->powered == 0 || (onoff && d->powered == 1)) { + /* when switching from 1 to 0 or from 0 to 1 */ + pr_debug("%s: power control=%d\n", __func__, onoff); + if (d->props->power_ctrl) { + ret = d->props->power_ctrl(d, onoff); + goto err; + } + } + + return 0; +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); + mutex_lock(&adap->sync_mutex); + pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); + + ret = dvb_usbv2_device_power_ctrl(d, 1); + if (ret < 0) + goto err; + + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 1); + if (ret < 0) + goto err; + } + + if (adap->fe_init[fe->id]) { + ret = adap->fe_init[fe->id](fe); + if (ret < 0) + goto err; + } + + adap->active_fe = fe->id; + mutex_unlock(&adap->sync_mutex); + + return 0; +err: + mutex_unlock(&adap->sync_mutex); + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +static int dvb_usb_fe_sleep(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *d = adap_to_d(adap); + mutex_lock(&adap->sync_mutex); + pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); + + if (adap->fe_sleep[fe->id]) { + ret = adap->fe_sleep[fe->id](fe); + if (ret < 0) + goto err; + } + + if (d->props->frontend_ctrl) { + ret = d->props->frontend_ctrl(fe, 0); + if (ret < 0) + goto err; + } + + ret = dvb_usbv2_device_power_ctrl(d, 0); + if (ret < 0) + goto err; + + adap->active_fe = -1; + mutex_unlock(&adap->sync_mutex); + + return 0; +err: + mutex_unlock(&adap->sync_mutex); + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) +{ + int ret, i, count_registered = 0; + struct dvb_usb_device *d = adap_to_d(adap); + pr_debug("%s: adap=%d\n", __func__, adap->id); + + memset(adap->fe, 0, sizeof(adap->fe)); + adap->active_fe = -1; + + if (d->props->frontend_attach) { + ret = d->props->frontend_attach(adap); + if (ret < 0) { + pr_debug("%s: frontend_attach() failed=%d\n", __func__, + ret); + goto err_dvb_frontend_detach; + } + } else { + pr_debug("%s: frontend_attach() do not exists\n", __func__); + ret = 0; + goto err; + } + + for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) { + adap->fe[i]->id = i; + + /* re-assign sleep and wakeup functions */ + adap->fe_init[i] = adap->fe[i]->ops.init; + adap->fe[i]->ops.init = dvb_usb_fe_wakeup; + adap->fe_sleep[i] = adap->fe[i]->ops.sleep; + adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; + + ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); + if (ret < 0) { + pr_err("%s: frontend%d registration failed\n", + KBUILD_MODNAME, i); + goto err_dvb_unregister_frontend; + } + + count_registered++; + } + + if (d->props->tuner_attach) { + ret = d->props->tuner_attach(adap); + if (ret < 0) { + pr_debug("%s: tuner_attach() failed=%d\n", __func__, + ret); + goto err_dvb_unregister_frontend; + } + } + + return 0; + +err_dvb_unregister_frontend: + for (i = count_registered - 1; i >= 0; i--) + dvb_unregister_frontend(adap->fe[i]); + +err_dvb_frontend_detach: + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { + if (adap->fe[i]) + dvb_frontend_detach(adap->fe[i]); + } + +err: + pr_debug("%s: failed=%d\n", __func__, ret); + return ret; +} + +int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) +{ + int i; + pr_debug("%s: adap=%d\n", __func__, adap->id); + + for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { + if (adap->fe[i]) { + dvb_unregister_frontend(adap->fe[i]); + dvb_frontend_detach(adap->fe[i]); + } + } + + return 0; +} + static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) { struct dvb_usb_adapter *adap; @@ -346,30 +764,6 @@ err: return ret; } -int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int ret; - - if (onoff) - d->powered++; - else - d->powered--; - - if (d->powered == 0 || (onoff && d->powered == 1)) { - /* when switching from 1 to 0 or from 0 to 1 */ - pr_debug("%s: power control=%d\n", __func__, onoff); - if (d->props->power_ctrl) { - ret = d->props->power_ctrl(d, onoff); - goto err; - } - } - - return 0; -err: - pr_debug("%s: failed=%d\n", __func__, ret); - return ret; -} - /* * udev, which is used for the firmware downloading, requires we cannot * block during module_init(). module_init() calls USB probe() which From 9f6f82ee61b23f0234fc83be363483bc4a65d99c Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 19 Jun 2012 22:31:04 -0300 Subject: [PATCH 0297/5375] [media] dvb_usb_v2: move dvb_usbv2_generic_rw() debugs behind define It is nice to have this debug, but as it generates very huge amount of traffic, better to make it conditional. Use define macro to disable it as I did not find out how to use dynamic debugs to dump variable length buffers like that. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index 75b7ac43810d..e886362ccf7e 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -8,6 +8,7 @@ */ #include "dvb_usb_common.h" +#undef DVB_USB_XFER_DEBUG int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen, int delay_ms) { @@ -26,8 +27,10 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, if (ret) return ret; +#ifdef DVB_USB_XFER_DEBUG print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": >>> ", DUMP_PREFIX_NONE, 32, 1, wbuf, wlen, 0); +#endif ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, d->props->generic_bulk_ctrl_endpoint), wbuf, wlen, @@ -53,10 +56,10 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, if (ret) pr_err("%s: recv bulk message failed: %d\n", KBUILD_MODNAME, ret); - else - print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": <<< ", - DUMP_PREFIX_NONE, 32, 1, rbuf, actlen, - 0); +#ifdef DVB_USB_XFER_DEBUG + print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": <<< ", + DUMP_PREFIX_NONE, 32, 1, rbuf, actlen, 0); +#endif } mutex_unlock(&d->usb_mutex); From 831511bdeee8b956fc9399f61fc9b25bd808429f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 20 Jun 2012 00:32:53 -0300 Subject: [PATCH 0298/5375] [media] dvb_usb_v2: multiple small tweaks around the code Naming, small code changes, debug writings, etc. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/anysee.c | 4 +- drivers/media/dvb/dvb-usb/dvb_usb.h | 111 +++++++++++------------ drivers/media/dvb/dvb-usb/dvb_usb_core.c | 91 ++++++++----------- drivers/media/dvb/dvb-usb/usb_urb.c | 36 ++++---- 4 files changed, 109 insertions(+), 133 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 2655034b86a9..9de0004c06d3 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -1264,7 +1264,7 @@ static int anysee_init(struct dvb_usb_device *d) return 0; } -static void anysee_disconnect(struct dvb_usb_device *d) +static void anysee_exit(struct dvb_usb_device *d) { return anysee_ci_release(d); } @@ -1287,7 +1287,7 @@ static struct dvb_usb_device_properties anysee_props = { .get_rc_config = anysee_get_rc_config, .frontend_ctrl = anysee_frontend_ctrl, .streaming_ctrl = anysee_streaming_ctrl, - .disconnect = anysee_disconnect, + .exit = anysee_exit, .num_adapters = 1, .adapter = { diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index a87a9ff579c4..56bf3a7f085b 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -10,10 +10,8 @@ #ifndef DVB_USB_H #define DVB_USB_H -#include -#include +#include #include -#include #include #include "dvb_frontend.h" @@ -65,15 +63,35 @@ .rc_map = (rc), \ }) +struct dvb_usb_device; +struct dvb_usb_adapter; + struct dvb_usb_driver_info { const char *name; const char *rc_map; const struct dvb_usb_device_properties *props; }; -struct dvb_usb_device; -struct dvb_usb_adapter; -struct usb_data_stream; +/** + * struct dvb_rc properties of remote controller, using rc-core + * @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. + * @bulk_mode: device supports bulk mode for RC (disable polling mode) + */ +struct dvb_usb_rc { + char *map_name; + u64 allowed_protos; + int (*change_protocol)(struct rc_dev *dev, u64 rc_type); + int (*query) (struct dvb_usb_device *d); + unsigned int interval; + const enum rc_driver_type driver_type; + bool bulk_mode; +}; /** * Properties of USB streaming - TODO this structure should be somewhere else @@ -83,13 +101,13 @@ struct usb_data_stream; struct usb_data_stream_properties { #define USB_BULK 1 #define USB_ISOC 2 - int type; - int count; - int endpoint; + u8 type; + u8 count; + u8 endpoint; union { struct { - int buffersize; /* per URB */ + unsigned int buffersize; /* per URB */ } bulk; struct { int framesperurb; @@ -124,37 +142,15 @@ struct dvb_usb_adapter_properties { #define DVB_USB_ADAP_HAS_PID_FILTER 0x01 #define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 #define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 - int caps; - int size_of_priv; + u8 caps; - int pid_filter_count; + u8 pid_filter_count; int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); struct usb_data_stream_properties stream; }; -/** - * struct dvb_rc properties of remote controller, using rc-core - * @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. - * @bulk_mode: device supports bulk mode for RC (disable polling mode) - */ -struct dvb_usb_rc { - char *map_name; - u64 allowed_protos; - int (*change_protocol)(struct rc_dev *dev, u64 rc_type); - int (*query) (struct dvb_usb_device *d); - int interval; - const enum rc_driver_type driver_type; - bool bulk_mode; -}; - /** * struct dvb_usb_device_properties - properties of a dvb-usb-device * @owner: owner of the dvb_adapter @@ -196,8 +192,11 @@ struct dvb_usb_device_properties { const char *driver_name; struct module *owner; short *adapter_nr; + u8 bInterfaceNumber; - int size_of_priv; + unsigned int size_of_priv; + u8 generic_bulk_ctrl_endpoint; + u8 generic_bulk_ctrl_endpoint_response; #define WARM 0 #define COLD 1 @@ -207,11 +206,12 @@ struct dvb_usb_device_properties { int (*download_firmware) (struct dvb_usb_device *, const struct firmware *); - int num_adapters; - int (*get_adapter_count) (struct dvb_usb_device *); - struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + struct i2c_algorithm *i2c_algo; - int (*power_ctrl) (struct dvb_usb_device *, int); + unsigned int num_adapters; + struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; + int (*get_adapter_count) (struct dvb_usb_device *); + int (*power_ctrl) (struct dvb_usb_device *, int); int (*read_config) (struct dvb_usb_device *d); int (*read_mac_address) (struct dvb_usb_adapter *, u8 []); int (*frontend_attach) (struct dvb_usb_adapter *); @@ -221,18 +221,13 @@ struct dvb_usb_device_properties { int (*fe_ioctl_override) (struct dvb_frontend *, unsigned int, void *, unsigned int); int (*init) (struct dvb_usb_device *); - void (*disconnect) (struct dvb_usb_device *); + void (*exit) (struct dvb_usb_device *); int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *); #define DVB_USB_FE_TS_TYPE_188 0 #define DVB_USB_FE_TS_TYPE_204 1 #define DVB_USB_FE_TS_TYPE_RAW 2 int (*get_stream_config) (struct dvb_frontend *, u8 *, struct usb_data_stream_properties *); - - struct i2c_algorithm *i2c_algo; - - int generic_bulk_ctrl_endpoint; - int generic_bulk_ctrl_endpoint_response; }; /** @@ -247,12 +242,12 @@ struct dvb_usb_device_properties { */ #define MAX_NO_URBS_FOR_DATA_STREAM 10 struct usb_data_stream { - struct usb_device *udev; - struct usb_data_stream_properties props; + struct usb_device *udev; + struct usb_data_stream_properties props; #define USB_STATE_INIT 0x00 #define USB_STATE_URB_BUF 0x01 - int state; + u8 state; void (*complete) (struct usb_data_stream *, u8 *, size_t); @@ -297,26 +292,23 @@ struct usb_data_stream { struct dvb_usb_adapter { const struct dvb_usb_adapter_properties *props; struct usb_data_stream stream; - u8 id; + u8 id; u8 ts_type; - int pid_filtering; - int feed_count; - int max_feed_count; - - /* sync frontend and streaming as those are different tasks */ - struct mutex sync_mutex; + bool pid_filtering; + u8 feed_count; + u8 max_feed_count; + s8 active_fe; /* dvb */ struct dvb_adapter dvb_adap; struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; + struct mutex sync_mutex; struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP]; int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); - - int active_fe; }; /** @@ -346,11 +338,12 @@ struct dvb_usb_device { const struct dvb_usb_device_properties *props; const char *name; const char *rc_map; - struct dvb_usb_rc rc; + struct usb_device *udev; + struct usb_interface *intf; + struct dvb_usb_rc rc; struct work_struct probe_work; pid_t work_pid; - struct usb_interface *intf; int powered; /* locking */ diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_core.c b/drivers/media/dvb/dvb-usb/dvb_usb_core.c index f3e1ec2c473e..42473e1dbac8 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_core.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_core.c @@ -12,22 +12,22 @@ * see Documentation/dvb/README.dvb-usb for more information */ #include "dvb_usb_common.h" -#include int dvb_usbv2_disable_rc_polling; module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644); MODULE_PARM_DESC(disable_rc_polling, - "disable remote control polling (default: 0)."); + "disable remote control polling (default: 0)"); static int dvb_usb_force_pid_filter_usage; module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); -MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a" \ - " PID filter, if any (default: 0)."); +MODULE_PARM_DESC(force_pid_filter_usage, "force all DVB USB devices to use a " \ + "PID filter, if any (default: 0)"); static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name) { int ret; const struct firmware *fw; + pr_debug("%s:\n", __func__); if (!d->props->download_firmware) { ret = -EINVAL; @@ -36,10 +36,10 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *nam ret = request_firmware(&fw, name, &d->udev->dev); if (ret < 0) { - pr_err("%s: did not find the firmware file. (%s) " \ + pr_err("%s: Did not find the firmware file '%s'. " \ "Please see linux/Documentation/dvb/ for " \ - "more details on firmware-problems. (%d)\n", - KBUILD_MODNAME, name, ret); + "more details on firmware-problems. Status " \ + "%d\n", KBUILD_MODNAME, name, ret); goto err; } @@ -47,9 +47,7 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *nam name); ret = d->props->download_firmware(d, fw); - release_firmware(fw); - if (ret < 0) goto err; @@ -62,7 +60,6 @@ err: static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) { int ret; - pr_debug("%s:\n", __func__); if (!d->props->i2c_algo) @@ -103,29 +100,27 @@ static void dvb_usb_read_remote_control(struct work_struct *work) struct dvb_usb_device, rc_query_work.work); int ret; - /* TODO: need a lock here. We can simply skip checking for the remote - control if we're busy. */ - - /* when the parameter has been set to 1 via sysfs while the - * driver was running, or when bulk mode is enabled after IR init + /* + * When the parameter has been set to 1 via sysfs while the + * driver was running, or when bulk mode is enabled after IR init. */ if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode) return; ret = d->rc.query(d); - if (ret < 0) - pr_err("%s: error %d while querying for an remote control " \ - "event\n", KBUILD_MODNAME, ret); + if (ret < 0) { + pr_err("%s: rc.query() failed=%d\n", KBUILD_MODNAME, ret); + return; /* stop polling */ + } schedule_delayed_work(&d->rc_query_work, - msecs_to_jiffies(d->rc.interval)); + msecs_to_jiffies(d->rc.interval)); } static int dvb_usbv2_remote_init(struct dvb_usb_device *d) { int ret; struct rc_dev *dev; - pr_debug("%s:\n", __func__); if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) @@ -142,7 +137,7 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) } dev->dev.parent = &d->udev->dev; - dev->input_name = "IR-receiver inside an USB DVB receiver"; + dev->input_name = d->name; usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); dev->input_phys = d->rc_phys; @@ -153,13 +148,10 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) dev->allowed_protos = d->rc.allowed_protos; dev->change_protocol = d->rc.change_protocol; dev->priv = d; - /* select used keymap */ if (d->rc.map_name) dev->map_name = d->rc.map_name; - else if (d->rc_map) - dev->map_name = d->rc_map; else - dev->map_name = RC_MAP_EMPTY; /* keep rc enabled */ + dev->map_name = d->rc_map; ret = rc_register_device(dev); if (ret < 0) { @@ -235,9 +227,8 @@ int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) { pr_debug("%s: adap=%d\n", __func__, adap->id); - usb_urb_exitv2(&adap->stream); - return 0; + return usb_urb_exitv2(&adap->stream); } static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, @@ -369,7 +360,7 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) if (ret < 0) { pr_debug("%s: dvb_register_adapter() failed=%d\n", __func__, ret); - goto err; + goto err_dvb_register_adapter; } adap->dvb_adap.priv = adap; @@ -378,7 +369,7 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) ret = d->props->read_mac_address(adap, adap->dvb_adap.proposed_mac); if (ret < 0) - goto err_dmx; + goto err_dvb_dmx_init; pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME, adap->dvb_adap.proposed_mac); @@ -387,8 +378,7 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; adap->demux.priv = adap; adap->demux.filternum = 0; - if (adap->demux.filternum < adap->max_feed_count) - adap->demux.filternum = adap->max_feed_count; + adap->demux.filternum = adap->max_feed_count; adap->demux.feednum = adap->demux.filternum; adap->demux.start_feed = dvb_usb_start_feed; adap->demux.stop_feed = dvb_usb_stop_feed; @@ -396,7 +386,7 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) ret = dvb_dmx_init(&adap->demux); if (ret < 0) { pr_err("%s: dvb_dmx_init() failed=%d\n", KBUILD_MODNAME, ret); - goto err_dmx; + goto err_dvb_dmx_init; } adap->dmxdev.filternum = adap->demux.filternum; @@ -406,25 +396,25 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) if (ret < 0) { pr_err("%s: dvb_dmxdev_init() failed=%d\n", KBUILD_MODNAME, ret); - goto err_dmx_dev; + goto err_dvb_dmxdev_init; } ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); if (ret < 0) { pr_err("%s: dvb_net_init() failed=%d\n", KBUILD_MODNAME, ret); - goto err_net_init; + goto err_dvb_net_init; } mutex_init(&adap->sync_mutex); return 0; -err_net_init: +err_dvb_net_init: dvb_dmxdev_release(&adap->dmxdev); -err_dmx_dev: +err_dvb_dmxdev_init: dvb_dmx_release(&adap->demux); -err_dmx: +err_dvb_dmx_init: dvb_unregister_adapter(&adap->dvb_adap); -err: +err_dvb_register_adapter: adap->dvb_adap.priv = NULL; return ret; } @@ -468,7 +458,7 @@ err: return ret; } -static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) +static int dvb_usb_fe_init(struct dvb_frontend *fe) { int ret; struct dvb_usb_adapter *adap = fe->dvb->priv; @@ -560,10 +550,9 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) { adap->fe[i]->id = i; - /* re-assign sleep and wakeup functions */ adap->fe_init[i] = adap->fe[i]->ops.init; - adap->fe[i]->ops.init = dvb_usb_fe_wakeup; + adap->fe[i]->ops.init = dvb_usb_fe_init; adap->fe_sleep[i] = adap->fe[i]->ops.sleep; adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; @@ -699,7 +688,6 @@ err: static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) { int i; - pr_debug("%s:\n", __func__); for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { @@ -727,7 +715,8 @@ static int dvb_usbv2_exit(struct dvb_usb_device *d) static int dvb_usbv2_init(struct dvb_usb_device *d) { - int ret = 0; + int ret; + pr_debug("%s:\n", __func__); dvb_usbv2_device_power_ctrl(d, 1); @@ -770,7 +759,6 @@ err: * is this routine. Due to that we delay actual operation using workqueue * and return always success here. */ - static void dvb_usbv2_init_work(struct work_struct *work) { int ret; @@ -778,7 +766,6 @@ static void dvb_usbv2_init_work(struct work_struct *work) container_of(work, struct dvb_usb_device, probe_work); d->work_pid = current->pid; - pr_debug("%s: work_pid=%d\n", __func__, d->work_pid); if (d->props->size_of_priv) { @@ -817,7 +804,8 @@ static void dvb_usbv2_init_work(struct work_struct *work) */ return; } else { - /* Unexpected error. We must unregister driver + /* + * Unexpected error. We must unregister driver * manually from the device, because device is * already register by returning from probe() * with success. usb_driver_release_interface() @@ -844,7 +832,6 @@ static void dvb_usbv2_init_work(struct work_struct *work) err_usb_driver_release_interface: pr_info("%s: '%s' error while loading driver (%d)\n", KBUILD_MODNAME, d->name, ret); - /* it finally calls disconnect() which frees mem */ usb_driver_release_interface(to_usb_driver(d->intf->dev.driver), d->intf); pr_debug("%s: failed=%d\n", __func__, ret); @@ -909,8 +896,7 @@ EXPORT_SYMBOL(dvb_usbv2_probe); void dvb_usbv2_disconnect(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name; - + const char *name = d->name; pr_debug("%s: pid=%d work_pid=%d\n", __func__, current->pid, d->work_pid); @@ -918,10 +904,9 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) if (d->work_pid != current->pid) cancel_work_sync(&d->probe_work); - if (d->props->disconnect) - d->props->disconnect(d); + if (d->props->exit) + d->props->exit(d); - name = d->name; dvb_usbv2_exit(d); pr_info("%s: '%s' successfully deinitialized and disconnected\n", @@ -933,7 +918,6 @@ int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) { struct dvb_usb_device *d = usb_get_intfdata(intf); int i; - pr_debug("%s:\n", __func__); /* stop remote controller poll */ @@ -955,7 +939,6 @@ int dvb_usbv2_resume(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); int i; - pr_debug("%s:\n", __func__); /* start streaming */ diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c index 32e80be2168d..d860dac2a83d 100644 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -38,7 +38,7 @@ static void usb_urb_complete(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - pr_debug("%s: URB completition failed=%d\n", __func__, + pr_debug("%s: urb completition failed=%d\n", __func__, urb->status); break; } @@ -76,7 +76,7 @@ int usb_urb_killv2(struct usb_data_stream *stream) { int i; for (i = 0; i < stream->urbs_submitted; i++) { - pr_debug("%s: kill URB=%d\n", __func__, i); + pr_debug("%s: kill urb=%d\n", __func__, i); /* stop the URB */ usb_kill_urb(stream->urb_list[i]); } @@ -96,10 +96,10 @@ int usb_urb_submitv2(struct usb_data_stream *stream, } for (i = 0; i < stream->urbs_initialized; i++) { - pr_debug("%s: submit URB=%d\n", __func__, i); + pr_debug("%s: submit urb=%d\n", __func__, i); ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); if (ret) { - pr_err("%s: could not submit URB no. %d - get them " \ + pr_err("%s: could not submit urb no. %d - get them " \ "all back\n", KBUILD_MODNAME, i); usb_urb_killv2(stream); return ret; @@ -115,9 +115,9 @@ int usb_urb_free_urbs(struct usb_data_stream *stream) usb_urb_killv2(stream); - for (i = 0; i < stream->urbs_initialized; i++) { - if (stream->urb_list[i] != NULL) { - pr_debug("%s: free URB=%d\n", __func__, i); + for (i = stream->urbs_initialized - 1; i >= 0; i--) { + if (stream->urb_list[i]) { + pr_debug("%s: free urb=%d\n", __func__, i); /* free the URBs */ usb_free_urb(stream->urb_list[i]); } @@ -133,7 +133,7 @@ static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream) /* allocate the URBs */ for (i = 0; i < stream->props.count; i++) { - pr_debug("%s: alloc URB=%d\n", __func__, i); + pr_debug("%s: alloc urb=%d\n", __func__, i); stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); if (!stream->urb_list[i]) { pr_debug("%s: failed\n", __func__); @@ -164,7 +164,7 @@ static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) for (i = 0; i < stream->props.count; i++) { struct urb *urb; int frame_offset = 0; - pr_debug("%s: alloc URB=%d\n", __func__, i); + pr_debug("%s: alloc urb=%d\n", __func__, i); stream->urb_list[i] = usb_alloc_urb( stream->props.u.isoc.framesperurb, GFP_ATOMIC); if (!stream->urb_list[i]) { @@ -229,17 +229,17 @@ int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, __func__, num * size); for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { - pr_debug("%s: alloc buf=%d\n", __func__, stream->buf_num); stream->buf_list[stream->buf_num] = usb_alloc_coherent( stream->udev, size, GFP_ATOMIC, &stream->dma_addr[stream->buf_num]); - if (stream->buf_list[stream->buf_num] == NULL) { - pr_debug("%s: failed\n", __func__); + if (!stream->buf_list[stream->buf_num]) { + pr_debug("%s: alloc buf=%d failed\n", __func__, + stream->buf_num); usb_free_stream_buffers(stream); return -ENOMEM; } - pr_debug("%s: buf %d: %p (dma %llu)\n", __func__, + pr_debug("%s: alloc buf=%d %p (dma %llu)\n", __func__, stream->buf_num, stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); @@ -255,7 +255,7 @@ int usb_urb_reconfig(struct usb_data_stream *stream, { int buf_size; - if (props == NULL) + if (!props) return 0; /* check allocated buffers are large enough for the request */ @@ -293,7 +293,7 @@ int usb_urb_reconfig(struct usb_data_stream *stream, return 0; } - pr_debug("%s: re-alloc URBs\n", __func__); + pr_debug("%s: re-alloc urbs\n", __func__); usb_urb_free_urbs(stream); memcpy(&stream->props, props, sizeof(*props)); @@ -310,7 +310,7 @@ int usb_urb_initv2(struct usb_data_stream *stream, { int ret; - if (stream == NULL || props == NULL) + if (!stream || !props) return -EINVAL; memcpy(&stream->props, props, sizeof(*props)); @@ -318,7 +318,7 @@ int usb_urb_initv2(struct usb_data_stream *stream, usb_clear_halt(stream->udev, usb_rcvbulkpipe(stream->udev, stream->props.endpoint)); - if (stream->complete == NULL) { + if (!stream->complete) { pr_err("%s: there is no data callback - this doesn't make " \ "sense\n", KBUILD_MODNAME); return -EINVAL; @@ -341,7 +341,7 @@ int usb_urb_initv2(struct usb_data_stream *stream, return usb_urb_alloc_isoc_urbs(stream); default: - pr_err("%s: unknown URB-type for data transfer\n", + pr_err("%s: unknown urb-type for data transfer\n", KBUILD_MODNAME); return -EINVAL; } From 1162c7b383a62431d5800e3697423fbcf9133ad7 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 20 Jun 2012 20:27:42 -0300 Subject: [PATCH 0299/5375] [media] dvb_usb_v2: refactor dvb_usbv2_generic_rw() Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 2 +- drivers/media/dvb/dvb-usb/af9035.c | 2 +- drivers/media/dvb/dvb-usb/anysee.c | 2 +- drivers/media/dvb/dvb-usb/dvb_usb.h | 4 +-- drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 47 +++++++++++-------------- 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 6cecd755f1d9..e48cb586f4cf 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -100,7 +100,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) rlen = 0; - ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen, 0); + ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); if (ret) goto error; diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c index b030055d14a3..82b1ac716c2f 100644 --- a/drivers/media/dvb/dvb-usb/af9035.c +++ b/drivers/media/dvb/dvb-usb/af9035.c @@ -77,7 +77,7 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) if (req->cmd == CMD_FW_DL) rlen = 0; - ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen, 0); + ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); if (ret) goto err; diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 9de0004c06d3..87c978b0373e 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -69,7 +69,7 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, /* We need receive one message more after dvb_usb_generic_rw due to weird transaction flow, which is 1 x send + 2 x receive. */ - ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); + ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf)); if (ret) goto error_unlock; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 56bf3a7f085b..d771e1c72737 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -197,6 +197,7 @@ struct dvb_usb_device_properties { unsigned int size_of_priv; u8 generic_bulk_ctrl_endpoint; u8 generic_bulk_ctrl_endpoint_response; + unsigned int generic_bulk_ctrl_delay; #define WARM 0 #define COLD 1 @@ -371,8 +372,7 @@ extern int dvb_usbv2_suspend(struct usb_interface *, pm_message_t); extern int dvb_usbv2_resume(struct usb_interface *); /* the generic read/write method for device control */ -extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16, - int); +extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16); extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16); #endif diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index e886362ccf7e..11e284b371be 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -10,55 +10,50 @@ #undef DVB_USB_XFER_DEBUG int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, - u16 rlen, int delay_ms) + u16 rlen) { - int actlen, ret = -ENOMEM; + int ret, actual_length; - if (!d || wbuf == NULL || wlen == 0) - return -EINVAL; - - if (d->props->generic_bulk_ctrl_endpoint == 0) { - pr_err("%s: endpoint for generic control not specified\n", - KBUILD_MODNAME); + if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint || + !d->props->generic_bulk_ctrl_endpoint_response) { + pr_debug("%s: failed=%d\n", __func__, -EINVAL); return -EINVAL; } ret = mutex_lock_interruptible(&d->usb_mutex); - if (ret) + if (ret < 0) return ret; #ifdef DVB_USB_XFER_DEBUG print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": >>> ", DUMP_PREFIX_NONE, 32, 1, wbuf, wlen, 0); #endif - ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, d->props->generic_bulk_ctrl_endpoint), wbuf, wlen, - &actlen, 2000); - - if (ret) - pr_err("%s: bulk message failed: %d (%d/%d)\n", KBUILD_MODNAME, - ret, wlen, actlen); + &actual_length, 2000); + if (ret < 0) + pr_err("%s: usb_bulk_msg() failed=%d\n", KBUILD_MODNAME, ret); else - ret = actlen != wlen ? -1 : 0; + ret = actual_length != wlen ? -EIO : 0; /* an answer is expected, and no error before */ if (!ret && rbuf && rlen) { - if (delay_ms) - msleep(delay_ms); + if (d->props->generic_bulk_ctrl_delay) + usleep_range(d->props->generic_bulk_ctrl_delay, + d->props->generic_bulk_ctrl_delay + + 20000); ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, - d->props->generic_bulk_ctrl_endpoint_response ? - d->props->generic_bulk_ctrl_endpoint_response : - d->props->generic_bulk_ctrl_endpoint), - rbuf, rlen, &actlen, 2000); - + d->props->generic_bulk_ctrl_endpoint_response), + rbuf, rlen, &actual_length, 2000); if (ret) - pr_err("%s: recv bulk message failed: %d\n", + pr_err("%s: 2nd usb_bulk_msg() failed=%d\n", KBUILD_MODNAME, ret); + #ifdef DVB_USB_XFER_DEBUG print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": <<< ", - DUMP_PREFIX_NONE, 32, 1, rbuf, actlen, 0); + DUMP_PREFIX_NONE, 32, 1, rbuf, actual_length, + 0); #endif } @@ -69,6 +64,6 @@ EXPORT_SYMBOL(dvb_usbv2_generic_rw); int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) { - return dvb_usbv2_generic_rw(d, buf, len, NULL, 0, 0); + return dvb_usbv2_generic_rw(d, buf, len, NULL, 0); } EXPORT_SYMBOL(dvb_usbv2_generic_write); From f93c80288730427c461d6db573411ca50683bd44 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 20 Jun 2012 22:22:14 -0300 Subject: [PATCH 0300/5375] [media] dvb_usb_v2: update header dvb_usb.h comments Comment briefly all used structures and variables. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 225 ++++++++++++++-------------- 1 file changed, 114 insertions(+), 111 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index d771e1c72737..7d7647d385a6 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -4,8 +4,6 @@ * see dvb-usb-init.c for copyright information. * * the headerfile, all dvb-usb-drivers have to include. - * - * TODO: clean-up the structures for unused fields and update the comments */ #ifndef DVB_USB_H #define DVB_USB_H @@ -20,6 +18,28 @@ #include "dmxdev.h" #include "dvb-usb-ids.h" +/* + * device file: /dev/dvb/adapter[0-1]/frontend[0-2] + * + * |-- device + * | |-- adapter0 + * | | |-- frontend0 + * | | |-- frontend1 + * | | `-- frontend2 + * | `-- adapter1 + * | |-- frontend0 + * | |-- frontend1 + * | `-- frontend2 + * + * + * Commonly used variable names: + * d = pointer to device (struct dvb_usb_device *) + * adap = pointer to adapter (struct dvb_usb_adapter *) + * fe = pointer to frontend (struct dvb_frontend *) + * + * Use macros defined in that file to resolve needed pointers. + */ + /* helper macros for every DVB USB driver use */ #define adap_to_d(adap) (container_of(adap, struct dvb_usb_device, \ adapter[adap->id])) @@ -66,6 +86,13 @@ struct dvb_usb_device; struct dvb_usb_adapter; +/** + * structure for carrying all needed data from the device driver to the general + * dvb usb routines + * @name: device name + * @rc_map: name of rc codes table + * @props: structure containing all device properties + */ struct dvb_usb_driver_info { const char *name; const char *rc_map; @@ -73,15 +100,14 @@ struct dvb_usb_driver_info { }; /** - * struct dvb_rc properties of remote controller, using rc-core - * @rc_codes: name of rc codes table - * @protocol: type of protocol(s) currently used by the driver + * structure for remote controller configuration + * @map_name: name of rc codes table * @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. - * @bulk_mode: device supports bulk mode for RC (disable polling mode) + * @query: called to query an event from the device + * @interval: time in ms between two queries + * @driver_type: used to point if a device supports raw mode + * @bulk_mode: device supports bulk mode for rc (disable polling mode) */ struct dvb_usb_rc { char *map_name; @@ -94,9 +120,10 @@ struct dvb_usb_rc { }; /** - * Properties of USB streaming - TODO this structure should be somewhere else - * describes the kind of USB transfer used for data-streaming. - * (BULK or ISOC) + * usb streaming configration for adapter + * @type: urb type + * @count: count of used urbs + * @endpoint: stream usb endpoint number */ struct usb_data_stream_properties { #define USB_BULK 1 @@ -118,25 +145,13 @@ struct usb_data_stream_properties { }; /** - * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter. - * A DVB-USB-Adapter is basically a dvb_adapter which is present on a - * USB-device. - * @caps: capabilities of the DVB USB device. - * @pid_filter_count: number of PID filter position in the optional hardware - * PID-filter. - * @num_frontends: number of frontends of the DVB USB adapter. - * @frontend_ctrl: called to power on/off active frontend. - * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the - * device (not URB submitting/killing). - * @pid_filter_ctrl: called to en/disable the PID filter, if any. - * @pid_filter: called to set/unset a PID for filtering. - * @frontend_attach: called to attach the possible frontends (fill fe-field - * of struct dvb_usb_device). - * @tuner_attach: called to attach the correct tuner and to fill pll_addr, - * pll_desc and pll_init_buf of struct dvb_usb_device). - * @stream: configuration of the USB streaming + * properties of dvb usb device adapter + * @caps: adapter capabilities + * @pid_filter_count: pid count of adapter pid-filter + * @pid_filter_ctrl: called to enable/disable pid-filter + * @pid_filter: called to set/unset pid for filtering + * @stream: adapter usb stream configuration */ - #define MAX_NO_OF_FE_PER_ADAP 3 struct dvb_usb_adapter_properties { #define DVB_USB_ADAP_HAS_PID_FILTER 0x01 @@ -153,39 +168,38 @@ struct dvb_usb_adapter_properties { /** * struct dvb_usb_device_properties - properties of a dvb-usb-device + * @driver_name: name of the owning driver module * @owner: owner of the dvb_adapter - * @usb_ctrl: which USB device-side controller is in use. Needed for firmware - * download. - * @firmware: name of the firmware file. - * @download_firmware: called to download the firmware when the usb_ctrl is - * DEVICE_SPECIFIC. - * @no_reconnect: device doesn't do a reconnect after downloading the firmware, - * so do the warm initialization right after it - * - * @size_of_priv: how many bytes shall be allocated for the private field - * of struct dvb_usb_device. - * - * @power_ctrl: called to enable/disable power of the device. - * @read_mac_address: called to read the MAC address of the device. - * @identify_state: called to determine the state (cold or warm), when it - * is not distinguishable by the USB IDs. + * @adapter_nr: values from the DVB_DEFINE_MOD_OPT_ADAPTER_NR() macro + * @bInterfaceNumber: usb interface number driver binds + * @size_of_priv: bytes allocated for the driver private data + * @generic_bulk_ctrl_endpoint: bulk control endpoint number for sent + * @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for + * receive + * @generic_bulk_ctrl_delay: delay between bulk control sent and receive message + * @identify_state: called to determine the firmware state (cold or warm) and + * return possible firmware file name to be loaded + * @firmware: name of the firmware file to be loaded + * @download_firmware: called to download the firmware + * @i2c_algo: i2c_algorithm if the device has i2c-adapter + * @num_adapters: dvb usb device adapter count + * @get_adapter_count: called to resolve adapter count + * @adapter: array of all adapter properties of device + * @power_ctrl: called to enable/disable power of the device + * @read_config: called to resolve device configuration + * @read_mac_address: called to resolve adapter mac-address + * @frontend_attach: called to attach the possible frontends + * @tuner_attach: called to attach the possible tuners + * @frontend_ctrl: called to power on/off active frontend + * @streaming_ctrl: called to start/stop the usb streaming of adapter + * @fe_ioctl_override: frontend ioctl override. avoid using that is possible * @init: called after adapters are created in order to finalize device - * configuration. - * - * @rc: remote controller properties - * - * @i2c_algo: i2c_algorithm if the device has I2CoverUSB. - * - * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic - * endpoint which received control messages with bulk transfers. When this - * is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write- - * helper functions. - * - * @generic_bulk_ctrl_endpoint_response: some DVB USB devices use a separate - * endpoint for responses to control messages sent with bulk transfers via - * the generic_bulk_ctrl_endpoint. When this is non-zero, this will be used - * instead of the generic_bulk_ctrl_endpoint when reading usb responses in - * the dvb_usb_generic_rw helper function. + * configuration + * @exit: called when driver is unloaded + * @get_rc_config: called to resolve used remote controller configuration + * @get_stream_config: called to resolve input and output stream configuration + * of the adapter just before streaming is started. input stream is transport + * stream from the demodulator and output stream is usb stream to host. */ #define MAX_NO_OF_ADAPTER_PER_DEVICE 2 struct dvb_usb_device_properties { @@ -210,8 +224,8 @@ struct dvb_usb_device_properties { struct i2c_algorithm *i2c_algo; unsigned int num_adapters; - struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; int (*get_adapter_count) (struct dvb_usb_device *); + struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; int (*power_ctrl) (struct dvb_usb_device *, int); int (*read_config) (struct dvb_usb_device *d); int (*read_mac_address) (struct dvb_usb_adapter *, u8 []); @@ -232,14 +246,14 @@ struct dvb_usb_device_properties { }; /** - * struct usb_data_stream - generic object of an USB stream - * @buf_num: number of buffer allocated. - * @buf_size: size of each buffer in buf_list. - * @buf_list: array containing all allocate buffers for streaming. - * @dma_addr: list of dma_addr_t for each buffer in buf_list. + * generic object of an usb stream + * @buf_num: number of buffer allocated + * @buf_size: size of each buffer in buf_list + * @buf_list: array containing all allocate buffers for streaming + * @dma_addr: list of dma_addr_t for each buffer in buf_list * - * @urbs_initialized: number of URBs initialized. - * @urbs_submitted: number of URBs submitted. + * @urbs_initialized: number of URBs initialized + * @urbs_submitted: number of URBs submitted */ #define MAX_NO_URBS_FOR_DATA_STREAM 10 struct usb_data_stream { @@ -265,30 +279,22 @@ struct usb_data_stream { }; /** - * struct dvb_usb_adapter - a DVB adapter on a USB device - * @id: index of this adapter (starting with 0). - * - * @feedcount: number of reqested feeds (used for streaming-activation) - * @pid_filtering: is hardware pid_filtering used or not. - * - * @pll_addr: I2C address of the tuner for programming - * @pll_init: array containing the initialization buffer - * @pll_desc: pointer to the appropriate struct dvb_pll_desc - * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or - * the board - * - * @dvb_adap: device's dvb_adapter. - * @dmxdev: device's dmxdev. - * @demux: device's software demuxer. - * @dvb_net: device's dvb_net interfaces. - * @dvb_frontend: device's frontend. - * @max_feed_count: how many feeds can be handled simultaneously by this - * device - * - * @fe_init: rerouted frontend-init (wakeup) function. - * @fe_sleep: rerouted frontend-sleep function. - * - * @stream: the usb data stream. + * dvb adapter object on dvb usb device + * @props: pointer to adapter properties + * @stream: adapter the usb data stream + * @id: index of this adapter (starting with 0) + * @ts_type: transport stream, input stream, type + * @pid_filtering: is hardware pid_filtering used or not + * @feed_count: current feed count + * @max_feed_count: maimum feed count device can handle + * @dvb_adap: adapter dvb_adapter + * @dmxdev: adapter dmxdev + * @demux: adapter software demuxer + * @dvb_net: adapter dvb_net interfaces + * @sync_mutex: mutex used to sync control and streaming of the adapter + * @fe: adapter frontends + * @fe_init: rerouted frontend-init function + * @fe_sleep: rerouted frontend-sleep function */ struct dvb_usb_adapter { const struct dvb_usb_adapter_properties *props; @@ -313,26 +319,23 @@ struct dvb_usb_adapter { }; /** - * struct dvb_usb_device - object of a DVB USB device - * @props: copy of the struct dvb_usb_properties this device belongs to. - * @desc: pointer to the device's struct dvb_usb_device_description. - * @state: initialization and runtime state of the device. + * dvb usb device object + * @props: device properties + * @name: device name + * @rc_map: name of rc codes table + * @udev: pointer to the device's struct usb_device + * @intf: pointer to the device's usb interface + * @rc: remote controller configuration + * @probe_work: work to defer .probe() + * @powered: indicated whether the device is power or not + * @usb_mutex: mutex for usb control messages + * @i2c_mutex: mutex for i2c-transfers + * @i2c_adap: device's i2c-adapter * - * @powered: indicated whether the device is power or not. - * Powered is in/decremented for each call to modify the state. - * @udev: pointer to the device's struct usb_device. - * - * @usb_mutex: semaphore of USB control messages (reading needs two messages) - * @i2c_mutex: semaphore for i2c-transfers - * - * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB - * - * @rc_dev: rc device for the remote control (rc-core mode) + * @rc_dev: rc device for the remote control * @input_dev: input device for the remote control (legacy mode) - * @rc_query_work: struct work_struct frequent rc queries - * @last_event: last triggered event - * @last_state: last state (no, pressed, repeat) - * @priv: private data of the actual driver (allocate by dvb-usb, size defined + * @rc_query_work: work for polling remote + * @priv: private data of the actual driver (allocate by dvb usb, size defined * in size_of_priv of dvb_usb_properties). */ struct dvb_usb_device { From edc7d4483473d71833fd4851ca0dbf8680b43ae1 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 20 Jun 2012 22:47:15 -0300 Subject: [PATCH 0301/5375] [media] dvb_usb_v2: remove unused variable It was left from the legacy remote controller we do not support. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 3 --- drivers/media/dvb/dvb-usb/dvb_usb_core.c | 1 - 2 files changed, 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 7d7647d385a6..bf5adb23418f 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -331,9 +331,7 @@ struct dvb_usb_adapter { * @usb_mutex: mutex for usb control messages * @i2c_mutex: mutex for i2c-transfers * @i2c_adap: device's i2c-adapter - * * @rc_dev: rc device for the remote control - * @input_dev: input device for the remote control (legacy mode) * @rc_query_work: work for polling remote * @priv: private data of the actual driver (allocate by dvb usb, size defined * in size_of_priv of dvb_usb_properties). @@ -361,7 +359,6 @@ struct dvb_usb_device { /* remote control */ struct rc_dev *rc_dev; - struct input_dev *input_dev; char rc_phys[64]; struct delayed_work rc_query_work; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_core.c b/drivers/media/dvb/dvb-usb/dvb_usb_core.c index 42473e1dbac8..b001dcdca693 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_core.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_core.c @@ -159,7 +159,6 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) goto err; } - d->input_dev = NULL; d->rc_dev = dev; /* start polling if needed */ From 12042b0593104ba0c0c8030b89c837e9262dc906 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 20 Jun 2012 23:09:41 -0300 Subject: [PATCH 0302/5375] [media] dvb_usb_v2: update copyrights Signed-off-by: Antti Palosaari Cc: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb.h | 22 ++++++++++++++---- drivers/media/dvb/dvb-usb/dvb_usb_common.h | 23 ++++++++++++++---- drivers/media/dvb/dvb-usb/dvb_usb_core.c | 27 ++++++++++++++-------- drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 23 ++++++++++++++---- 4 files changed, 72 insertions(+), 23 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index bf5adb23418f..036174c04929 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -1,10 +1,24 @@ -/* dvb-usb.h is part of the DVB USB library. +/* + * DVB USB framework * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari * - * the headerfile, all dvb-usb-drivers have to include. + * 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. */ + #ifndef DVB_USB_H #define DVB_USB_H diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb/dvb_usb_common.h index 80c8bd3079c5..45f07090d431 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_common.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb_common.h @@ -1,11 +1,24 @@ -/* dvb-usb-common.h is part of the DVB USB library. +/* + * DVB USB framework * - * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari * - * a header file containing prototypes and types for internal use of the - * dvb-usb-lib + * 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. */ + #ifndef DVB_USB_COMMON_H #define DVB_USB_COMMON_H diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_core.c b/drivers/media/dvb/dvb-usb/dvb_usb_core.c index b001dcdca693..81ee3fc09a48 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_core.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_core.c @@ -1,16 +1,24 @@ /* - * DVB USB library - provides a generic interface for a DVB USB device driver. + * DVB USB framework * - * dvb-usb-init.c + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.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 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. + * 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. * - * see Documentation/dvb/README.dvb-usb for more information + * 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 "dvb_usb_common.h" int dvb_usbv2_disable_rc_polling; @@ -956,7 +964,8 @@ int dvb_usbv2_resume(struct usb_interface *intf) } EXPORT_SYMBOL(dvb_usbv2_resume); -MODULE_VERSION("1.0"); +MODULE_VERSION("2.0"); MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices"); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("DVB USB common"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index 11e284b371be..985b517adb24 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -1,11 +1,24 @@ -/* dvb-usb-urb.c is part of the DVB USB library. +/* + * DVB USB framework * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. + * Copyright (C) 2004-6 Patrick Boettcher + * Copyright (C) 2012 Antti Palosaari * - * This file keeps functions for initializing and handling the - * USB and URB stuff. + * 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 "dvb_usb_common.h" #undef DVB_USB_XFER_DEBUG From 18cfe03d320b3b36e60145c5896afd5d911f63b2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 21 Jun 2012 02:57:34 -0300 Subject: [PATCH 0303/5375] [media] dvb_usb_v2: fix power_ctrl() callback error handling Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_core.c b/drivers/media/dvb/dvb-usb/dvb_usb_core.c index 81ee3fc09a48..93ce02a91189 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_core.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_core.c @@ -455,7 +455,8 @@ int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) pr_debug("%s: power control=%d\n", __func__, onoff); if (d->props->power_ctrl) { ret = d->props->power_ctrl(d, onoff); - goto err; + if (ret < 0) + goto err; } } From a13a6e1f9db8361cd018560f2664e3d341323a31 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Jun 2012 00:04:33 -0300 Subject: [PATCH 0304/5375] [media] dvb_usb_v2: change streaming control callback parameter Pass frontend instead of adapter as some drivers need to make decisions based frontend. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/anysee.c | 4 ++-- drivers/media/dvb/dvb-usb/dvb_usb.h | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_core.c | 6 ++++-- drivers/media/dvb/dvb-usb/ec168.c | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 87c978b0373e..fb3829a73d2d 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -187,11 +187,11 @@ static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id) return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3); } -static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +static int anysee_streaming_ctrl(struct dvb_frontend *fe, int onoff) { u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00}; deb_info("%s: onoff:%02x\n", __func__, onoff); - return anysee_ctrl_msg(adap_to_d(adap), buf, sizeof(buf), NULL, 0); + return anysee_ctrl_msg(fe_to_d(fe), buf, sizeof(buf), NULL, 0); } static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 036174c04929..6fcab07ecada 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -246,7 +246,7 @@ struct dvb_usb_device_properties { int (*frontend_attach) (struct dvb_usb_adapter *); int (*tuner_attach) (struct dvb_usb_adapter *); int (*frontend_ctrl) (struct dvb_frontend *, int); - int (*streaming_ctrl) (struct dvb_usb_adapter *, int); + int (*streaming_ctrl) (struct dvb_frontend *, int); int (*fe_ioctl_override) (struct dvb_frontend *, unsigned int, void *, unsigned int); int (*init) (struct dvb_usb_device *); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_core.c b/drivers/media/dvb/dvb-usb/dvb_usb_core.c index 93ce02a91189..07a0ac7e956c 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_core.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_core.c @@ -262,7 +262,8 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, usb_urb_killv2(&adap->stream); if (d->props->streaming_ctrl) { - ret = d->props->streaming_ctrl(adap, 0); + ret = d->props->streaming_ctrl( + adap->fe[adap->active_fe], 0); if (ret < 0) { pr_err("%s: streaming_ctrl() failed=%d\n", KBUILD_MODNAME, ret); @@ -330,7 +331,8 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, } if (d->props->streaming_ctrl) { - ret = d->props->streaming_ctrl(adap, 1); + ret = d->props->streaming_ctrl( + adap->fe[adap->active_fe], 1); if (ret < 0) { pr_err("%s: streaming_ctrl() failed=%d\n", KBUILD_MODNAME, ret); diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c index 1fb84728a27d..ab77622c383d 100644 --- a/drivers/media/dvb/dvb-usb/ec168.c +++ b/drivers/media/dvb/dvb-usb/ec168.c @@ -303,13 +303,13 @@ static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; } -static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff) { struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL}; pr_debug("%s: onoff=%d\n", __func__, onoff); if (onoff) req.index = 0x0102; - return ec168_ctrl_msg(adap_to_d(adap), &req); + return ec168_ctrl_msg(fe_to_d(fe), &req); } /* DVB USB Driver stuff */ From d10d1b9ac97b96dd9183944d30b1664bdbb5fbf6 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Jun 2012 22:44:00 -0300 Subject: [PATCH 0305/5375] [media] dvb_usb_v2: use dev_* logging macros Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_core.c | 215 +++++++++++++---------- drivers/media/dvb/dvb-usb/dvb_usb_urb.c | 9 +- drivers/media/dvb/dvb-usb/usb_urb.c | 72 ++++---- 3 files changed, 161 insertions(+), 135 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_core.c b/drivers/media/dvb/dvb-usb/dvb_usb_core.c index 07a0ac7e956c..920542c0b672 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_core.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_core.c @@ -35,7 +35,7 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *nam { int ret; const struct firmware *fw; - pr_debug("%s:\n", __func__); + dev_dbg(&d->udev->dev, "%s:\n", __func__); if (!d->props->download_firmware) { ret = -EINVAL; @@ -44,15 +44,15 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *nam ret = request_firmware(&fw, name, &d->udev->dev); if (ret < 0) { - pr_err("%s: Did not find the firmware file '%s'. " \ - "Please see linux/Documentation/dvb/ for " \ - "more details on firmware-problems. Status " \ - "%d\n", KBUILD_MODNAME, name, ret); + dev_err(&d->udev->dev, "%s: Did not find the firmware file "\ + "'%s'. Please see linux/Documentation/dvb/ " \ + "for more details on firmware-problems. " \ + "Status %d\n", KBUILD_MODNAME, name, ret); goto err; } - pr_info("%s: downloading firmware from file '%s'\n", KBUILD_MODNAME, - name); + dev_info(&d->udev->dev, "%s: downloading firmware from file '%s'\n", + KBUILD_MODNAME, name); ret = d->props->download_firmware(d, fw); release_firmware(fw); @@ -61,14 +61,14 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *nam return ret; err: - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) { int ret; - pr_debug("%s:\n", __func__); + dev_dbg(&d->udev->dev, "%s:\n", __func__); if (!d->props->i2c_algo) return 0; @@ -81,20 +81,20 @@ static int dvb_usbv2_i2c_init(struct dvb_usb_device *d) ret = i2c_add_adapter(&d->i2c_adap); if (ret < 0) { d->i2c_adap.algo = NULL; - pr_err("%s: i2c_add_adapter() failed=%d\n", KBUILD_MODNAME, - ret); + dev_err(&d->udev->dev, "%s: i2c_add_adapter() failed=%d\n", + KBUILD_MODNAME, ret); goto err; } return 0; err: - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d) { - pr_debug("%s:\n", __func__); + dev_dbg(&d->udev->dev, "%s:\n", __func__); if (d->i2c_adap.algo) i2c_del_adapter(&d->i2c_adap); @@ -117,7 +117,8 @@ static void dvb_usb_read_remote_control(struct work_struct *work) ret = d->rc.query(d); if (ret < 0) { - pr_err("%s: rc.query() failed=%d\n", KBUILD_MODNAME, ret); + dev_err(&d->udev->dev, "%s: rc.query() failed=%d\n", + KBUILD_MODNAME, ret); return; /* stop polling */ } @@ -129,7 +130,7 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) { int ret; struct rc_dev *dev; - pr_debug("%s:\n", __func__); + dev_dbg(&d->udev->dev, "%s:\n", __func__); if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) return 0; @@ -174,21 +175,22 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) /* initialize a work queue for handling polling */ INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); - pr_info("%s: schedule remote query interval to %d msecs\n", - KBUILD_MODNAME, d->rc.interval); + dev_info(&d->udev->dev, "%s: schedule remote query interval " \ + "to %d msecs\n", KBUILD_MODNAME, + d->rc.interval); schedule_delayed_work(&d->rc_query_work, msecs_to_jiffies(d->rc.interval)); } return 0; err: - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int dvb_usbv2_remote_exit(struct dvb_usb_device *d) { - pr_debug("%s:\n", __func__); + dev_dbg(&d->udev->dev, "%s:\n", __func__); if (d->rc_dev) { cancel_delayed_work_sync(&d->rc_query_work); @@ -222,7 +224,8 @@ static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf, int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) { - pr_debug("%s: adap=%d\n", __func__, adap->id); + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); adap->stream.udev = adap_to_d(adap)->udev; adap->stream.user_priv = adap; @@ -233,7 +236,8 @@ int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) { - pr_debug("%s: adap=%d\n", __func__, adap->id); + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); return usb_urb_exitv2(&adap->stream); } @@ -244,9 +248,9 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; struct dvb_usb_device *d = adap_to_d(adap); int ret; - pr_debug("%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: " \ - "%04x (%04d) at index %d '%s'\n", __func__, adap->id, - adap->active_fe, dvbdmxfeed->type, + dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d " \ + "setting pid [%s]: %04x (%04d) at index %d '%s'\n", + __func__, adap->id, adap->active_fe, dvbdmxfeed->type, adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid, dvbdmxfeed->index, (count == 1) ? "on" : "off"); @@ -258,15 +262,16 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, /* stop feeding if it is last pid */ if (adap->feed_count == 0) { - pr_debug("%s: stop feeding\n", __func__); + dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__); usb_urb_killv2(&adap->stream); if (d->props->streaming_ctrl) { ret = d->props->streaming_ctrl( adap->fe[adap->active_fe], 0); if (ret < 0) { - pr_err("%s: streaming_ctrl() failed=%d\n", - KBUILD_MODNAME, ret); + dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ + "failed=%d\n", KBUILD_MODNAME, + ret); goto err_mutex_unlock; } } @@ -280,14 +285,15 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, ret = adap->props->pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, (count == 1) ? 1 : 0); if (ret < 0) - pr_err("%s: pid_filter() failed=%d\n", - KBUILD_MODNAME, ret); + dev_err(&d->udev->dev, "%s: pid_filter() " \ + "failed=%d\n", KBUILD_MODNAME, + ret); /* start feeding if it is first pid */ if (adap->feed_count == 1 && count == 1) { struct usb_data_stream_properties stream_props; mutex_lock(&adap->sync_mutex); - pr_debug("%s: start feeding\n", __func__); + dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__); /* resolve input and output streaming paramters */ if (d->props->get_stream_config) { @@ -324,7 +330,8 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, ret = adap->props->pid_filter_ctrl(adap, adap->pid_filtering); if (ret < 0) { - pr_err("%s: pid_filter_ctrl() failed=%d\n", + dev_err(&d->udev->dev, "%s: " \ + "pid_filter_ctrl() failed=%d\n", KBUILD_MODNAME, ret); goto err_mutex_unlock; } @@ -334,8 +341,9 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, ret = d->props->streaming_ctrl( adap->fe[adap->active_fe], 1); if (ret < 0) { - pr_err("%s: streaming_ctrl() failed=%d\n", - KBUILD_MODNAME, ret); + dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ + "failed=%d\n", KBUILD_MODNAME, + ret); goto err_mutex_unlock; } } @@ -344,7 +352,7 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, return 0; err_mutex_unlock: mutex_unlock(&adap->sync_mutex); - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -362,13 +370,13 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) { int ret; struct dvb_usb_device *d = adap_to_d(adap); - pr_debug("%s: adap=%d\n", __func__, adap->id); + dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner, &d->udev->dev, d->props->adapter_nr); if (ret < 0) { - pr_debug("%s: dvb_register_adapter() failed=%d\n", __func__, - ret); + dev_dbg(&d->udev->dev, "%s: dvb_register_adapter() failed=%d\n", + __func__, ret); goto err_dvb_register_adapter; } @@ -380,8 +388,8 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) if (ret < 0) goto err_dvb_dmx_init; - pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME, - adap->dvb_adap.proposed_mac); + dev_info(&d->udev->dev, "%s: MAC address: %pM\n", + KBUILD_MODNAME, adap->dvb_adap.proposed_mac); } adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; @@ -394,7 +402,8 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->demux.write_to_decoder = NULL; ret = dvb_dmx_init(&adap->demux); if (ret < 0) { - pr_err("%s: dvb_dmx_init() failed=%d\n", KBUILD_MODNAME, ret); + dev_err(&d->udev->dev, "%s: dvb_dmx_init() failed=%d\n", + KBUILD_MODNAME, ret); goto err_dvb_dmx_init; } @@ -403,14 +412,15 @@ int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->dmxdev.capabilities = 0; ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); if (ret < 0) { - pr_err("%s: dvb_dmxdev_init() failed=%d\n", KBUILD_MODNAME, - ret); + dev_err(&d->udev->dev, "%s: dvb_dmxdev_init() failed=%d\n", + KBUILD_MODNAME, ret); goto err_dvb_dmxdev_init; } ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); if (ret < 0) { - pr_err("%s: dvb_net_init() failed=%d\n", KBUILD_MODNAME, ret); + dev_err(&d->udev->dev, "%s: dvb_net_init() failed=%d\n", + KBUILD_MODNAME, ret); goto err_dvb_net_init; } @@ -430,7 +440,8 @@ err_dvb_register_adapter: int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) { - pr_debug("%s: adap=%d\n", __func__, adap->id); + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); if (adap->dvb_adap.priv) { dvb_net_release(&adap->dvb_net); @@ -454,7 +465,7 @@ int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */ - pr_debug("%s: power control=%d\n", __func__, onoff); + dev_dbg(&d->udev->dev, "%s: power=%d\n", __func__, onoff); if (d->props->power_ctrl) { ret = d->props->power_ctrl(d, onoff); if (ret < 0) @@ -464,7 +475,7 @@ int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; err: - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -474,7 +485,8 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe) struct dvb_usb_adapter *adap = fe->dvb->priv; struct dvb_usb_device *d = adap_to_d(adap); mutex_lock(&adap->sync_mutex); - pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); + dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, + fe->id); ret = dvb_usbv2_device_power_ctrl(d, 1); if (ret < 0) @@ -498,7 +510,7 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe) return 0; err: mutex_unlock(&adap->sync_mutex); - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -508,7 +520,8 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) struct dvb_usb_adapter *adap = fe->dvb->priv; struct dvb_usb_device *d = adap_to_d(adap); mutex_lock(&adap->sync_mutex); - pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); + dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, + fe->id); if (adap->fe_sleep[fe->id]) { ret = adap->fe_sleep[fe->id](fe); @@ -532,7 +545,7 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) return 0; err: mutex_unlock(&adap->sync_mutex); - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -540,7 +553,7 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) { int ret, i, count_registered = 0; struct dvb_usb_device *d = adap_to_d(adap); - pr_debug("%s: adap=%d\n", __func__, adap->id); + dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); memset(adap->fe, 0, sizeof(adap->fe)); adap->active_fe = -1; @@ -548,12 +561,13 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) if (d->props->frontend_attach) { ret = d->props->frontend_attach(adap); if (ret < 0) { - pr_debug("%s: frontend_attach() failed=%d\n", __func__, - ret); + dev_dbg(&d->udev->dev, "%s: frontend_attach() " \ + "failed=%d\n", __func__, ret); goto err_dvb_frontend_detach; } } else { - pr_debug("%s: frontend_attach() do not exists\n", __func__); + dev_dbg(&d->udev->dev, "%s: frontend_attach() do not exists\n", + __func__); ret = 0; goto err; } @@ -568,8 +582,8 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); if (ret < 0) { - pr_err("%s: frontend%d registration failed\n", - KBUILD_MODNAME, i); + dev_err(&d->udev->dev, "%s: frontend%d registration " \ + "failed\n", KBUILD_MODNAME, i); goto err_dvb_unregister_frontend; } @@ -579,8 +593,8 @@ int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) if (d->props->tuner_attach) { ret = d->props->tuner_attach(adap); if (ret < 0) { - pr_debug("%s: tuner_attach() failed=%d\n", __func__, - ret); + dev_dbg(&d->udev->dev, "%s: tuner_attach() failed=%d\n", + __func__, ret); goto err_dvb_unregister_frontend; } } @@ -598,14 +612,15 @@ err_dvb_frontend_detach: } err: - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) { int i; - pr_debug("%s: adap=%d\n", __func__, adap->id); + dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, + adap->id); for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) { if (adap->fe[i]) { @@ -640,32 +655,33 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) /* speed - when running at FULL speed we need a HW PID filter */ if (d->udev->speed == USB_SPEED_FULL && !(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { - pr_err("%s: this USB2.0 device cannot be run on a " \ - "USB1.1 port (it lacks a hardware " \ - "PID filter)\n", KBUILD_MODNAME); + dev_err(&d->udev->dev, "%s: this USB2.0 device " \ + "cannot be run on a USB1.1 port (it " \ + "lacks a hardware PID filter)\n", + KBUILD_MODNAME); ret = -ENODEV; goto err; } else if ((d->udev->speed == USB_SPEED_FULL && adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || (adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { - pr_info("%s: will use the device's hardware PID " \ - "filter (table count: %d)\n", - KBUILD_MODNAME, + dev_info(&d->udev->dev, "%s: will use the device's " \ + "hardware PID filter " \ + "(table count: %d)\n", KBUILD_MODNAME, adap->props->pid_filter_count); adap->pid_filtering = 1; adap->max_feed_count = adap->props->pid_filter_count; } else { - pr_info("%s: will pass the complete MPEG2 transport " \ - "stream to the software demuxer\n", - KBUILD_MODNAME); + dev_info(&d->udev->dev, "%s: will pass the complete " \ + "MPEG2 transport stream to the " \ + "software demuxer\n", KBUILD_MODNAME); adap->pid_filtering = 0; adap->max_feed_count = 255; } if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { - pr_info("%s: pid filter enabled by module option\n", - KBUILD_MODNAME); + dev_info(&d->udev->dev, "%s: PID filter enabled by " \ + "module option\n", KBUILD_MODNAME); adap->pid_filtering = 1; adap->max_feed_count = adap->props->pid_filter_count; } @@ -691,14 +707,14 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) return 0; err: - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) { int i; - pr_debug("%s:\n", __func__); + dev_dbg(&d->udev->dev, "%s:\n", __func__); for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); @@ -712,7 +728,7 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) /* general initialization functions */ static int dvb_usbv2_exit(struct dvb_usb_device *d) { - pr_debug("%s:\n", __func__); + dev_dbg(&d->udev->dev, "%s:\n", __func__); dvb_usbv2_remote_exit(d); dvb_usbv2_adapter_exit(d); @@ -726,7 +742,7 @@ static int dvb_usbv2_exit(struct dvb_usb_device *d) static int dvb_usbv2_init(struct dvb_usb_device *d) { int ret; - pr_debug("%s:\n", __func__); + dev_dbg(&d->udev->dev, "%s:\n", __func__); dvb_usbv2_device_power_ctrl(d, 1); @@ -759,7 +775,7 @@ static int dvb_usbv2_init(struct dvb_usb_device *d) return 0; err: dvb_usbv2_device_power_ctrl(d, 0); - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -776,12 +792,13 @@ static void dvb_usbv2_init_work(struct work_struct *work) container_of(work, struct dvb_usb_device, probe_work); d->work_pid = current->pid; - pr_debug("%s: work_pid=%d\n", __func__, d->work_pid); + dev_dbg(&d->udev->dev, "%s: work_pid=%d\n", __func__, d->work_pid); if (d->props->size_of_priv) { d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL); if (!d->priv) { - pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME); + dev_err(&d->udev->dev, "%s: kzalloc() failed\n", + KBUILD_MODNAME); ret = -ENOMEM; goto err_usb_driver_release_interface; } @@ -793,8 +810,8 @@ static void dvb_usbv2_init_work(struct work_struct *work) if (ret == 0) { ; } else if (ret == COLD) { - pr_info("%s: found a '%s' in cold state\n", - KBUILD_MODNAME, d->name); + dev_info(&d->udev->dev, "%s: found a '%s' in cold " \ + "state\n", KBUILD_MODNAME, d->name); if (!name) name = d->props->firmware; @@ -829,22 +846,23 @@ static void dvb_usbv2_init_work(struct work_struct *work) } } - pr_info("%s: found a '%s' in warm state\n", KBUILD_MODNAME, d->name); + dev_info(&d->udev->dev, "%s: found a '%s' in warm state\n", + KBUILD_MODNAME, d->name); ret = dvb_usbv2_init(d); if (ret < 0) goto err_usb_driver_release_interface; - pr_info("%s: '%s' successfully initialized and connected\n", - KBUILD_MODNAME, d->name); + dev_info(&d->udev->dev, "%s: '%s' successfully initialized and " \ + "connected\n", KBUILD_MODNAME, d->name); return; err_usb_driver_release_interface: - pr_info("%s: '%s' error while loading driver (%d)\n", KBUILD_MODNAME, - d->name, ret); + dev_info(&d->udev->dev, "%s: '%s' error while loading driver (%d)\n", + KBUILD_MODNAME, d->name, ret); usb_driver_release_interface(to_usb_driver(d->intf->dev.driver), d->intf); - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return; } @@ -853,28 +871,29 @@ int dvb_usbv2_probe(struct usb_interface *intf, { int ret; struct dvb_usb_device *d; + struct usb_device *udev = interface_to_usbdev(intf); struct dvb_usb_driver_info *driver_info = (struct dvb_usb_driver_info *) id->driver_info; - pr_debug("%s: bInterfaceNumber=%d\n", __func__, + dev_dbg(&udev->dev, "%s: bInterfaceNumber=%d\n", __func__, intf->cur_altsetting->desc.bInterfaceNumber); if (!id->driver_info) { - pr_err("%s: driver_info failed\n", KBUILD_MODNAME); + dev_err(&udev->dev, "%s: driver_info failed\n", KBUILD_MODNAME); ret = -ENODEV; goto err; } d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); if (!d) { - pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME); + dev_err(&udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); ret = -ENOMEM; goto err; } d->name = driver_info->name; d->rc_map = driver_info->rc_map; - d->udev = interface_to_usbdev(intf); + d->udev = udev; d->intf = intf; d->props = driver_info->props; @@ -890,7 +909,8 @@ int dvb_usbv2_probe(struct usb_interface *intf, usb_set_intfdata(intf, d); ret = schedule_work(&d->probe_work); if (ret < 0) { - pr_err("%s: schedule_work() failed\n", KBUILD_MODNAME); + dev_err(&d->udev->dev, "%s: schedule_work() failed\n", + KBUILD_MODNAME); goto err_kfree; } @@ -898,7 +918,7 @@ int dvb_usbv2_probe(struct usb_interface *intf, err_kfree: kfree(d); err: - pr_debug("%s: failed=%d\n", __func__, ret); + dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } EXPORT_SYMBOL(dvb_usbv2_probe); @@ -907,8 +927,9 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); const char *name = d->name; - pr_debug("%s: pid=%d work_pid=%d\n", __func__, current->pid, - d->work_pid); + struct device dev = d->udev->dev; + dev_dbg(&d->udev->dev, "%s: pid=%d work_pid=%d\n", __func__, + current->pid, d->work_pid); /* ensure initialization work is finished until release resources */ if (d->work_pid != current->pid) @@ -919,7 +940,7 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) dvb_usbv2_exit(d); - pr_info("%s: '%s' successfully deinitialized and disconnected\n", + dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n", KBUILD_MODNAME, name); } EXPORT_SYMBOL(dvb_usbv2_disconnect); @@ -928,7 +949,7 @@ int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg) { struct dvb_usb_device *d = usb_get_intfdata(intf); int i; - pr_debug("%s:\n", __func__); + dev_dbg(&d->udev->dev, "%s:\n", __func__); /* stop remote controller poll */ if (d->rc.query && !d->rc.bulk_mode) @@ -949,7 +970,7 @@ int dvb_usbv2_resume(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); int i; - pr_debug("%s:\n", __func__); + dev_dbg(&d->udev->dev, "%s:\n", __func__); /* start streaming */ for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) { diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c index 985b517adb24..5f5bdd0c4c9d 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_urb.c @@ -29,7 +29,7 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint || !d->props->generic_bulk_ctrl_endpoint_response) { - pr_debug("%s: failed=%d\n", __func__, -EINVAL); + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL); return -EINVAL; } @@ -45,7 +45,8 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, d->props->generic_bulk_ctrl_endpoint), wbuf, wlen, &actual_length, 2000); if (ret < 0) - pr_err("%s: usb_bulk_msg() failed=%d\n", KBUILD_MODNAME, ret); + dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n", + KBUILD_MODNAME, ret); else ret = actual_length != wlen ? -EIO : 0; @@ -60,8 +61,8 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, d->props->generic_bulk_ctrl_endpoint_response), rbuf, rlen, &actual_length, 2000); if (ret) - pr_err("%s: 2nd usb_bulk_msg() failed=%d\n", - KBUILD_MODNAME, ret); + dev_err(&d->udev->dev, "%s: 2nd usb_bulk_msg() " \ + "failed=%d\n", KBUILD_MODNAME, ret); #ifdef DVB_USB_XFER_DEBUG print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": <<< ", diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c index d860dac2a83d..c5e2ff0ca3fb 100644 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -22,8 +22,8 @@ static void usb_urb_complete(struct urb *urb) int i; u8 *b; - pr_debug("%s: %s urb completed status=%d length=%d/%d" \ - " pack_num=%d errors=%d\n", __func__, + dev_dbg(&stream->udev->dev, "%s: %s urb completed status=%d " \ + "length=%d/%d pack_num=%d errors=%d\n", __func__, ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", urb->status, urb->actual_length, urb->transfer_buffer_length, @@ -38,8 +38,8 @@ static void usb_urb_complete(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - pr_debug("%s: urb completition failed=%d\n", __func__, - urb->status); + dev_dbg(&stream->udev->dev, "%s: urb completition failed=%d\n", + __func__, urb->status); break; } @@ -48,8 +48,9 @@ static void usb_urb_complete(struct urb *urb) case PIPE_ISOCHRONOUS: for (i = 0; i < urb->number_of_packets; i++) { if (urb->iso_frame_desc[i].status != 0) - pr_debug("%s: iso frame descriptor has an " \ - "error=%d\n", __func__, + dev_dbg(&stream->udev->dev, "%s: iso frame " \ + "descriptor has an error=%d\n", + __func__, urb->iso_frame_desc[i].status); else if (urb->iso_frame_desc[i].actual_length > 0) stream->complete(stream, @@ -65,8 +66,8 @@ static void usb_urb_complete(struct urb *urb) stream->complete(stream, b, urb->actual_length); break; default: - pr_err("%s: unknown endpoint type in completition handler\n", - KBUILD_MODNAME); + dev_err(&stream->udev->dev, "%s: unknown endpoint type in " \ + "completition handler\n", KBUILD_MODNAME); return; } usb_submit_urb(urb, GFP_ATOMIC); @@ -76,7 +77,7 @@ int usb_urb_killv2(struct usb_data_stream *stream) { int i; for (i = 0; i < stream->urbs_submitted; i++) { - pr_debug("%s: kill urb=%d\n", __func__, i); + dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i); /* stop the URB */ usb_kill_urb(stream->urb_list[i]); } @@ -96,11 +97,12 @@ int usb_urb_submitv2(struct usb_data_stream *stream, } for (i = 0; i < stream->urbs_initialized; i++) { - pr_debug("%s: submit urb=%d\n", __func__, i); + dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i); ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); if (ret) { - pr_err("%s: could not submit urb no. %d - get them " \ - "all back\n", KBUILD_MODNAME, i); + dev_err(&stream->udev->dev, "%s: could not submit " \ + "urb no. %d - get them all back\n", + KBUILD_MODNAME, i); usb_urb_killv2(stream); return ret; } @@ -117,7 +119,8 @@ int usb_urb_free_urbs(struct usb_data_stream *stream) for (i = stream->urbs_initialized - 1; i >= 0; i--) { if (stream->urb_list[i]) { - pr_debug("%s: free urb=%d\n", __func__, i); + dev_dbg(&stream->udev->dev, "%s: free urb=%d\n", + __func__, i); /* free the URBs */ usb_free_urb(stream->urb_list[i]); } @@ -133,10 +136,10 @@ static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream) /* allocate the URBs */ for (i = 0; i < stream->props.count; i++) { - pr_debug("%s: alloc urb=%d\n", __func__, i); + dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); if (!stream->urb_list[i]) { - pr_debug("%s: failed\n", __func__); + dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); for (j = 0; j < i; j++) usb_free_urb(stream->urb_list[j]); return -ENOMEM; @@ -164,11 +167,11 @@ static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) for (i = 0; i < stream->props.count; i++) { struct urb *urb; int frame_offset = 0; - pr_debug("%s: alloc urb=%d\n", __func__, i); + dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i); stream->urb_list[i] = usb_alloc_urb( stream->props.u.isoc.framesperurb, GFP_ATOMIC); if (!stream->urb_list[i]) { - pr_debug("%s: failed\n", __func__); + dev_dbg(&stream->udev->dev, "%s: failed\n", __func__); for (j = 0; j < i; j++) usb_free_urb(stream->urb_list[j]); return -ENOMEM; @@ -206,8 +209,8 @@ int usb_free_stream_buffers(struct usb_data_stream *stream) if (stream->state & USB_STATE_URB_BUF) { while (stream->buf_num) { stream->buf_num--; - pr_debug("%s: free buf=%d\n", __func__, - stream->buf_num); + dev_dbg(&stream->udev->dev, "%s: free buf=%d\n", + __func__, stream->buf_num); usb_free_coherent(stream->udev, stream->buf_size, stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]); @@ -225,22 +228,22 @@ int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, stream->buf_num = 0; stream->buf_size = size; - pr_debug("%s: all in all I will use %lu bytes for streaming\n", - __func__, num * size); + dev_dbg(&stream->udev->dev, "%s: all in all I will use %lu bytes for " \ + "streaming\n", __func__, num * size); for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { stream->buf_list[stream->buf_num] = usb_alloc_coherent( stream->udev, size, GFP_ATOMIC, &stream->dma_addr[stream->buf_num]); if (!stream->buf_list[stream->buf_num]) { - pr_debug("%s: alloc buf=%d failed\n", __func__, - stream->buf_num); + dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n", + __func__, stream->buf_num); usb_free_stream_buffers(stream); return -ENOMEM; } - pr_debug("%s: alloc buf=%d %p (dma %llu)\n", __func__, - stream->buf_num, + dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n", + __func__, stream->buf_num, stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); memset(stream->buf_list[stream->buf_num], 0, size); @@ -264,14 +267,15 @@ int usb_urb_reconfig(struct usb_data_stream *stream, } else if (props->type == USB_ISOC) { buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb; } else { - pr_err("%s: invalid endpoint type=%d\n", KBUILD_MODNAME, - props->type); + dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n", + KBUILD_MODNAME, props->type); return -EINVAL; } if (stream->buf_num < props->count || stream->buf_size < buf_size) { - pr_err("%s: cannot reconfigure as allocated buffers are too " \ - "small\n", KBUILD_MODNAME); + dev_err(&stream->udev->dev, "%s: cannot reconfigure as " \ + "allocated buffers are too small\n", + KBUILD_MODNAME); return -EINVAL; } @@ -293,7 +297,7 @@ int usb_urb_reconfig(struct usb_data_stream *stream, return 0; } - pr_debug("%s: re-alloc urbs\n", __func__); + dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__); usb_urb_free_urbs(stream); memcpy(&stream->props, props, sizeof(*props)); @@ -319,8 +323,8 @@ int usb_urb_initv2(struct usb_data_stream *stream, stream->props.endpoint)); if (!stream->complete) { - pr_err("%s: there is no data callback - this doesn't make " \ - "sense\n", KBUILD_MODNAME); + dev_err(&stream->udev->dev, "%s: there is no data callback - " \ + "this doesn't make sense\n", KBUILD_MODNAME); return -EINVAL; } @@ -341,8 +345,8 @@ int usb_urb_initv2(struct usb_data_stream *stream, return usb_urb_alloc_isoc_urbs(stream); default: - pr_err("%s: unknown urb-type for data transfer\n", - KBUILD_MODNAME); + dev_err(&stream->udev->dev, "%s: unknown urb-type for data " \ + "transfer\n", KBUILD_MODNAME); return -EINVAL; } } From b62fd172ff1da93a0c720639e1f64f2a4282f943 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Jun 2012 22:49:19 -0300 Subject: [PATCH 0306/5375] [media] dvb_usb_v2: do not try to remove non-existent adapter Check that adapter exists before trying to remove it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb_usb_core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_core.c b/drivers/media/dvb/dvb-usb/dvb_usb_core.c index 920542c0b672..aed7463167bc 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_core.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_core.c @@ -717,9 +717,11 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) dev_dbg(&d->udev->dev, "%s:\n", __func__); for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) { - dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); - dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); - dvb_usbv2_adapter_stream_exit(&d->adapter[i]); + if (d->adapter[i].props) { + dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); + dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); + dvb_usbv2_adapter_stream_exit(&d->adapter[i]); + } } return 0; From 5674ca257c6b1553005d5a9d9b8f514c53591203 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Jun 2012 23:01:31 -0300 Subject: [PATCH 0307/5375] [media] dvb_usb_v2: remove usb_clear_halt() from stream It works no longer as it was designed since we can change streaming configuration during device operation. Maybe it should be performed conditionally on cases when streaming endpoint is changed. Anyhow, let it out now and add later if needed. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/usb_urb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb/usb_urb.c index c5e2ff0ca3fb..eaf673a3978d 100644 --- a/drivers/media/dvb/dvb-usb/usb_urb.c +++ b/drivers/media/dvb/dvb-usb/usb_urb.c @@ -319,9 +319,6 @@ int usb_urb_initv2(struct usb_data_stream *stream, memcpy(&stream->props, props, sizeof(*props)); - usb_clear_halt(stream->udev, usb_rcvbulkpipe(stream->udev, - stream->props.endpoint)); - if (!stream->complete) { dev_err(&stream->udev->dev, "%s: there is no data callback - " \ "this doesn't make sense\n", KBUILD_MODNAME); From de73beeed032f93f0106992c075357be5b1f2fab Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 5 Jul 2012 19:57:07 -0300 Subject: [PATCH 0308/5375] [media] dvb_usb_v2: register device even no remote keymap defined It failed to register device when remote keymap was not set. Fix it to register device even keymap is NULL. In that case just skip remote registration. Driver should set RC_MAP_EMPTY to enable remote in case of there is remote receiver but default keymap is unknown. Reported-by: pierigno Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 4 ++++ drivers/media/dvb/dvb-usb/af9035.c | 4 ++++ drivers/media/dvb/dvb-usb/dvb_usb.h | 2 +- drivers/media/dvb/dvb-usb/dvb_usb_core.c | 10 ++++++---- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index e48cb586f4cf..bbe1d3382195 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -1276,6 +1276,10 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) } } + /* load empty to enable rc */ + if (!rc->map_name) + rc->map_name = RC_MAP_EMPTY; + rc->allowed_protos = RC_TYPE_NEC; rc->query = af9015_rc_query; rc->interval = 500; diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c index 82b1ac716c2f..79197f46aa95 100644 --- a/drivers/media/dvb/dvb-usb/af9035.c +++ b/drivers/media/dvb/dvb-usb/af9035.c @@ -966,6 +966,10 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) rc->query = af9035_rc_query; rc->interval = 500; + + /* load empty to enable rc */ + if (!rc->map_name) + rc->map_name = RC_MAP_EMPTY; } return 0; diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h index 6fcab07ecada..773817b5fe06 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb/dvb_usb.h @@ -124,7 +124,7 @@ struct dvb_usb_driver_info { * @bulk_mode: device supports bulk mode for rc (disable polling mode) */ struct dvb_usb_rc { - char *map_name; + const char *map_name; u64 allowed_protos; int (*change_protocol)(struct rc_dev *dev, u64 rc_type); int (*query) (struct dvb_usb_device *d); diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_core.c b/drivers/media/dvb/dvb-usb/dvb_usb_core.c index aed7463167bc..3224621e1f32 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb_core.c +++ b/drivers/media/dvb/dvb-usb/dvb_usb_core.c @@ -135,10 +135,15 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config) return 0; + d->rc.map_name = d->rc_map; ret = d->props->get_rc_config(d, &d->rc); if (ret < 0) goto err; + /* disable rc when there is no keymap defined */ + if (!d->rc.map_name) + return 0; + dev = rc_allocate_device(); if (!dev) { ret = -ENOMEM; @@ -153,14 +158,11 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) usb_to_input_id(d->udev, &dev->input_id); /* TODO: likely RC-core should took const char * */ dev->driver_name = (char *) d->props->driver_name; + dev->map_name = d->rc.map_name; dev->driver_type = d->rc.driver_type; dev->allowed_protos = d->rc.allowed_protos; dev->change_protocol = d->rc.change_protocol; dev->priv = d; - if (d->rc.map_name) - dev->map_name = d->rc.map_name; - else - dev->map_name = d->rc_map; ret = rc_register_device(dev); if (ret < 0) { From 8572211842afc53c8450fb470f2b8d02ba7592e0 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Jun 2012 00:17:04 -0300 Subject: [PATCH 0309/5375] [media] mxl111sf: convert to new DVB USB Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 +- drivers/media/dvb/dvb-usb/mxl111sf-tuner.c | 2 + drivers/media/dvb/dvb-usb/mxl111sf.c | 1496 ++++++++------------ drivers/media/dvb/dvb-usb/mxl111sf.h | 22 +- 4 files changed, 577 insertions(+), 945 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index bf7e7222e4e3..a663c75505e5 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -426,7 +426,7 @@ config DVB_USB_IT913X config DVB_USB_MXL111SF tristate "MxL111SF DTV USB2.0 support" - depends on DVB_USB + depends on DVB_USB_V2 select DVB_LGDT3305 if !DVB_FE_CUSTOMISE select DVB_LG2160 if !DVB_FE_CUSTOMISE select VIDEO_TVEEPROM diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c index 74da5bb1ce99..ef4c65fcbb73 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c @@ -31,6 +31,8 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); if (mxl111sf_tuner_debug) \ mxl_printk(KERN_DEBUG, fmt, ##arg) +#define err pr_err + /* ------------------------------------------------------------------------ */ struct mxl111sf_tuner_state { diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c index cd842798f5af..1fb017ecee74 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c @@ -52,9 +52,11 @@ MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int)."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define deb_info(args...) dprintk(dvb_usb_mxl111sf_debug, 0x13, args) -#define deb_reg(args...) dprintk(dvb_usb_mxl111sf_debug, 0x08, args) -#define deb_adv(args...) dprintk(dvb_usb_mxl111sf_debug, MXL_ADV_DBG, args) +#define deb_info pr_debug +#define deb_reg pr_debug +#define deb_adv pr_debug +#define err pr_err +#define info pr_info int mxl111sf_ctrl_msg(struct dvb_usb_device *d, u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) @@ -70,8 +72,8 @@ int mxl111sf_ctrl_msg(struct dvb_usb_device *d, sndbuf[0] = cmd; memcpy(&sndbuf[1], wbuf, wlen); - ret = (wo) ? dvb_usb_generic_write(d, sndbuf, 1+wlen) : - dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); + ret = (wo) ? dvb_usbv2_generic_write(d, sndbuf, 1+wlen) : + dvb_usbv2_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen); mxl_fail(ret); return ret; @@ -246,21 +248,20 @@ fail: }) /* ------------------------------------------------------------------------ */ - +#if 0 static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff) { /* power control depends on which adapter is being woken: * save this for init, instead, via mxl111sf_adap_fe_init */ return 0; } +#endif static int mxl111sf_adap_fe_init(struct dvb_frontend *fe) { - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; - struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv; - + struct dvb_usb_device *d = fe_to_d(fe); + struct mxl111sf_state *state = fe_to_priv(fe); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; int err; /* exit if we didnt initialize the driver yet */ @@ -275,7 +276,7 @@ static int mxl111sf_adap_fe_init(struct dvb_frontend *fe) state->alt_mode = adap_state->alt_mode; - if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) err("set interface failed"); err = mxl1x1sf_soft_reset(state); @@ -315,10 +316,8 @@ fail: static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe) { - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; - struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv; + struct mxl111sf_state *state = fe_to_priv(fe); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; int err; /* exit if we didnt initialize the driver yet */ @@ -339,11 +338,10 @@ fail: } -static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +static int mxl111sf_ep6_streaming_ctrl(struct dvb_frontend *fe, int onoff) { - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; - struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv; + struct mxl111sf_state *state = fe_to_priv(fe); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id]; int ret = 0; deb_info("%s(%d)\n", __func__, onoff); @@ -365,10 +363,9 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return ret; } -static int mxl111sf_ep5_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +static int mxl111sf_ep5_streaming_ctrl(struct dvb_frontend *fe, int onoff) { - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; + struct mxl111sf_state *state = fe_to_priv(fe); int ret = 0; deb_info("%s(%d)\n", __func__, onoff); @@ -392,10 +389,9 @@ static int mxl111sf_ep5_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return ret; } -static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +static int mxl111sf_ep4_streaming_ctrl(struct dvb_frontend *fe, int onoff) { - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; + struct mxl111sf_state *state = fe_to_priv(fe); int ret = 0; deb_info("%s(%d)\n", __func__, onoff); @@ -421,12 +417,11 @@ static struct lgdt3305_config hauppauge_lgdt3305_config = { .vsb_if_khz = 6000, }; -static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) +static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) { - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; - int fe_id = adap->num_frontends_initialized; - struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; int ret; deb_adv("%s()\n", __func__); @@ -436,7 +431,7 @@ static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; state->alt_mode = adap_state->alt_mode; - if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) err("set interface failed"); state->gpio_mode = MXL111SF_GPIO_MOD_ATSC; @@ -469,14 +464,15 @@ static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) if (mxl_fail(ret)) goto fail; - adap->fe_adap[fe_id].fe = dvb_attach(lgdt3305_attach, + adap->fe[fe_id] = dvb_attach(lgdt3305_attach, &hauppauge_lgdt3305_config, - &adap->dev->i2c_adap); - if (adap->fe_adap[fe_id].fe) { - adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; - adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; - adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; return 0; } ret = -EIO; @@ -492,12 +488,11 @@ static struct lg2160_config hauppauge_lg2160_config = { .if_khz = 6000, }; -static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap) +static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) { - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; - int fe_id = adap->num_frontends_initialized; - struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; int ret; deb_adv("%s()\n", __func__); @@ -507,7 +502,7 @@ static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap) adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; state->alt_mode = adap_state->alt_mode; - if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) err("set interface failed"); state->gpio_mode = MXL111SF_GPIO_MOD_MH; @@ -544,14 +539,15 @@ static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap) if (mxl_fail(ret)) goto fail; - adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach, + adap->fe[fe_id] = dvb_attach(lg2160_attach, &hauppauge_lg2160_config, - &adap->dev->i2c_adap); - if (adap->fe_adap[fe_id].fe) { - adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; - adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; - adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; return 0; } ret = -EIO; @@ -577,12 +573,11 @@ static struct lg2160_config hauppauge_lg2161_1040_config = { .output_if = 4, /* LG2161_OIF_SPI_MAS */ }; -static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap) +static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) { - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; - int fe_id = adap->num_frontends_initialized; - struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; int ret; deb_adv("%s()\n", __func__); @@ -592,7 +587,7 @@ static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap) adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; state->alt_mode = adap_state->alt_mode; - if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) err("set interface failed"); state->gpio_mode = MXL111SF_GPIO_MOD_MH; @@ -629,16 +624,17 @@ static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap) if (mxl_fail(ret)) goto fail; - adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach, + adap->fe[fe_id] = dvb_attach(lg2160_attach, (MXL111SF_V8_200 == state->chip_rev) ? &hauppauge_lg2161_1040_config : &hauppauge_lg2161_1019_config, - &adap->dev->i2c_adap); - if (adap->fe_adap[fe_id].fe) { - adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; - adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; - adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; return 0; } ret = -EIO; @@ -664,12 +660,11 @@ static struct lg2160_config hauppauge_lg2161_1040_ep6_config = { .output_if = 7, /* LG2161_OIF_SERIAL_TS */ }; -static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap) +static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id) { - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; - int fe_id = adap->num_frontends_initialized; - struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; int ret; deb_adv("%s()\n", __func__); @@ -679,7 +674,7 @@ static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap) adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1; state->alt_mode = adap_state->alt_mode; - if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) err("set interface failed"); state->gpio_mode = MXL111SF_GPIO_MOD_MH; @@ -716,16 +711,17 @@ static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap) if (mxl_fail(ret)) goto fail; - adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach, + adap->fe[fe_id] = dvb_attach(lg2160_attach, (MXL111SF_V8_200 == state->chip_rev) ? &hauppauge_lg2161_1040_ep6_config : &hauppauge_lg2161_1019_ep6_config, - &adap->dev->i2c_adap); - if (adap->fe_adap[fe_id].fe) { - adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; - adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; - adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; + &d->i2c_adap); + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; return 0; } ret = -EIO; @@ -739,12 +735,11 @@ static struct mxl111sf_demod_config mxl_demod_config = { .program_regs = mxl111sf_ctrl_program_regs, }; -static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap) +static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id) { - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; - int fe_id = adap->num_frontends_initialized; - struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; + struct dvb_usb_device *d = adap_to_d(adap); + struct mxl111sf_state *state = d_to_priv(d); + struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id]; int ret; deb_adv("%s()\n", __func__); @@ -754,7 +749,7 @@ static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap) adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2; state->alt_mode = adap_state->alt_mode; - if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) + if (usb_set_interface(d->udev, 0, state->alt_mode) < 0) err("set interface failed"); state->gpio_mode = MXL111SF_GPIO_MOD_DVBT; @@ -783,13 +778,14 @@ static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap) /* dont care if this fails */ mxl111sf_init_port_expander(state); - adap->fe_adap[fe_id].fe = dvb_attach(mxl111sf_demod_attach, state, + adap->fe[fe_id] = dvb_attach(mxl111sf_demod_attach, state, &mxl_demod_config); - if (adap->fe_adap[fe_id].fe) { - adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; - adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; - adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; - adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; + if (adap->fe[fe_id]) { + state->num_frontends++; + adap_state->fe_init = adap->fe[fe_id]->ops.init; + adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init; + adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep; + adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep; return 0; } ret = -EIO; @@ -816,10 +812,7 @@ static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, static int mxl111sf_ant_hunt(struct dvb_frontend *fe) { - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; - + struct mxl111sf_state *state = fe_to_priv(fe); int antctrl = dvb_usb_mxl111sf_rfswitch; u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2; @@ -872,18 +865,18 @@ static struct mxl111sf_tuner_config mxl_tuner_config = { static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap) { - struct dvb_usb_device *d = adap->dev; - struct mxl111sf_state *state = d->priv; - int fe_id = adap->num_frontends_initialized; + struct mxl111sf_state *state = adap_to_priv(adap); + int i; deb_adv("%s()\n", __func__); - if (NULL != dvb_attach(mxl111sf_tuner_attach, - adap->fe_adap[fe_id].fe, state, - &mxl_tuner_config)) - return 0; + for (i = 0; i < state->num_frontends; i++) { + if (dvb_attach(mxl111sf_tuner_attach, adap->fe[i], state, + &mxl_tuner_config) == NULL) + return -EIO; + } - return -EIO; + return 0; } static int mxl111sf_fe_ioctl_override(struct dvb_frontend *fe, @@ -926,902 +919,537 @@ struct i2c_algorithm mxl111sf_i2c_algo = { #endif }; -static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties; -static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties; -static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties; -static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties; -static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties; -static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties; -static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties; -static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties; -static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties; -static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties; -static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties; -static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties; -static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties; -static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties; -static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties; -static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties; - -static int mxl111sf_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static int mxl111sf_init(struct dvb_usb_device *d) { - struct dvb_usb_device *d = NULL; + struct mxl111sf_state *state = d_to_priv(d); + int ret; + static u8 eeprom[256]; + struct i2c_client c; - deb_adv("%s()\n", __func__); + ret = get_chip_info(state); + if (mxl_fail(ret)) + err("failed to get chip info during probe"); - if (((dvb_usb_mxl111sf_isoc) && - (0 == dvb_usb_device_init(intf, - &mxl111sf_dvbt_isoc_properties, - THIS_MODULE, &d, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_atsc_isoc_properties, - THIS_MODULE, &d, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_atsc_mh_isoc_properties, - THIS_MODULE, &d, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_mh_isoc_properties, - THIS_MODULE, &d, adapter_nr) || - ((dvb_usb_mxl111sf_spi) && - (0 == dvb_usb_device_init(intf, - &mxl111sf_mercury_spi_isoc_properties, - THIS_MODULE, &d, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_mercury_mh_spi_isoc_properties, - THIS_MODULE, &d, adapter_nr))) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_mercury_tp_isoc_properties, - THIS_MODULE, &d, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_mercury_mh_tp_isoc_properties, - THIS_MODULE, &d, adapter_nr))) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_dvbt_bulk_properties, - THIS_MODULE, &d, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_atsc_bulk_properties, - THIS_MODULE, &d, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_atsc_mh_bulk_properties, - THIS_MODULE, &d, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_mh_bulk_properties, - THIS_MODULE, &d, adapter_nr) || - ((dvb_usb_mxl111sf_spi) && - (0 == dvb_usb_device_init(intf, - &mxl111sf_mercury_spi_bulk_properties, - THIS_MODULE, &d, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_mercury_mh_spi_bulk_properties, - THIS_MODULE, &d, adapter_nr))) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_mercury_tp_bulk_properties, - THIS_MODULE, &d, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &mxl111sf_mercury_mh_tp_bulk_properties, - THIS_MODULE, &d, adapter_nr) || 0) { + mutex_init(&state->fe_lock); - struct mxl111sf_state *state = d->priv; - static u8 eeprom[256]; - struct i2c_client c; - int ret; + if (state->chip_rev > MXL111SF_V6) + mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1); - ret = get_chip_info(state); - if (mxl_fail(ret)) - err("failed to get chip info during probe"); + c.adapter = &d->i2c_adap; + c.addr = 0xa0 >> 1; - mutex_init(&state->fe_lock); - - if (state->chip_rev > MXL111SF_V6) - mxl111sf_config_pin_mux_modes(state, - PIN_MUX_TS_SPI_IN_MODE_1); - - c.adapter = &d->i2c_adap; - c.addr = 0xa0 >> 1; - - ret = tveeprom_read(&c, eeprom, sizeof(eeprom)); - if (mxl_fail(ret)) - return 0; - tveeprom_hauppauge_analog(&c, &state->tv, - (0x84 == eeprom[0xa0]) ? - eeprom + 0xa0 : eeprom + 0x80); -#if 0 - switch (state->tv.model) { - case 117001: - case 126001: - case 138001: - break; - default: - printk(KERN_WARNING "%s: warning: " - "unknown hauppauge model #%d\n", - __func__, state->tv.model); - } -#endif + ret = tveeprom_read(&c, eeprom, sizeof(eeprom)); + if (mxl_fail(ret)) return 0; + tveeprom_hauppauge_analog(&c, &state->tv, (0x84 == eeprom[0xa0]) ? + eeprom + 0xa0 : eeprom + 0x80); +#if 0 + switch (state->tv.model) { + case 117001: + case 126001: + case 138001: + break; + default: + printk(KERN_WARNING "%s: warning: " + "unknown hauppauge model #%d\n", + __func__, state->tv.model); } - err("Your device is not yet supported by this driver. " - "See kernellabs.com for more info"); - return -EINVAL; +#endif + return 0; } -static struct usb_device_id mxl111sf_table[] = { -/* 0 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600) }, /* ATSC+ IR */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601) }, /* ATSC */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602) }, /* + */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603) }, /* ATSC+ */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604) }, /* DVBT */ -/* 5 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609) }, /* ATSC IR */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a) }, /* + IR */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b) }, /* ATSC+ IR */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c) }, /* DVBT IR */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653) }, /* ATSC+ */ -/*10 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b) }, /* ATSC+ IR */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700) }, /* ATSC+ sw */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701) }, /* ATSC sw */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702) }, /* + sw */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703) }, /* ATSC+ sw */ -/*15 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704) }, /* DVBT sw */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753) }, /* ATSC+ sw */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763) }, /* ATSC+ no */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764) }, /* DVBT no */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853) }, /* ATSC+ sw */ -/*20 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854) }, /* DVBT sw */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863) }, /* ATSC+ no */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864) }, /* DVBT no */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3) }, /* ATSC+ sw */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4) }, /* DVBT sw */ -/*25 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3) }, /* ATSC+ no */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4) }, /* DVBT no */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff) }, /* ATSC+ */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612) }, /* + */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613) }, /* ATSC+ */ -/*30 */ { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a) }, /* + IR */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b) }, /* ATSC+ IR */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757) }, /* ATSC+DVBT sw */ - { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767) }, /* ATSC+DVBT no */ - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, mxl111sf_table); +static int mxl111sf_frontend_attach_dvbt(struct dvb_usb_adapter *adap) +{ + return mxl111sf_attach_demod(adap, 0); +} +static int mxl111sf_frontend_attach_atsc(struct dvb_usb_adapter *adap) +{ + return mxl111sf_lgdt3305_frontend_attach(adap, 0); +} -#define MXL111SF_EP4_BULK_STREAMING_CONFIG \ - .size_of_priv = sizeof(struct mxl111sf_adap_state), \ - .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ - .stream = { \ - .type = USB_BULK, \ - .count = 5, \ - .endpoint = 0x04, \ - .u = { \ - .bulk = { \ - .buffersize = 8192, \ - } \ - } \ - } +static int mxl111sf_frontend_attach_mh(struct dvb_usb_adapter *adap) +{ + return mxl111sf_lg2160_frontend_attach(adap, 0); +} -/* FIXME: works for v6 but not v8 silicon */ -#define MXL111SF_EP4_ISOC_STREAMING_CONFIG \ - .size_of_priv = sizeof(struct mxl111sf_adap_state), \ - .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ - .stream = { \ - .type = USB_ISOC, \ - .count = 5, \ - .endpoint = 0x04, \ - .u = { \ - .isoc = { \ - .framesperurb = 96, \ - /* FIXME: v6 SILICON: */ \ - .framesize = 564, \ - .interval = 1, \ - } \ - } \ - } +static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap) +{ + int ret; + deb_info("%s\n", __func__); -#define MXL111SF_EP5_BULK_STREAMING_CONFIG \ - .size_of_priv = sizeof(struct mxl111sf_adap_state), \ - .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, \ - .stream = { \ - .type = USB_BULK, \ - .count = 5, \ - .endpoint = 0x05, \ - .u = { \ - .bulk = { \ - .buffersize = 8192, \ - } \ - } \ - } + ret = mxl111sf_lgdt3305_frontend_attach(adap, 0); + if (ret < 0) + return ret; -#define MXL111SF_EP5_ISOC_STREAMING_CONFIG \ - .size_of_priv = sizeof(struct mxl111sf_adap_state), \ - .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, \ - .stream = { \ - .type = USB_ISOC, \ - .count = 5, \ - .endpoint = 0x05, \ - .u = { \ - .isoc = { \ - .framesperurb = 96, \ - .framesize = 200, \ - .interval = 1, \ - } \ - } \ - } + ret = mxl111sf_attach_demod(adap, 1); + if (ret < 0) + return ret; -#define MXL111SF_EP6_BULK_STREAMING_CONFIG \ - .size_of_priv = sizeof(struct mxl111sf_adap_state), \ - .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ - .stream = { \ - .type = USB_BULK, \ - .count = 5, \ - .endpoint = 0x06, \ - .u = { \ - .bulk = { \ - .buffersize = 8192, \ - } \ - } \ - } + ret = mxl111sf_lg2160_frontend_attach(adap, 2); + if (ret < 0) + return ret; -/* FIXME */ -#define MXL111SF_EP6_ISOC_STREAMING_CONFIG \ - .size_of_priv = sizeof(struct mxl111sf_adap_state), \ - .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ - .stream = { \ - .type = USB_ISOC, \ - .count = 5, \ - .endpoint = 0x06, \ - .u = { \ - .isoc = { \ - .framesperurb = 24, \ - .framesize = 3072, \ - .interval = 1, \ - } \ - } \ - } + return ret; +} -#define MXL111SF_DEFAULT_DEVICE_PROPERTIES \ - .caps = DVB_USB_IS_AN_I2C_ADAPTER, \ - .usb_ctrl = DEVICE_SPECIFIC, \ - /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), \ - EP6 BULK transfer (atsc/qam), \ - use usb alt setting 2 for EP4 BULK transfer (dvb-t), \ - EP6 ISOC transfer (atsc/qam), \ - */ \ - .power_ctrl = mxl111sf_power_ctrl, \ - .i2c_algo = &mxl111sf_i2c_algo, \ - .generic_bulk_ctrl_endpoint = MXL_EP2_REG_WRITE, \ - .generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \ - .size_of_priv = sizeof(struct mxl111sf_state) +static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap) +{ + int ret; + deb_info("%s\n", __func__); -static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, + ret = mxl111sf_lgdt3305_frontend_attach(adap, 0); + if (ret < 0) + return ret; + + ret = mxl111sf_attach_demod(adap, 1); + if (ret < 0) + return ret; + + ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 2); + if (ret < 0) + return ret; + + return ret; +} + +static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap) +{ + int ret; + deb_info("%s\n", __func__); + + ret = mxl111sf_attach_demod(adap, 0); + if (ret < 0) + return ret; + + if (dvb_usb_mxl111sf_spi) + ret = mxl111sf_lg2161_frontend_attach(adap, 1); + else + ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 1); + + return ret; +} + +static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *stream, u8 endpoint) +{ + deb_info("%s: endpoint=%d size=8192\n", __func__, endpoint); + stream->type = USB_BULK; + stream->count = 5; + stream->endpoint = endpoint; + stream->u.bulk.buffersize = 8192; +} + +static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *stream, + u8 endpoint, int framesperurb, int framesize) +{ + deb_info("%s: endpoint=%d size=%d\n", __func__, endpoint, + framesperurb * framesize); + stream->type = USB_ISOC; + stream->count = 5; + stream->endpoint = endpoint; + stream->u.isoc.framesperurb = framesperurb; + stream->u.isoc.framesize = framesize; + stream->u.isoc.interval = 1; +} + +/* DVB USB Driver stuff */ + +/* dvbt mxl111sf + * bulk EP4/BULK/5/8192 + * isoc EP4/ISOC/5/96/564 + */ +static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_dvbt = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_dvbt, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, + .get_stream_config = mxl111sf_get_stream_config_dvbt, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_adapters = 1, .adapter = { { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 1, - .fe = {{ - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_BULK_STREAMING_CONFIG, - } }, - }, - }, - .num_device_descs = 3, - .devices = { - { "Hauppauge 126xxx DVBT (bulk)", - { NULL }, - { &mxl111sf_table[4], &mxl111sf_table[8], - NULL }, - }, - { "Hauppauge 117xxx DVBT (bulk)", - { NULL }, - { &mxl111sf_table[15], &mxl111sf_table[18], - NULL }, - }, - { "Hauppauge 138xxx DVBT (bulk)", - { NULL }, - { &mxl111sf_table[20], &mxl111sf_table[22], - &mxl111sf_table[24], &mxl111sf_table[26], - NULL }, - }, + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } } }; -static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, +/* atsc lgdt3305 + * bulk EP6/BULK/5/8192 + * isoc EP6/ISOC/5/24/3072 + */ +static int mxl111sf_get_stream_config_atsc(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_atsc = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_atsc, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, + .get_stream_config = mxl111sf_get_stream_config_atsc, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_adapters = 1, .adapter = { { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 1, - .fe = {{ - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_ISOC_STREAMING_CONFIG, - } }, - }, - }, - .num_device_descs = 3, - .devices = { - { "Hauppauge 126xxx DVBT (isoc)", - { NULL }, - { &mxl111sf_table[4], &mxl111sf_table[8], - NULL }, - }, - { "Hauppauge 117xxx DVBT (isoc)", - { NULL }, - { &mxl111sf_table[15], &mxl111sf_table[18], - NULL }, - }, - { "Hauppauge 138xxx DVBT (isoc)", - { NULL }, - { &mxl111sf_table[20], &mxl111sf_table[22], - &mxl111sf_table[24], &mxl111sf_table[26], - NULL }, - }, + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } } }; -static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, +/* mh lg2160 + * bulk EP5/BULK/5/8192/RAW + * isoc EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_mh(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_mh = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_mh, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, + .get_stream_config = mxl111sf_get_stream_config_mh, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_adapters = 1, .adapter = { { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 1, - .fe = {{ - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_BULK_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 2, - .devices = { - { "Hauppauge 126xxx ATSC (bulk)", - { NULL }, - { &mxl111sf_table[1], &mxl111sf_table[5], - NULL }, - }, - { "Hauppauge 117xxx ATSC (bulk)", - { NULL }, - { &mxl111sf_table[12], - NULL }, - }, + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } } }; -static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, +/* atsc mh lgdt3305 mxl111sf lg2160 + * bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW + * isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + if (fe->id == 0) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } else if (fe->id == 1) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + } else if (fe->id == 2) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + } + return 0; +} + +static int mxl111sf_streaming_ctrl_atsc_mh(struct dvb_frontend *fe, int onoff) +{ + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + if (fe->id == 0) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + else if (fe->id == 1) + return mxl111sf_ep4_streaming_ctrl(fe, onoff); + else if (fe->id == 2) + return mxl111sf_ep5_streaming_ctrl(fe, onoff); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_atsc_mh, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_streaming_ctrl_atsc_mh, + .get_stream_config = mxl111sf_get_stream_config_atsc_mh, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_adapters = 1, .adapter = { { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 1, - .fe = {{ - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_ISOC_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 2, - .devices = { - { "Hauppauge 126xxx ATSC (isoc)", - { NULL }, - { &mxl111sf_table[1], &mxl111sf_table[5], - NULL }, - }, - { "Hauppauge 117xxx ATSC (isoc)", - { NULL }, - { &mxl111sf_table[12], - NULL }, - }, + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } } }; -static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, +/* mercury lgdt3305 mxl111sf lg2161 + * tp bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP6/BULK/5/8192/RAW + * tp isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW + * spi bulk EP6/BULK/5/8192 EP4/BULK/5/8192 EP5/BULK/5/8192/RAW + * spi isoc EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + if (fe->id == 0) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } else if (fe->id == 1) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + } else if (fe->id == 2 && dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + } else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } + return 0; +} + +static int mxl111sf_streaming_ctrl_mercury(struct dvb_frontend *fe, int onoff) +{ + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + if (fe->id == 0) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + else if (fe->id == 1) + return mxl111sf_ep4_streaming_ctrl(fe, onoff); + else if (fe->id == 2 && dvb_usb_mxl111sf_spi) + return mxl111sf_ep5_streaming_ctrl(fe, onoff); + else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_mercury = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_mercury, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_streaming_ctrl_mercury, + .get_stream_config = mxl111sf_get_stream_config_mercury, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_adapters = 1, .adapter = { { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2160_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP5_BULK_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 2, - .devices = { - { "HCW 126xxx (bulk)", - { NULL }, - { &mxl111sf_table[2], &mxl111sf_table[6], - NULL }, - }, - { "HCW 117xxx (bulk)", - { NULL }, - { &mxl111sf_table[13], - NULL }, - }, + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } } }; -static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, +/* mercury mh mxl111sf lg2161 + * tp bulk EP4/BULK/5/8192 EP6/BULK/5/8192/RAW + * tp isoc EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW + * spi bulk EP4/BULK/5/8192 EP5/BULK/5/8192/RAW + * spi isoc EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW + */ +static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe, + u8 *ts_type, struct usb_data_stream_properties *stream) +{ + deb_info("%s: fe=%d\n", __func__, fe->id); + + if (fe->id == 0) { + *ts_type = DVB_USB_FE_TS_TYPE_188; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 4, 96, 564); + else + mxl111sf_stream_config_bulk(stream, 4); + } else if (fe->id == 1 && dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 5, 96, 200); + else + mxl111sf_stream_config_bulk(stream, 5); + } else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) { + *ts_type = DVB_USB_FE_TS_TYPE_RAW; + if (dvb_usb_mxl111sf_isoc) + mxl111sf_stream_config_isoc(stream, 6, 24, 3072); + else + mxl111sf_stream_config_bulk(stream, 6); + } + return 0; +} + +static int mxl111sf_streaming_ctrl_mercury_mh(struct dvb_frontend *fe, int onoff) +{ + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + if (fe->id == 0) + return mxl111sf_ep4_streaming_ctrl(fe, onoff); + else if (fe->id == 1 && dvb_usb_mxl111sf_spi) + return mxl111sf_ep5_streaming_ctrl(fe, onoff); + else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) + return mxl111sf_ep6_streaming_ctrl(fe, onoff); + return 0; +} + +static struct dvb_usb_device_properties mxl111sf_props_mercury_mh = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct mxl111sf_state), + + .generic_bulk_ctrl_endpoint = 0x02, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .i2c_algo = &mxl111sf_i2c_algo, + .frontend_attach = mxl111sf_frontend_attach_mercury_mh, + .tuner_attach = mxl111sf_attach_tuner, + .init = mxl111sf_init, + .streaming_ctrl = mxl111sf_streaming_ctrl_mercury_mh, + .get_stream_config = mxl111sf_get_stream_config_mercury_mh, + .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_adapters = 1, .adapter = { { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2160_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP5_ISOC_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 2, - .devices = { - { "HCW 126xxx (isoc)", - { NULL }, - { &mxl111sf_table[2], &mxl111sf_table[6], - NULL }, - }, - { "HCW 117xxx (isoc)", - { NULL }, - { &mxl111sf_table[13], - NULL }, - }, + .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1), + } } }; -static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, +static const struct usb_device_id mxl111sf_id_table[] = { + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602, &mxl111sf_props_mh, "HCW 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a, &mxl111sf_props_mh, "HCW 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702, &mxl111sf_props_mh, "HCW 117xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, mxl111sf_id_table); - .num_adapters = 1, - .adapter = { - { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 3, - .fe = {{ - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_BULK_STREAMING_CONFIG, - }, - { - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_BULK_STREAMING_CONFIG, - }, - { - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2160_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP5_BULK_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 2, - .devices = { - { "Hauppauge 126xxx ATSC+ (bulk)", - { NULL }, - { &mxl111sf_table[0], &mxl111sf_table[3], - &mxl111sf_table[7], &mxl111sf_table[9], - &mxl111sf_table[10], NULL }, - }, - { "Hauppauge 117xxx ATSC+ (bulk)", - { NULL }, - { &mxl111sf_table[11], &mxl111sf_table[14], - &mxl111sf_table[16], &mxl111sf_table[17], - &mxl111sf_table[32], &mxl111sf_table[33], - NULL }, - }, - } +static struct usb_driver mxl111sf_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = mxl111sf_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, }; -static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 3, - .fe = {{ - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_ISOC_STREAMING_CONFIG, - }, - { - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_ISOC_STREAMING_CONFIG, - }, - { - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2160_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP5_ISOC_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 2, - .devices = { - { "Hauppauge 126xxx ATSC+ (isoc)", - { NULL }, - { &mxl111sf_table[0], &mxl111sf_table[3], - &mxl111sf_table[7], &mxl111sf_table[9], - &mxl111sf_table[10], NULL }, - }, - { "Hauppauge 117xxx ATSC+ (isoc)", - { NULL }, - { &mxl111sf_table[11], &mxl111sf_table[14], - &mxl111sf_table[16], &mxl111sf_table[17], - &mxl111sf_table[32], &mxl111sf_table[33], - NULL }, - }, - } -}; - -static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 3, - .fe = {{ - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_BULK_STREAMING_CONFIG, - }, - { - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_BULK_STREAMING_CONFIG, - }, - { - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2161_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP5_BULK_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 2, - .devices = { - { "Hauppauge Mercury (spi-bulk)", - { NULL }, - { &mxl111sf_table[19], &mxl111sf_table[21], - &mxl111sf_table[23], &mxl111sf_table[25], - NULL }, - }, - { "Hauppauge WinTV-Aero-M (spi-bulk)", - { NULL }, - { &mxl111sf_table[29], &mxl111sf_table[31], - NULL }, - }, - } -}; - -static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 3, - .fe = {{ - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_ISOC_STREAMING_CONFIG, - }, - { - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_ISOC_STREAMING_CONFIG, - }, - { - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2161_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP5_ISOC_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 2, - .devices = { - { "Hauppauge Mercury (spi-isoc)", - { NULL }, - { &mxl111sf_table[19], &mxl111sf_table[21], - &mxl111sf_table[23], &mxl111sf_table[25], - NULL }, - }, - { "Hauppauge WinTV-Aero-M (spi-isoc)", - { NULL }, - { &mxl111sf_table[29], &mxl111sf_table[31], - NULL }, - }, - } -}; - -static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 3, - .fe = {{ - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_BULK_STREAMING_CONFIG, - }, - { - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_BULK_STREAMING_CONFIG, - }, - { - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_BULK_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 2, - .devices = { - { "Hauppauge Mercury (tp-bulk)", - { NULL }, - { &mxl111sf_table[19], &mxl111sf_table[21], - &mxl111sf_table[23], &mxl111sf_table[25], - &mxl111sf_table[27], NULL }, - }, - { "Hauppauge WinTV-Aero-M", - { NULL }, - { &mxl111sf_table[29], &mxl111sf_table[31], - NULL }, - }, - } -}; - -static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 3, - .fe = {{ - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_ISOC_STREAMING_CONFIG, - }, - { - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_ISOC_STREAMING_CONFIG, - }, - { - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_ISOC_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 2, - .devices = { - { "Hauppauge Mercury (tp-isoc)", - { NULL }, - { &mxl111sf_table[19], &mxl111sf_table[21], - &mxl111sf_table[23], &mxl111sf_table[25], - &mxl111sf_table[27], NULL }, - }, - { "Hauppauge WinTV-Aero-M (tp-isoc)", - { NULL }, - { &mxl111sf_table[29], &mxl111sf_table[31], - NULL }, - }, - } -}; - -static -struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 2, - .fe = {{ - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_BULK_STREAMING_CONFIG, - }, - { - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_BULK_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 1, - .devices = { - { "Hauppauge 126xxx (tp-bulk)", - { NULL }, - { &mxl111sf_table[28], &mxl111sf_table[30], - NULL }, - }, - } -}; - -static -struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 2, - .fe = {{ - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_ISOC_STREAMING_CONFIG, - }, - { - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP6_ISOC_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 1, - .devices = { - { "Hauppauge 126xxx (tp-isoc)", - { NULL }, - { &mxl111sf_table[28], &mxl111sf_table[30], - NULL }, - }, - } -}; - -static -struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 2, - .fe = {{ - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_BULK_STREAMING_CONFIG, - }, - { - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2161_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP5_BULK_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 1, - .devices = { - { "Hauppauge 126xxx (spi-bulk)", - { NULL }, - { &mxl111sf_table[28], &mxl111sf_table[30], - NULL }, - }, - } -}; - -static -struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties = { - MXL111SF_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .fe_ioctl_override = mxl111sf_fe_ioctl_override, - .num_frontends = 2, - .fe = {{ - .frontend_attach = mxl111sf_attach_demod, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP4_ISOC_STREAMING_CONFIG, - }, - { - .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD, - - .frontend_attach = mxl111sf_lg2161_frontend_attach, - .tuner_attach = mxl111sf_attach_tuner, - - MXL111SF_EP5_ISOC_STREAMING_CONFIG, - }}, - }, - }, - .num_device_descs = 1, - .devices = { - { "Hauppauge 126xxx (spi-isoc)", - { NULL }, - { &mxl111sf_table[28], &mxl111sf_table[30], - NULL }, - }, - } -}; - -static struct usb_driver mxl111sf_driver = { - .name = "dvb_usb_mxl111sf", - .probe = mxl111sf_probe, - .disconnect = dvb_usb_device_exit, - .id_table = mxl111sf_table, -}; - -module_usb_driver(mxl111sf_driver); +module_usb_driver(mxl111sf_usb_driver); MODULE_AUTHOR("Michael Krufky "); MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF"); diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.h b/drivers/media/dvb/dvb-usb/mxl111sf.h index 364d89f826bd..9816de86e48c 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.h +++ b/drivers/media/dvb/dvb-usb/mxl111sf.h @@ -15,7 +15,7 @@ #undef DVB_USB_LOG_PREFIX #endif #define DVB_USB_LOG_PREFIX "mxl111sf" -#include "dvb-usb.h" +#include "dvb_usb.h" #include #define MXL_EP1_REG_READ 1 @@ -39,6 +39,15 @@ enum mxl111sf_gpio_port_expander { mxl111sf_PCA9534, }; +struct mxl111sf_adap_state { + int alt_mode; + int gpio_mode; + int device_mode; + int ep6_clockphase; + int (*fe_init)(struct dvb_frontend *); + int (*fe_sleep)(struct dvb_frontend *); +}; + struct mxl111sf_state { struct dvb_usb_device *d; @@ -74,15 +83,8 @@ struct mxl111sf_state { struct tveeprom tv; struct mutex fe_lock; -}; - -struct mxl111sf_adap_state { - int alt_mode; - int gpio_mode; - int device_mode; - int ep6_clockphase; - int (*fe_init)(struct dvb_frontend *); - int (*fe_sleep)(struct dvb_frontend *); + u8 num_frontends; + struct mxl111sf_adap_state adap_state[3]; }; int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data); From 4d2e596ac8ff68d48c9d1ba15226fca3b494f984 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Jun 2012 18:25:51 -0300 Subject: [PATCH 0310/5375] [media] gl861: convert to new DVB USB Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 +- drivers/media/dvb/dvb-usb/gl861.c | 130 ++++++++++-------------------- drivers/media/dvb/dvb-usb/gl861.h | 5 +- 3 files changed, 46 insertions(+), 91 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index a663c75505e5..09fded4eb0b4 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -164,7 +164,7 @@ config DVB_USB_M920X config DVB_USB_GL861 tristate "Genesys Logic GL861 USB2.0 support" - depends on DVB_USB + depends on DVB_USB_V2 select DVB_ZL10353 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE help diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c index c1f5582e1cdf..cf29f43e3598 100644 --- a/drivers/media/dvb/dvb-usb/gl861.c +++ b/drivers/media/dvb/dvb-usb/gl861.c @@ -11,11 +11,6 @@ #include "zl10353.h" #include "qt1010.h" -/* debug */ -static int dvb_usb_gl861_debug; -module_param_named(debug, dvb_usb_gl861_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." - DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, @@ -43,7 +38,7 @@ static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, value = value + wbuf[1]; break; default: - warn("wlen = %x, aborting.", wlen); + pr_err("%s: wlen=%d, aborting\n", KBUILD_MODNAME, wlen); return -EINVAL; } @@ -103,9 +98,9 @@ static struct zl10353_config gl861_zl10353_config = { static int gl861_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &gl861_zl10353_config, - &adap->dev->i2c_adap); - if (adap->fe_adap[0].fe == NULL) + adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config, + &adap_to_d(adap)->i2c_adap); + if (adap->fe[0] == NULL) return -EIO; return 0; @@ -118,98 +113,61 @@ static struct qt1010_config gl861_qt1010_config = { static int gl861_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(qt1010_attach, - adap->fe_adap[0].fe, &adap->dev->i2c_adap, + adap->fe[0], &adap_to_d(adap)->i2c_adap, &gl861_qt1010_config) == NULL ? -ENODEV : 0; } -/* DVB USB Driver stuff */ -static struct dvb_usb_device_properties gl861_properties; - -static int gl861_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static int gl861_init(struct dvb_usb_device *d) { - struct dvb_usb_device *d; - struct usb_host_interface *alt; - int ret; - - if (intf->num_altsetting < 2) - return -ENODEV; - - ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d, - adapter_nr); - if (ret == 0) { - alt = usb_altnum_to_altsetting(intf, 0); - - if (alt == NULL) { - deb_rc("not alt found!\n"); - return -ENODEV; - } - - ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - } - - return ret; + /* + * There is 2 interfaces. Interface 0 is for TV and interface 1 is + * for HID remote controller. Interface 0 has 2 alternate settings. + * For some reason we need to set interface explicitly, defaulted + * as alternate setting 1? + */ + return usb_set_interface(d->udev, 0, 0); } -static struct usb_device_id gl861_table [] = { - { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) }, - { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, gl861_table); +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties gl861_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .adapter_nr = adapter_nr, -static struct dvb_usb_device_properties gl861_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - - .size_of_priv = 0, + .i2c_algo = &gl861_i2c_algo, + .frontend_attach = gl861_frontend_attach, + .tuner_attach = gl861_tuner_attach, + .init = gl861_init, .num_adapters = 1, - .adapter = {{ - .num_frontends = 1, - .fe = {{ - - .frontend_attach = gl861_frontend_attach, - .tuner_attach = gl861_tuner_attach, - - .stream = { - .type = USB_BULK, - .count = 7, - .endpoint = 0x81, - .u = { - .bulk = { - .buffersize = 512, - } - } - }, - }}, - } }, - .i2c_algo = &gl861_i2c_algo, - - .num_device_descs = 2, - .devices = { + .adapter = { { - .name = "MSI Mega Sky 55801 DVB-T USB2.0", - .cold_ids = { NULL }, - .warm_ids = { &gl861_table[0], NULL }, - }, - { - .name = "A-LINK DTU DVB-T USB2.0", - .cold_ids = { NULL }, - .warm_ids = { &gl861_table[1], NULL }, - }, + .stream = DVB_USB_STREAM_BULK(0x81, 7, 512), + } } }; -static struct usb_driver gl861_driver = { - .name = "dvb_usb_gl861", - .probe = gl861_probe, - .disconnect = dvb_usb_device_exit, - .id_table = gl861_table, +static const struct usb_device_id gl861_id_table[] = { + { DVB_USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801, + &gl861_props, "MSI Mega Sky 55801 DVB-T USB2.0", NULL) }, + { DVB_USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU, + &gl861_props, "A-LINK DTU DVB-T USB2.0", NULL) }, + { } +}; +MODULE_DEVICE_TABLE(usb, gl861_id_table); + +static struct usb_driver gl861_usb_driver = { + .name = KBUILD_MODNAME, + .id_table = gl861_id_table, + .probe = dvb_usbv2_probe, + .disconnect = dvb_usbv2_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, }; -module_usb_driver(gl861_driver); +module_usb_driver(gl861_usb_driver); MODULE_AUTHOR("Carl Lundqvist "); MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861"); diff --git a/drivers/media/dvb/dvb-usb/gl861.h b/drivers/media/dvb/dvb-usb/gl861.h index c54855e2c233..b0b80d87bb7e 100644 --- a/drivers/media/dvb/dvb-usb/gl861.h +++ b/drivers/media/dvb/dvb-usb/gl861.h @@ -1,10 +1,7 @@ #ifndef _DVB_USB_GL861_H_ #define _DVB_USB_GL861_H_ -#define DVB_USB_LOG_PREFIX "gl861" -#include "dvb-usb.h" - -#define deb_rc(args...) dprintk(dvb_usb_gl861_debug, 0x01, args) +#include "dvb_usb.h" #define GL861_WRITE 0x40 #define GL861_READ 0xc0 From ad6b9e517b39acec98862e7f9bddefe1b275445b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 9 Jul 2012 14:59:28 -0300 Subject: [PATCH 0311/5375] [media] dvb_usb_v2: move from dvb-usb to dvb-usb-v2 Move to own directory. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/Kconfig | 1 + drivers/media/dvb/Makefile | 1 + drivers/media/dvb/dvb-usb-v2/Kconfig | 104 ++++++++++++++++++ drivers/media/dvb/dvb-usb-v2/Makefile | 35 ++++++ .../dvb/{dvb-usb => dvb-usb-v2}/af9015.c | 0 .../dvb/{dvb-usb => dvb-usb-v2}/af9015.h | 0 .../dvb/{dvb-usb => dvb-usb-v2}/af9035.c | 0 .../dvb/{dvb-usb => dvb-usb-v2}/af9035.h | 0 .../dvb/{dvb-usb => dvb-usb-v2}/anysee.c | 0 .../dvb/{dvb-usb => dvb-usb-v2}/anysee.h | 0 .../dvb/{dvb-usb => dvb-usb-v2}/au6610.c | 0 .../dvb/{dvb-usb => dvb-usb-v2}/au6610.h | 0 .../dvb/{dvb-usb => dvb-usb-v2}/ce6230.c | 0 .../dvb/{dvb-usb => dvb-usb-v2}/ce6230.h | 0 .../dvb/{dvb-usb => dvb-usb-v2}/dvb_usb.h | 2 +- .../{dvb-usb => dvb-usb-v2}/dvb_usb_common.h | 0 .../{dvb-usb => dvb-usb-v2}/dvb_usb_core.c | 0 .../dvb_usb_firmware.c | 0 .../dvb_usb_firmware.h | 0 .../dvb/{dvb-usb => dvb-usb-v2}/dvb_usb_urb.c | 0 .../media/dvb/{dvb-usb => dvb-usb-v2}/ec168.c | 0 .../media/dvb/{dvb-usb => dvb-usb-v2}/ec168.h | 0 .../media/dvb/{dvb-usb => dvb-usb-v2}/gl861.c | 0 .../media/dvb/{dvb-usb => dvb-usb-v2}/gl861.h | 0 .../{dvb-usb => dvb-usb-v2}/mxl111sf-demod.c | 0 .../{dvb-usb => dvb-usb-v2}/mxl111sf-demod.h | 0 .../{dvb-usb => dvb-usb-v2}/mxl111sf-gpio.c | 0 .../{dvb-usb => dvb-usb-v2}/mxl111sf-gpio.h | 0 .../{dvb-usb => dvb-usb-v2}/mxl111sf-i2c.c | 0 .../{dvb-usb => dvb-usb-v2}/mxl111sf-i2c.h | 0 .../{dvb-usb => dvb-usb-v2}/mxl111sf-phy.c | 0 .../{dvb-usb => dvb-usb-v2}/mxl111sf-phy.h | 0 .../{dvb-usb => dvb-usb-v2}/mxl111sf-reg.h | 0 .../{dvb-usb => dvb-usb-v2}/mxl111sf-tuner.c | 0 .../{dvb-usb => dvb-usb-v2}/mxl111sf-tuner.h | 0 .../dvb/{dvb-usb => dvb-usb-v2}/mxl111sf.c | 0 .../dvb/{dvb-usb => dvb-usb-v2}/mxl111sf.h | 0 .../dvb/{dvb-usb => dvb-usb-v2}/usb_urb.c | 0 drivers/media/dvb/dvb-usb/Kconfig | 104 ------------------ drivers/media/dvb/dvb-usb/Makefile | 31 ------ 40 files changed, 142 insertions(+), 136 deletions(-) create mode 100644 drivers/media/dvb/dvb-usb-v2/Kconfig create mode 100644 drivers/media/dvb/dvb-usb-v2/Makefile rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/af9015.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/af9015.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/af9035.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/af9035.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/anysee.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/anysee.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/au6610.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/au6610.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/ce6230.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/ce6230.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/dvb_usb.h (99%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/dvb_usb_common.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/dvb_usb_core.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/dvb_usb_firmware.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/dvb_usb_firmware.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/dvb_usb_urb.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/ec168.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/ec168.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/gl861.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/gl861.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf-demod.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf-demod.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf-gpio.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf-gpio.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf-i2c.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf-i2c.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf-phy.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf-phy.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf-reg.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf-tuner.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf-tuner.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf.c (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/mxl111sf.h (100%) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/usb_urb.c (100%) diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index f6e40b3a44cc..3a6ccbc02add 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -44,6 +44,7 @@ source "drivers/media/dvb/ttpci/Kconfig" comment "Supported USB Adapters" depends on DVB_CORE && USB && I2C source "drivers/media/dvb/dvb-usb/Kconfig" +source "drivers/media/dvb/dvb-usb-v2/Kconfig" source "drivers/media/dvb/ttusb-budget/Kconfig" source "drivers/media/dvb/ttusb-dec/Kconfig" source "drivers/media/dvb/siano/Kconfig" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index b2cefe637a64..8f7e0129d70e 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -10,6 +10,7 @@ obj-y := dvb-core/ \ b2c2/ \ bt8xx/ \ dvb-usb/ \ + dvb-usb-v2/ \ pluto2/ \ siano/ \ dm1105/ \ diff --git a/drivers/media/dvb/dvb-usb-v2/Kconfig b/drivers/media/dvb/dvb-usb-v2/Kconfig new file mode 100644 index 000000000000..bef2ffa18130 --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/Kconfig @@ -0,0 +1,104 @@ +config DVB_USB_V2 + tristate "Support for various USB DVB devices v2" + depends on DVB_CORE && USB && I2C && RC_CORE + help + By enabling this you will be able to choose the various supported + USB1.1 and USB2.0 DVB devices. + + Almost every USB device needs a firmware, please look into + . + + For a complete list of supported USB devices see the LinuxTV DVB Wiki: + + + Say Y if you own a USB DVB device. + +config DVB_USB_FIRMWARE + tristate "Firmware helper routines" + depends on DVB_USB_V2 + +config DVB_USB_AF9015 + tristate "Afatech AF9015 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_AF9013 + select DVB_PLL if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver + +config DVB_USB_AF9035 + tristate "Afatech AF9035 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_AF9033 + select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Afatech AF9035 based DVB USB receiver. + +config DVB_USB_ANYSEE + tristate "Anysee DVB-T/C USB2.0 support" + depends on DVB_USB_V2 + select DVB_PLL if !DVB_FE_CUSTOMISE + select DVB_MT352 if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_STV0900 if !DVB_FE_CUSTOMISE + select DVB_STV6110 if !DVB_FE_CUSTOMISE + select DVB_ISL6423 if !DVB_FE_CUSTOMISE + select DVB_CXD2820R if !DVB_FE_CUSTOMISE + help + Say Y here to support the Anysee E30, Anysee E30 Plus or + Anysee E30 C Plus DVB USB2.0 receiver. + +config DVB_USB_AU6610 + tristate "Alcor Micro AU6610 USB2.0 support" + depends on DVB_USB_V2 + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. + +config DVB_USB_CE6230 + tristate "Intel CE6230 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_ZL10353 + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver + +config DVB_USB_EC168 + tristate "E3C EC168 DVB-T USB2.0 support" + depends on DVB_USB_V2 + select DVB_EC100 + select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. + +config DVB_USB_GL861 + tristate "Genesys Logic GL861 USB2.0 support" + depends on DVB_USB_V2 + select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE + help + Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 + receiver with USB ID 0db0:5581. + +config DVB_USB_MXL111SF + tristate "MxL111SF DTV USB2.0 support" + depends on DVB_USB_V2 + select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select DVB_LG2160 if !DVB_FE_CUSTOMISE + select VIDEO_TVEEPROM + help + Say Y here to support the MxL111SF USB2.0 DTV receiver. + diff --git a/drivers/media/dvb/dvb-usb-v2/Makefile b/drivers/media/dvb/dvb-usb-v2/Makefile new file mode 100644 index 000000000000..6080ec89577f --- /dev/null +++ b/drivers/media/dvb/dvb-usb-v2/Makefile @@ -0,0 +1,35 @@ +dvb_usbv2-objs = dvb_usb_core.o dvb_usb_urb.o usb_urb.o +obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o + +obj-$(CONFIG_DVB_USB_FIRMWARE) += dvb_usb_firmware.o + +dvb-usb-af9015-objs = af9015.o +obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o + +dvb-usb-af9035-objs = af9035.o +obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o + +dvb-usb-anysee-objs = anysee.o +obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o + +dvb-usb-au6610-objs = au6610.o +obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o + +dvb-usb-ce6230-objs = ce6230.o +obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o + +dvb-usb-ec168-objs = ec168.o +obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o + +dvb-usb-gl861-objs = gl861.o +obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o + +dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o +obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o +obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o +obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o + +ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core +ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/ +ccflags-y += -I$(srctree)/drivers/media/common/tuners + diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb-v2/af9015.c similarity index 100% rename from drivers/media/dvb/dvb-usb/af9015.c rename to drivers/media/dvb/dvb-usb-v2/af9015.c diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb-v2/af9015.h similarity index 100% rename from drivers/media/dvb/dvb-usb/af9015.h rename to drivers/media/dvb/dvb-usb-v2/af9015.h diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb-v2/af9035.c similarity index 100% rename from drivers/media/dvb/dvb-usb/af9035.c rename to drivers/media/dvb/dvb-usb-v2/af9035.c diff --git a/drivers/media/dvb/dvb-usb/af9035.h b/drivers/media/dvb/dvb-usb-v2/af9035.h similarity index 100% rename from drivers/media/dvb/dvb-usb/af9035.h rename to drivers/media/dvb/dvb-usb-v2/af9035.h diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb-v2/anysee.c similarity index 100% rename from drivers/media/dvb/dvb-usb/anysee.c rename to drivers/media/dvb/dvb-usb-v2/anysee.c diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb-v2/anysee.h similarity index 100% rename from drivers/media/dvb/dvb-usb/anysee.h rename to drivers/media/dvb/dvb-usb-v2/anysee.h diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb-v2/au6610.c similarity index 100% rename from drivers/media/dvb/dvb-usb/au6610.c rename to drivers/media/dvb/dvb-usb-v2/au6610.c diff --git a/drivers/media/dvb/dvb-usb/au6610.h b/drivers/media/dvb/dvb-usb-v2/au6610.h similarity index 100% rename from drivers/media/dvb/dvb-usb/au6610.h rename to drivers/media/dvb/dvb-usb-v2/au6610.h diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb-v2/ce6230.c similarity index 100% rename from drivers/media/dvb/dvb-usb/ce6230.c rename to drivers/media/dvb/dvb-usb-v2/ce6230.c diff --git a/drivers/media/dvb/dvb-usb/ce6230.h b/drivers/media/dvb/dvb-usb-v2/ce6230.h similarity index 100% rename from drivers/media/dvb/dvb-usb/ce6230.h rename to drivers/media/dvb/dvb-usb-v2/ce6230.h diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb-v2/dvb_usb.h similarity index 99% rename from drivers/media/dvb/dvb-usb/dvb_usb.h rename to drivers/media/dvb/dvb-usb-v2/dvb_usb.h index 773817b5fe06..4db591be646c 100644 --- a/drivers/media/dvb/dvb-usb/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb-v2/dvb_usb.h @@ -30,7 +30,7 @@ #include "dvb_demux.h" #include "dvb_net.h" #include "dmxdev.h" -#include "dvb-usb-ids.h" +#include "../dvb-usb/dvb-usb-ids.h" /* * device file: /dev/dvb/adapter[0-1]/frontend[0-2] diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_common.h b/drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h similarity index 100% rename from drivers/media/dvb/dvb-usb/dvb_usb_common.h rename to drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_core.c b/drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c similarity index 100% rename from drivers/media/dvb/dvb-usb/dvb_usb_core.c rename to drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.c similarity index 100% rename from drivers/media/dvb/dvb-usb/dvb_usb_firmware.c rename to drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.c diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_firmware.h b/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.h similarity index 100% rename from drivers/media/dvb/dvb-usb/dvb_usb_firmware.h rename to drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.h diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c similarity index 100% rename from drivers/media/dvb/dvb-usb/dvb_usb_urb.c rename to drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb-v2/ec168.c similarity index 100% rename from drivers/media/dvb/dvb-usb/ec168.c rename to drivers/media/dvb/dvb-usb-v2/ec168.c diff --git a/drivers/media/dvb/dvb-usb/ec168.h b/drivers/media/dvb/dvb-usb-v2/ec168.h similarity index 100% rename from drivers/media/dvb/dvb-usb/ec168.h rename to drivers/media/dvb/dvb-usb-v2/ec168.h diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb-v2/gl861.c similarity index 100% rename from drivers/media/dvb/dvb-usb/gl861.c rename to drivers/media/dvb/dvb-usb-v2/gl861.c diff --git a/drivers/media/dvb/dvb-usb/gl861.h b/drivers/media/dvb/dvb-usb-v2/gl861.h similarity index 100% rename from drivers/media/dvb/dvb-usb/gl861.h rename to drivers/media/dvb/dvb-usb-v2/gl861.h diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.c similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf-demod.c rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.c diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.h similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf-demod.h rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.h diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.c similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf-gpio.c rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.c diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-gpio.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.h similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf-gpio.h rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.h diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.c similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf-i2c.c rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.c diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.h similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf-i2c.h rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.h diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.c similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf-phy.c rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.c diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.h similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf-phy.h rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.h diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-reg.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-reg.h similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf-reg.h rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-reg.h diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf-tuner.c rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.h similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf-tuner.h rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.h diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf.c similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf.c rename to drivers/media/dvb/dvb-usb-v2/mxl111sf.c diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.h b/drivers/media/dvb/dvb-usb-v2/mxl111sf.h similarity index 100% rename from drivers/media/dvb/dvb-usb/mxl111sf.h rename to drivers/media/dvb/dvb-usb-v2/mxl111sf.h diff --git a/drivers/media/dvb/dvb-usb/usb_urb.c b/drivers/media/dvb/dvb-usb-v2/usb_urb.c similarity index 100% rename from drivers/media/dvb/dvb-usb/usb_urb.c rename to drivers/media/dvb/dvb-usb-v2/usb_urb.c diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 09fded4eb0b4..67b91b74976f 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -13,25 +13,6 @@ config DVB_USB Say Y if you own a USB DVB device. -config DVB_USB_V2 - tristate "Support for various USB DVB devices v2" - depends on DVB_CORE && USB && I2C && RC_CORE - help - By enabling this you will be able to choose the various supported - USB1.1 and USB2.0 DVB devices. - - Almost every USB device needs a firmware, please look into - . - - For a complete list of supported USB devices see the LinuxTV DVB Wiki: - - - Say Y if you own a USB DVB device. - -config DVB_USB_FIRMWARE - tristate "Firmware helper routines" - depends on DVB_USB - config DVB_USB_DEBUG bool "Enable extended debug support for all DVB-USB devices" depends on DVB_USB @@ -162,23 +143,6 @@ config DVB_USB_M920X "DTV USB MINI" (in cold state) are supported. Firmware required. -config DVB_USB_GL861 - tristate "Genesys Logic GL861 USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 - receiver with USB ID 0db0:5581. - -config DVB_USB_AU6610 - tristate "Alcor Micro AU6610 USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. - config DVB_USB_DIGITV tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" depends on DVB_USB @@ -318,23 +282,6 @@ config DVB_USB_CINERGY_T2 Say Y if you own such a device and want to use it. -config DVB_USB_ANYSEE - tristate "Anysee DVB-T/C USB2.0 support" - depends on DVB_USB_V2 - select DVB_PLL if !DVB_FE_CUSTOMISE - select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TDA10023 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE - select DVB_CX24116 if !DVB_FE_CUSTOMISE - select DVB_STV0900 if !DVB_FE_CUSTOMISE - select DVB_STV6110 if !DVB_FE_CUSTOMISE - select DVB_ISL6423 if !DVB_FE_CUSTOMISE - select DVB_CXD2820R if !DVB_FE_CUSTOMISE - help - Say Y here to support the Anysee E30, Anysee E30 Plus or - Anysee E30 C Plus DVB USB2.0 receiver. - config DVB_USB_DTV5100 tristate "AME DTV-5100 USB2.0 DVB-T support" depends on DVB_USB @@ -343,43 +290,12 @@ config DVB_USB_DTV5100 help Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. -config DVB_USB_AF9015 - tristate "Afatech AF9015 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_AF9013 - select DVB_PLL if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver - -config DVB_USB_CE6230 - tristate "Intel CE6230 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver - config DVB_USB_FRIIO tristate "Friio ISDB-T USB2.0 Receiver support" depends on DVB_USB help Say Y here to support the Japanese DTV receiver Friio. -config DVB_USB_EC168 - tristate "E3C EC168 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_EC100 - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. - config DVB_USB_AZ6007 tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" depends on DVB_USB @@ -424,15 +340,6 @@ config DVB_USB_IT913X help Say Y here to support the it913x device -config DVB_USB_MXL111SF - tristate "MxL111SF DTV USB2.0 support" - depends on DVB_USB_V2 - select DVB_LGDT3305 if !DVB_FE_CUSTOMISE - select DVB_LG2160 if !DVB_FE_CUSTOMISE - select VIDEO_TVEEPROM - help - Say Y here to support the MxL111SF USB2.0 DTV receiver. - config DVB_USB_RTL28XXU tristate "Realtek RTL28xxU DVB USB support" depends on DVB_USB && EXPERIMENTAL @@ -446,14 +353,3 @@ config DVB_USB_RTL28XXU help Say Y here to support the Realtek RTL28xxU DVB USB receiver. -config DVB_USB_AF9035 - tristate "Afatech AF9035 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_AF9033 - select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE - help - Say Y here to support the Afatech AF9035 based DVB USB receiver. - diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 50f506e0632a..29fa0f0637e5 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -1,11 +1,6 @@ dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o obj-$(CONFIG_DVB_USB) += dvb-usb.o -dvb_usbv2-objs = dvb_usb_core.o dvb_usb_urb.o usb_urb.o -obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o - -obj-$(CONFIG_DVB_USB_FIRMWARE) += dvb_usb_firmware.o - dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o @@ -38,12 +33,6 @@ obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o dvb-usb-m920x-objs = m920x.o obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o -dvb-usb-gl861-objs = gl861.o -obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o - -dvb-usb-au6610-objs = au6610.o -obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o - dvb-usb-digitv-objs = digitv.o obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o @@ -65,9 +54,6 @@ obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o dvb-usb-af9005-remote-objs = af9005-remote.o obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o -dvb-usb-anysee-objs = anysee.o -obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o - dvb-usb-pctv452e-objs = pctv452e.o obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o @@ -77,21 +63,12 @@ obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o dvb-usb-dtv5100-objs = dtv5100.o obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o -dvb-usb-af9015-objs = af9015.o -obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o - dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o -dvb-usb-ce6230-objs = ce6230.o -obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o - dvb-usb-friio-objs = friio.o friio-fe.o obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o -dvb-usb-ec168-objs = ec168.o -obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o - dvb-usb-az6007-objs = az6007.o obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o @@ -107,17 +84,9 @@ obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o dvb-usb-it913x-objs := it913x.o obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o -dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o -obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o -obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o -obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o - dvb-usb-rtl28xxu-objs = rtl28xxu.o obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o -dvb-usb-af9035-objs = af9035.o -obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o - ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/ # due to tuner-xc3028 From eb29fbeaed617f7a2cf53d276535f8fbdc28db09 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 24 Jul 2012 21:21:04 -0300 Subject: [PATCH 0312/5375] [media] af9015: remote controller fixes 1) AF9015 remote controller query will fail rarely due to register access failures and dvb_usb_v2 will stop rc polling when error returned. Add logic to allow errors until two consecutive errors occurs. 2) Remote controller key map was not loaded in case of key map was set as a device property. Fix it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb-v2/af9015.c | 15 ++++++++++++--- drivers/media/dvb/dvb-usb-v2/af9015.h | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb/dvb-usb-v2/af9015.c b/drivers/media/dvb/dvb-usb-v2/af9015.c index bbe1d3382195..10363f6b5234 100644 --- a/drivers/media/dvb/dvb-usb-v2/af9015.c +++ b/drivers/media/dvb/dvb-usb-v2/af9015.c @@ -1232,11 +1232,19 @@ static int af9015_rc_query(struct dvb_usb_device *d) } state->rc_repeat = buf[6]; + state->rc_failed = false; error: - if (ret) + if (ret) { err("%s: failed:%d", __func__, ret); + /* allow random errors as dvb-usb will stop polling on error */ + if (!state->rc_failed) + ret = 0; + + state->rc_failed = true; + } + return ret; } @@ -1249,8 +1257,9 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) return 0; /* try to load remote based module param */ - rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote, - af9015_rc_setup_modparam); + if (!rc->map_name) + rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote, + af9015_rc_setup_modparam); /* try to load remote based eeprom hash */ if (!rc->map_name) diff --git a/drivers/media/dvb/dvb-usb-v2/af9015.h b/drivers/media/dvb/dvb-usb-v2/af9015.h index b41ee73b26dc..c6b304d962ad 100644 --- a/drivers/media/dvb/dvb-usb-v2/af9015.h +++ b/drivers/media/dvb/dvb-usb-v2/af9015.h @@ -139,6 +139,7 @@ struct af9015_state { u8 rc_repeat; u32 rc_keycode; u8 rc_last[4]; + bool rc_failed; u8 dual_mode; u8 seq; /* packet sequence number */ u16 mt2060_if1[2]; From 355b4b2b5e83986132c77326e2b97780480b8d69 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 1 Aug 2012 21:38:46 -0300 Subject: [PATCH 0313/5375] [media] dvb_usbv2: rename dvb_usb_firmware to cypress_firmware Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb-v2/Kconfig | 12 ++++++++++-- drivers/media/dvb/dvb-usb-v2/Makefile | 2 +- .../{dvb_usb_firmware.c => cypress_firmware.c} | 4 ++-- .../{dvb_usb_firmware.h => cypress_firmware.h} | 6 +++--- 4 files changed, 16 insertions(+), 8 deletions(-) rename drivers/media/dvb/dvb-usb-v2/{dvb_usb_firmware.c => cypress_firmware.c} (97%) rename drivers/media/dvb/dvb-usb-v2/{dvb_usb_firmware.h => cypress_firmware.h} (85%) diff --git a/drivers/media/dvb/dvb-usb-v2/Kconfig b/drivers/media/dvb/dvb-usb-v2/Kconfig index bef2ffa18130..81f0f1c03c1c 100644 --- a/drivers/media/dvb/dvb-usb-v2/Kconfig +++ b/drivers/media/dvb/dvb-usb-v2/Kconfig @@ -13,9 +13,17 @@ config DVB_USB_V2 Say Y if you own a USB DVB device. -config DVB_USB_FIRMWARE - tristate "Firmware helper routines" +config DVB_USB_CYPRESS_FIRMWARE + tristate "Cypress firmware helper routines" depends on DVB_USB_V2 + help + Common firmware download routine for various Cypress USB interface + chips. + + Supported models are: + Cypress AN2135 + Cypress AN2235 + Cypress FX2 config DVB_USB_AF9015 tristate "Afatech AF9015 DVB-T USB2.0 support" diff --git a/drivers/media/dvb/dvb-usb-v2/Makefile b/drivers/media/dvb/dvb-usb-v2/Makefile index 6080ec89577f..a98319cd216e 100644 --- a/drivers/media/dvb/dvb-usb-v2/Makefile +++ b/drivers/media/dvb/dvb-usb-v2/Makefile @@ -1,7 +1,7 @@ dvb_usbv2-objs = dvb_usb_core.o dvb_usb_urb.o usb_urb.o obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o -obj-$(CONFIG_DVB_USB_FIRMWARE) += dvb_usb_firmware.o +obj-$(DVB_USB_CYPRESS_FIRMWARE) += dvb_usb_cypress_firmware.o dvb-usb-af9015-objs = af9015.o obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.c b/drivers/media/dvb/dvb-usb-v2/cypress_firmware.c similarity index 97% rename from drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.c rename to drivers/media/dvb/dvb-usb-v2/cypress_firmware.c index 61c3fe9a599e..9f7c970c6424 100644 --- a/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.c +++ b/drivers/media/dvb/dvb-usb-v2/cypress_firmware.c @@ -1,4 +1,4 @@ -/* dvb_usb_firmware.c is part of the DVB USB library. +/* cypress_firmware.c is part of the DVB USB library. * * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) * see dvb-usb-init.c for copyright information. @@ -9,7 +9,7 @@ */ #include "dvb_usb.h" -#include "dvb_usb_firmware.h" +#include "cypress_firmware.h" struct usb_cypress_controller { u8 id; diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.h b/drivers/media/dvb/dvb-usb-v2/cypress_firmware.h similarity index 85% rename from drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.h rename to drivers/media/dvb/dvb-usb-v2/cypress_firmware.h index 358d9d0b1899..80085fd4132c 100644 --- a/drivers/media/dvb/dvb-usb-v2/dvb_usb_firmware.h +++ b/drivers/media/dvb/dvb-usb-v2/cypress_firmware.h @@ -1,4 +1,4 @@ -/* dvb_usb_firmware.c is part of the DVB USB library. +/* cypress_firmware.h is part of the DVB USB library. * * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) * see dvb-usb-init.c for copyright information. @@ -8,8 +8,8 @@ * */ -#ifndef DVB_USB_FIRMWARE_H -#define DVB_USB_FIRMWARE_H +#ifndef CYPRESS_FIRMWARE_H +#define CYPRESS_FIRMWARE_H #define CYPRESS_AN2135 0 #define CYPRESS_AN2235 1 From a0f1e98b34f22bb4055aebfc528bc9080b259f8f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 31 Jul 2012 18:34:07 +0100 Subject: [PATCH 0314/5375] ASoC: imx-ssi: Say if we fail to register a second AC'97 bus Saves anyone wondering what happened if they run into this error. Signed-off-by: Mark Brown --- sound/soc/fsl/imx-ssi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index e174c1767c2d..3c520c46fa4a 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -560,6 +560,7 @@ static int imx_ssi_probe(struct platform_device *pdev) if (ssi->flags & IMX_SSI_USE_AC97) { if (ac97_ssi) { + dev_err(&pdev->dev, "AC'97 SSI already registered\n"); ret = -EBUSY; goto failed_register; } From a384f6411734e763daa4bae30e8ff170d7d4c3e2 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Thu, 19 Jul 2012 15:47:11 -0700 Subject: [PATCH 0315/5375] pstore/ram: Fix possible NULL dereference We can dereference 'cxt->cprz' if console and dump logging are disabled (which is unlikely, but still possible to do). This patch fixes the issue by changing the code so that we don't dereference przs at all, we can just calculate bufsize from console_size and record_size values. Plus, while at it, the patch improves the buffer size calculation. After Kay's printk rework, we know the optimal buffer size for console logging -- it is LOG_LINE_MAX (defined privately in printk.c). Previously, if only console logging was enabled, we would allocate unnecessary large buffer in pstore, while we only need LOG_LINE_MAX. (Pstore console logging is still capable of handling buffers > LOG_LINE_MAX, it will just do multiple calls to psinfo->write). Note that I don't export the constant, since we will do even a better thing soon: we will switch console logging to a new write_buf API, which will eliminate the need for the additional buffer; and so we won't need the constant. Reported-by: Dan Carpenter Signed-off-by: Anton Vorontsov Acked-by: Kees Cook --- fs/pstore/ram.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 0b311bc18916..bcd1bbd42598 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -414,13 +414,14 @@ static int __devinit ramoops_probe(struct platform_device *pdev) cxt->pstore.data = cxt; /* - * Console can handle any buffer size, so prefer dumps buffer - * size since usually it is smaller. + * Console can handle any buffer size, so prefer LOG_LINE_MAX. If we + * have to handle dumps, we must have at least record_size buffer. And + * for ftrace, bufsize is irrelevant (if bufsize is 0, buf will be + * ZERO_SIZE_PTR). */ - if (cxt->przs) - cxt->pstore.bufsize = cxt->przs[0]->buffer_size; - else - cxt->pstore.bufsize = cxt->cprz->buffer_size; + if (cxt->console_size) + cxt->pstore.bufsize = 1024; /* LOG_LINE_MAX */ + cxt->pstore.bufsize = max(cxt->record_size, cxt->pstore.bufsize); cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL); spin_lock_init(&cxt->pstore.buf_lock); if (!cxt->pstore.buf) { From 0427193b691edc81c846c7d0ebd2561cae8709d8 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 3 Aug 2012 17:02:48 -0700 Subject: [PATCH 0316/5375] pstore/ram: Fix printk format warning Fix printk format warning (on i386) in pstore: fs/pstore/ram.c:409:3: warning: format '%lu' expects type 'long unsigned int', but argument 2 has type 'size_t' Signed-off-by: Randy Dunlap Acked-by: Kees Cook Signed-off-by: Anton Vorontsov --- fs/pstore/ram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index bcd1bbd42598..fba8c7256929 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -406,7 +406,7 @@ static int __devinit ramoops_probe(struct platform_device *pdev) goto fail_init_fprz; if (!cxt->przs && !cxt->cprz && !cxt->fprz) { - pr_err("memory size too small, minimum is %lu\n", + pr_err("memory size too small, minimum is %zu\n", cxt->console_size + cxt->record_size + cxt->ftrace_size); goto fail_cnt; From 242030365eacb649161023a3a024373198c34d59 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 17 Jul 2012 19:49:37 -0700 Subject: [PATCH 0317/5375] pstore/ram: Mark ramoops_pstore_write_buf() as notrace write_buf() should be marked as notrace, otherwise it is prone to recursion. Though, yet the issue is never triggered in real life, because we run inside the function tracer, where ftrace does its own recurse protection. But it's still no good, plus soon we might switch to our own tracer ops, and then the issue will be fatal. So, let's fix it. Signed-off-by: Anton Vorontsov --- fs/pstore/ram.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index fba8c7256929..91016049e551 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #define RAMOOPS_KERNMSG_HDR "====" @@ -181,12 +182,11 @@ static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) return len; } - -static int ramoops_pstore_write_buf(enum pstore_type_id type, - enum kmsg_dump_reason reason, - u64 *id, unsigned int part, - const char *buf, size_t size, - struct pstore_info *psi) +static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, + enum kmsg_dump_reason reason, + u64 *id, unsigned int part, + const char *buf, size_t size, + struct pstore_info *psi) { struct ramoops_context *cxt = psi->data; struct persistent_ram_zone *prz = cxt->przs[cxt->dump_write_cnt]; From ccc0e3483c2447fd14d4fb9ba2a77da628322815 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 5 Aug 2012 19:50:15 -0300 Subject: [PATCH 0318/5375] [media] move dvb-usb-ids.h to dvb-core While this header were meant to be used just by dvb-usb driver, it is now being used also by dvb-usb-v2 and cx231xx. So, move it to a better place. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/{dvb-usb => dvb-core}/dvb-usb-ids.h | 0 drivers/media/dvb/dvb-usb-v2/dvb_usb.h | 2 +- drivers/media/dvb/dvb-usb/Makefile | 1 - drivers/media/video/cx231xx/Makefile | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) rename drivers/media/dvb/{dvb-usb => dvb-core}/dvb-usb-ids.h (100%) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-core/dvb-usb-ids.h similarity index 100% rename from drivers/media/dvb/dvb-usb/dvb-usb-ids.h rename to drivers/media/dvb/dvb-core/dvb-usb-ids.h diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb.h b/drivers/media/dvb/dvb-usb-v2/dvb_usb.h index 4db591be646c..773817b5fe06 100644 --- a/drivers/media/dvb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/dvb/dvb-usb-v2/dvb_usb.h @@ -30,7 +30,7 @@ #include "dvb_demux.h" #include "dvb_net.h" #include "dmxdev.h" -#include "../dvb-usb/dvb-usb-ids.h" +#include "dvb-usb-ids.h" /* * device file: /dev/dvb/adapter[0-1]/frontend[0-2] diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 29fa0f0637e5..4b70599b38d9 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -92,4 +92,3 @@ ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/ # due to tuner-xc3028 ccflags-y += -I$(srctree)/drivers/media/common/tuners ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci - diff --git a/drivers/media/video/cx231xx/Makefile b/drivers/media/video/cx231xx/Makefile index b3348975c7c2..cb06b022e011 100644 --- a/drivers/media/video/cx231xx/Makefile +++ b/drivers/media/video/cx231xx/Makefile @@ -12,5 +12,4 @@ ccflags-y += -Idrivers/media/video ccflags-y += -Idrivers/media/common/tuners ccflags-y += -Idrivers/media/dvb/dvb-core ccflags-y += -Idrivers/media/dvb/frontends -ccflags-y += -Idrivers/media/dvb/dvb-usb From 59dfc97c819a6d25e1000c2daf9d84f32c35e1a5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 6 Aug 2012 01:43:19 -0300 Subject: [PATCH 0319/5375] ARM: mxs_defconfig: Enable USB host Enable USB host. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/configs/mxs_defconfig | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index ccdb6357fb74..e3487e491f9a 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -95,7 +95,6 @@ CONFIG_GPIO_SYSFS=y # CONFIG_MFD_SUPPORT is not set CONFIG_DISPLAY_SUPPORT=m # CONFIG_HID_SUPPORT is not set -# CONFIG_USB_SUPPORT is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_TIMER=y @@ -110,6 +109,13 @@ CONFIG_SND_SOC_I2C_AND_SPI=y CONFIG_SND_SOC_SGTL5000=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_USB=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_STORAGE=y +CONFIG_USB_MXS_PHY=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y CONFIG_MMC=y CONFIG_MMC_MXS=y CONFIG_RTC_CLASS=y From 793ea49c476ebacfefabf78af9ea88a19da6ecdb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Aug 2012 16:52:41 +0300 Subject: [PATCH 0320/5375] ALSA: print small buffers via %*ph[C] Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/isa/gus/interwave.c | 5 ++--- sound/usb/6fire/firmware.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index a76bc8d27c1d..3fc8b66fd167 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -443,9 +443,8 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus) for (i = 0; i < 8; ++i) iwave[i] = snd_gf1_peek(gus, bank_pos + i); #ifdef CONFIG_SND_DEBUG_ROM - printk(KERN_DEBUG "ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos, - iwave[0], iwave[1], iwave[2], iwave[3], - iwave[4], iwave[5], iwave[6], iwave[7]); + printk(KERN_DEBUG "ROM at 0x%06x = %*phC\n", bank_pos, + 8, iwave); #endif if (strncmp(iwave, "INTRWAVE", 8)) continue; /* first check */ diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 56ad923bf6b5..a1d9b0792a1e 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -346,11 +346,10 @@ static int usb6fire_fw_check(u8 *version) if (!memcmp(version, known_fw_versions + i, 4)) return 0; - snd_printk(KERN_ERR PREFIX "invalid fimware version in device: " - "%02x %02x %02x %02x. " + snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %*ph. " "please reconnect to power. if this failure " "still happens, check your firmware installation.", - version[0], version[1], version[2], version[3]); + 4, version); return -EINVAL; } From aab2eb7a38e0e510874acca01838f5badbca6c7e Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Wed, 1 Aug 2012 18:01:10 +0900 Subject: [PATCH 0321/5375] KVM: Stop checking rmap to see if slot is being created Instead, check npages consistently. This helps to make rmap architecture specific in a later patch. Signed-off-by: Takuya Yoshikawa Signed-off-by: Avi Kivity --- arch/x86/kvm/x86.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3ca90d74711d..abc039d78428 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6385,7 +6385,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, *x86 needs to handle !user_alloc case. */ if (!user_alloc) { - if (npages && !old.rmap) { + if (npages && !old.npages) { unsigned long userspace_addr; userspace_addr = vm_mmap(NULL, 0, @@ -6413,7 +6413,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, int nr_mmu_pages = 0, npages = mem->memory_size >> PAGE_SHIFT; - if (!user_alloc && !old.user_alloc && old.rmap && !npages) { + if (!user_alloc && !old.user_alloc && old.npages && !npages) { int ret; ret = vm_munmap(old.userspace_addr, From 65fbe37c42ed75604c9a770639209dcee162ebe7 Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Wed, 1 Aug 2012 18:02:01 +0900 Subject: [PATCH 0322/5375] KVM: MMU: Use gfn_to_rmap() instead of directly reading rmap array This helps to make rmap architecture specific in a later patch. Signed-off-by: Takuya Yoshikawa Signed-off-by: Avi Kivity --- arch/x86/kvm/mmu.c | 3 ++- arch/x86/kvm/mmu_audit.c | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index a9a20528e700..ee768bb2367f 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1181,7 +1181,8 @@ void kvm_mmu_write_protect_pt_masked(struct kvm *kvm, unsigned long *rmapp; while (mask) { - rmapp = &slot->rmap[gfn_offset + __ffs(mask)]; + rmapp = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask), + PT_PAGE_TABLE_LEVEL, slot); __rmap_write_protect(kvm, rmapp, PT_PAGE_TABLE_LEVEL, false); /* clear the first set bit */ diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c index 7d7d0b9e23eb..ca403f9bb0f2 100644 --- a/arch/x86/kvm/mmu_audit.c +++ b/arch/x86/kvm/mmu_audit.c @@ -190,7 +190,6 @@ static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp) static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp) { - struct kvm_memory_slot *slot; unsigned long *rmapp; u64 *sptep; struct rmap_iterator iter; @@ -198,8 +197,7 @@ static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp) if (sp->role.direct || sp->unsync || sp->role.invalid) return; - slot = gfn_to_memslot(kvm, sp->gfn); - rmapp = &slot->rmap[sp->gfn - slot->base_gfn]; + rmapp = gfn_to_rmap(kvm, sp->gfn, PT_PAGE_TABLE_LEVEL); for (sptep = rmap_get_first(*rmapp, &iter); sptep; sptep = rmap_get_next(&iter)) { From d89cc617b954aff4030fce178f7d86f59aaf713d Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Wed, 1 Aug 2012 18:03:28 +0900 Subject: [PATCH 0323/5375] KVM: Push rmap into kvm_arch_memory_slot Two reasons: - x86 can integrate rmap and rmap_pde and remove heuristics in __gfn_to_rmap(). - Some architectures do not need rmap. Since rmap is one of the most memory consuming stuff in KVM, ppc'd better restrict the allocation to Book3S HV. Signed-off-by: Takuya Yoshikawa Acked-by: Paul Mackerras Signed-off-by: Avi Kivity --- arch/powerpc/include/asm/kvm_host.h | 1 + arch/powerpc/kvm/book3s_64_mmu_hv.c | 6 ++-- arch/powerpc/kvm/book3s_hv_rm_mmu.c | 4 +-- arch/powerpc/kvm/powerpc.c | 8 +++++ arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/mmu.c | 5 +-- arch/x86/kvm/x86.c | 55 +++++++++++++++++------------ include/linux/kvm_host.h | 1 - virt/kvm/kvm_main.c | 11 +----- 9 files changed, 49 insertions(+), 44 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 572ad0141268..a29e0918172a 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -221,6 +221,7 @@ struct revmap_entry { #define KVMPPC_GOT_PAGE 0x80 struct kvm_arch_memory_slot { + unsigned long *rmap; }; struct kvm_arch { diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 3c635c0616b0..d95d11322a15 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -705,7 +705,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, goto out_unlock; hpte[0] = (hpte[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID; - rmap = &memslot->rmap[gfn - memslot->base_gfn]; + rmap = &memslot->arch.rmap[gfn - memslot->base_gfn]; lock_rmap(rmap); /* Check if we might have been invalidated; let the guest retry if so */ @@ -788,7 +788,7 @@ static int kvm_handle_hva_range(struct kvm *kvm, for (; gfn < gfn_end; ++gfn) { gfn_t gfn_offset = gfn - memslot->base_gfn; - ret = handler(kvm, &memslot->rmap[gfn_offset], gfn); + ret = handler(kvm, &memslot->arch.rmap[gfn_offset], gfn); retval |= ret; } } @@ -1036,7 +1036,7 @@ long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot) unsigned long *rmapp, *map; preempt_disable(); - rmapp = memslot->rmap; + rmapp = memslot->arch.rmap; map = memslot->dirty_bitmap; for (i = 0; i < memslot->npages; ++i) { if (kvm_test_clear_dirty(kvm, rmapp)) diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c index 5c70d19494f9..56ac1a5d9912 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c +++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c @@ -84,7 +84,7 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index, if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) return; - rmap = real_vmalloc_addr(&memslot->rmap[gfn - memslot->base_gfn]); + rmap = real_vmalloc_addr(&memslot->arch.rmap[gfn - memslot->base_gfn]); lock_rmap(rmap); head = *rmap & KVMPPC_RMAP_INDEX; @@ -180,7 +180,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags, if (!slot_is_aligned(memslot, psize)) return H_PARAMETER; slot_fn = gfn - memslot->base_gfn; - rmap = &memslot->rmap[slot_fn]; + rmap = &memslot->arch.rmap[slot_fn]; if (!kvm->arch.using_mmu_notifiers) { physp = kvm->arch.slot_phys[memslot->id]; diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 87f4dc886076..879b14a61403 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -302,10 +302,18 @@ long kvm_arch_dev_ioctl(struct file *filp, void kvm_arch_free_memslot(struct kvm_memory_slot *free, struct kvm_memory_slot *dont) { + if (!dont || free->arch.rmap != dont->arch.rmap) { + vfree(free->arch.rmap); + free->arch.rmap = NULL; + } } int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) { + slot->arch.rmap = vzalloc(npages * sizeof(*slot->arch.rmap)); + if (!slot->arch.rmap) + return -ENOMEM; + return 0; } diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 48e713188469..1309e69b57fa 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -504,7 +504,7 @@ struct kvm_lpage_info { }; struct kvm_arch_memory_slot { - unsigned long *rmap_pde[KVM_NR_PAGE_SIZES - 1]; + unsigned long *rmap[KVM_NR_PAGE_SIZES]; struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1]; }; diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index ee768bb2367f..aa9a987ddefb 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -970,11 +970,8 @@ static unsigned long *__gfn_to_rmap(gfn_t gfn, int level, { unsigned long idx; - if (likely(level == PT_PAGE_TABLE_LEVEL)) - return &slot->rmap[gfn - slot->base_gfn]; - idx = gfn_to_index(gfn, slot->base_gfn, level); - return &slot->arch.rmap_pde[level - PT_DIRECTORY_LEVEL][idx]; + return &slot->arch.rmap[level - PT_PAGE_TABLE_LEVEL][idx]; } /* diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index abc039d78428..ebf2109318e0 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6303,14 +6303,18 @@ void kvm_arch_free_memslot(struct kvm_memory_slot *free, { int i; - for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) { - if (!dont || free->arch.rmap_pde[i] != dont->arch.rmap_pde[i]) { - kvm_kvfree(free->arch.rmap_pde[i]); - free->arch.rmap_pde[i] = NULL; + for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) { + if (!dont || free->arch.rmap[i] != dont->arch.rmap[i]) { + kvm_kvfree(free->arch.rmap[i]); + free->arch.rmap[i] = NULL; } - if (!dont || free->arch.lpage_info[i] != dont->arch.lpage_info[i]) { - kvm_kvfree(free->arch.lpage_info[i]); - free->arch.lpage_info[i] = NULL; + if (i == 0) + continue; + + if (!dont || free->arch.lpage_info[i - 1] != + dont->arch.lpage_info[i - 1]) { + kvm_kvfree(free->arch.lpage_info[i - 1]); + free->arch.lpage_info[i - 1] = NULL; } } } @@ -6319,28 +6323,30 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) { int i; - for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) { + for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) { unsigned long ugfn; int lpages; - int level = i + 2; + int level = i + 1; lpages = gfn_to_index(slot->base_gfn + npages - 1, slot->base_gfn, level) + 1; - slot->arch.rmap_pde[i] = - kvm_kvzalloc(lpages * sizeof(*slot->arch.rmap_pde[i])); - if (!slot->arch.rmap_pde[i]) + slot->arch.rmap[i] = + kvm_kvzalloc(lpages * sizeof(*slot->arch.rmap[i])); + if (!slot->arch.rmap[i]) goto out_free; + if (i == 0) + continue; - slot->arch.lpage_info[i] = - kvm_kvzalloc(lpages * sizeof(*slot->arch.lpage_info[i])); - if (!slot->arch.lpage_info[i]) + slot->arch.lpage_info[i - 1] = kvm_kvzalloc(lpages * + sizeof(*slot->arch.lpage_info[i - 1])); + if (!slot->arch.lpage_info[i - 1]) goto out_free; if (slot->base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1)) - slot->arch.lpage_info[i][0].write_count = 1; + slot->arch.lpage_info[i - 1][0].write_count = 1; if ((slot->base_gfn + npages) & (KVM_PAGES_PER_HPAGE(level) - 1)) - slot->arch.lpage_info[i][lpages - 1].write_count = 1; + slot->arch.lpage_info[i - 1][lpages - 1].write_count = 1; ugfn = slot->userspace_addr >> PAGE_SHIFT; /* * If the gfn and userspace address are not aligned wrt each @@ -6352,18 +6358,21 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) unsigned long j; for (j = 0; j < lpages; ++j) - slot->arch.lpage_info[i][j].write_count = 1; + slot->arch.lpage_info[i - 1][j].write_count = 1; } } return 0; out_free: - for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) { - kvm_kvfree(slot->arch.rmap_pde[i]); - kvm_kvfree(slot->arch.lpage_info[i]); - slot->arch.rmap_pde[i] = NULL; - slot->arch.lpage_info[i] = NULL; + for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) { + kvm_kvfree(slot->arch.rmap[i]); + slot->arch.rmap[i] = NULL; + if (i == 0) + continue; + + kvm_kvfree(slot->arch.lpage_info[i - 1]); + slot->arch.lpage_info[i - 1] = NULL; } return -ENOMEM; } diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index dbc65f9d6a2b..3c16f0f1fe35 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -213,7 +213,6 @@ struct kvm_memory_slot { gfn_t base_gfn; unsigned long npages; unsigned long flags; - unsigned long *rmap; unsigned long *dirty_bitmap; struct kvm_arch_memory_slot arch; unsigned long userspace_addr; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index bcf973ec98ff..14ec567816ab 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -550,16 +550,12 @@ static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot) static void kvm_free_physmem_slot(struct kvm_memory_slot *free, struct kvm_memory_slot *dont) { - if (!dont || free->rmap != dont->rmap) - vfree(free->rmap); - if (!dont || free->dirty_bitmap != dont->dirty_bitmap) kvm_destroy_dirty_bitmap(free); kvm_arch_free_memslot(free, dont); free->npages = 0; - free->rmap = NULL; } void kvm_free_physmem(struct kvm *kvm) @@ -768,11 +764,7 @@ int __kvm_set_memory_region(struct kvm *kvm, if (npages && !old.npages) { new.user_alloc = user_alloc; new.userspace_addr = mem->userspace_addr; -#ifndef CONFIG_S390 - new.rmap = vzalloc(npages * sizeof(*new.rmap)); - if (!new.rmap) - goto out_free; -#endif /* not defined CONFIG_S390 */ + if (kvm_arch_create_memslot(&new, npages)) goto out_free; } @@ -831,7 +823,6 @@ int __kvm_set_memory_region(struct kvm *kvm, /* actual memory is freed via old in kvm_free_physmem_slot below */ if (!npages) { - new.rmap = NULL; new.dirty_bitmap = NULL; memset(&new.arch, 0, sizeof(new.arch)); } From 6d8c4529f8058b4e8c902fe689786877f2224060 Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Thu, 26 Jul 2012 05:45:32 -0300 Subject: [PATCH 0324/5375] [media] i.MX: coda: Add platform support for coda in i.MX27 i.MX27 SoC include a codadx6 codec that is able to encode and decode H.264, H.263 and MPEG4. Signed-off-by: Javier Martin Acked-by: Sascha Hauer Signed-off-by: Mauro Carvalho Chehab --- arch/arm/mach-imx/clk-imx27.c | 4 +- arch/arm/mach-imx/devices-imx27.h | 4 ++ arch/arm/plat-mxc/devices/Kconfig | 6 ++- arch/arm/plat-mxc/devices/Makefile | 1 + .../plat-mxc/devices/platform-imx27-coda.c | 37 +++++++++++++++++++ .../plat-mxc/include/mach/devices-common.h | 8 ++++ 6 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 arch/arm/plat-mxc/devices/platform-imx27-coda.c diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index 7aa6313fb167..b60ada1572bc 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c @@ -239,8 +239,8 @@ int __init mx27_clocks_init(unsigned long fref) clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "imx-ssi.0"); clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1"); clk_register_clkdev(clk[nfc_baud_gate], NULL, "mxc_nand.0"); - clk_register_clkdev(clk[vpu_baud_gate], "per", "imx-vpu"); - clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "imx-vpu"); + clk_register_clkdev(clk[vpu_baud_gate], "per", "coda-imx27.0"); + clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "coda-imx27.0"); clk_register_clkdev(clk[dma_ahb_gate], "ahb", "imx-dma"); clk_register_clkdev(clk[dma_ipg_gate], "ipg", "imx-dma"); clk_register_clkdev(clk[fec_ipg_gate], "ipg", "imx27-fec.0"); diff --git a/arch/arm/mach-imx/devices-imx27.h b/arch/arm/mach-imx/devices-imx27.h index 436c5720fe6a..04822932cdd1 100644 --- a/arch/arm/mach-imx/devices-imx27.h +++ b/arch/arm/mach-imx/devices-imx27.h @@ -17,6 +17,10 @@ extern const struct imx_fsl_usb2_udc_data imx27_fsl_usb2_udc_data; #define imx27_add_fsl_usb2_udc(pdata) \ imx_add_fsl_usb2_udc(&imx27_fsl_usb2_udc_data, pdata) +extern const struct imx_imx27_coda_data imx27_coda_data; +#define imx27_add_coda() \ + imx_add_imx27_coda(&imx27_coda_data) + extern const struct imx_imx2_wdt_data imx27_imx2_wdt_data; #define imx27_add_imx2_wdt() \ imx_add_imx2_wdt(&imx27_imx2_wdt_data) diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig index cb3e3eef55c0..6b46cee2f9cd 100644 --- a/arch/arm/plat-mxc/devices/Kconfig +++ b/arch/arm/plat-mxc/devices/Kconfig @@ -15,7 +15,11 @@ config IMX_HAVE_PLATFORM_GPIO_KEYS config IMX_HAVE_PLATFORM_IMX21_HCD bool - + +config IMX_HAVE_PLATFORM_IMX27_CODA + bool + default y if SOC_IMX27 + config IMX_HAVE_PLATFORM_IMX2_WDT bool diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile index c11ac8472beb..76f3195475d0 100644 --- a/arch/arm/plat-mxc/devices/Makefile +++ b/arch/arm/plat-mxc/devices/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_FSL_USB2_UDC) += platform-fsl-usb2-udc.o obj-$(CONFIG_IMX_HAVE_PLATFORM_GPIO_KEYS) += platform-gpio_keys.o obj-y += platform-gpio-mxc.o obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX21_HCD) += platform-imx21-hcd.o +obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX27_CODA) += platform-imx27-coda.o obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX2_WDT) += platform-imx2-wdt.o obj-$(CONFIG_IMX_HAVE_PLATFORM_IMXDI_RTC) += platform-imxdi_rtc.o obj-y += platform-imx-dma.o diff --git a/arch/arm/plat-mxc/devices/platform-imx27-coda.c b/arch/arm/plat-mxc/devices/platform-imx27-coda.c new file mode 100644 index 000000000000..8b12aacdf396 --- /dev/null +++ b/arch/arm/plat-mxc/devices/platform-imx27-coda.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2012 Vista Silicon + * Javier Martin + * + * 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 + +#ifdef CONFIG_SOC_IMX27 +const struct imx_imx27_coda_data imx27_coda_data __initconst = { + .iobase = MX27_VPU_BASE_ADDR, + .iosize = SZ_512, + .irq = MX27_INT_VPU, +}; +#endif + +struct platform_device *__init imx_add_imx27_coda( + const struct imx_imx27_coda_data *data) +{ + struct resource res[] = { + { + .start = data->iobase, + .end = data->iobase + data->iosize - 1, + .flags = IORESOURCE_MEM, + }, { + .start = data->irq, + .end = data->irq, + .flags = IORESOURCE_IRQ, + }, + }; + return imx_add_platform_device_dmamask("coda-imx27", 0, res, 2, NULL, + 0, DMA_BIT_MASK(32)); +} diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h index a7f5bb1084d7..762780cad1bd 100644 --- a/arch/arm/plat-mxc/include/mach/devices-common.h +++ b/arch/arm/plat-mxc/include/mach/devices-common.h @@ -83,6 +83,14 @@ struct platform_device *__init imx_add_imx21_hcd( const struct imx_imx21_hcd_data *data, const struct mx21_usbh_platform_data *pdata); +struct imx_imx27_coda_data { + resource_size_t iobase; + resource_size_t iosize; + resource_size_t irq; +}; +struct platform_device *__init imx_add_imx27_coda( + const struct imx_imx27_coda_data *data); + struct imx_imx2_wdt_data { int id; resource_size_t iobase; From 186b250a07253770717f41eee911b8c5467be04e Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Thu, 26 Jul 2012 05:53:35 -0300 Subject: [PATCH 0325/5375] [media] media: coda: Add driver for Coda video codec Coda is a range of video codecs from Chips&Media that support H.264, H.263, MPEG4 and other video standards. Currently only support for the codadx6 included in the i.MX27 SoC is added. H.264 and MPEG4 video encoding are the only supported capabilities by now. [mchehab@redhat.com: Add missing include linux/of.h] Signed-off-by: Javier Martin Reviewed-by: Philipp Zabel Reviewed-by: Sylwester Nawrocki Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 9 + drivers/media/video/Makefile | 1 + drivers/media/video/coda.c | 1849 ++++++++++++++++++++++++++++++++++ drivers/media/video/coda.h | 216 ++++ 4 files changed, 2075 insertions(+) create mode 100644 drivers/media/video/coda.c create mode 100644 drivers/media/video/coda.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c128fac0ce2c..c95954d9692b 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1224,6 +1224,15 @@ config VIDEO_MEM2MEM_TESTDEV This is a virtual test device for the memory-to-memory driver framework. +config VIDEO_CODA + tristate "Chips&Media Coda multi-standard codec IP" + depends on VIDEO_DEV && VIDEO_V4L2 + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + ---help--- + Coda is a range of video codec IPs that supports + H.264, MPEG-4, and other video formats. + config VIDEO_SAMSUNG_S5P_G2D tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index b7da9faa3b0a..09f704a7f47c 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -188,6 +188,7 @@ obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o +obj-$(CONFIG_VIDEO_CODA) += coda.o obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ diff --git a/drivers/media/video/coda.c b/drivers/media/video/coda.c new file mode 100644 index 000000000000..0d6e0a095607 --- /dev/null +++ b/drivers/media/video/coda.c @@ -0,0 +1,1849 @@ +/* + * Coda multi-standard codec IP + * + * Copyright (C) 2012 Vista Silicon S.L. + * Javier Martin, + * Xavier Duret + * + * 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 +#include +#include + +#include "coda.h" + +#define CODA_NAME "coda" + +#define CODA_MAX_INSTANCES 4 + +#define CODA_FMO_BUF_SIZE 32 +#define CODADX6_WORK_BUF_SIZE (288 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024) +#define CODA7_WORK_BUF_SIZE (512 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024) +#define CODA_PARA_BUF_SIZE (10 * 1024) +#define CODA_ISRAM_SIZE (2048 * 2) + +#define CODA_OUTPUT_BUFS 4 +#define CODA_CAPTURE_BUFS 2 + +#define MAX_W 720 +#define MAX_H 576 +#define CODA_MAX_FRAME_SIZE 0x90000 +#define FMO_SLICE_SAVE_BUF_SIZE (32) +#define CODA_DEFAULT_GAMMA 4096 + +#define MIN_W 176 +#define MIN_H 144 +#define MAX_W 720 +#define MAX_H 576 + +#define S_ALIGN 1 /* multiple of 2 */ +#define W_ALIGN 1 /* multiple of 2 */ +#define H_ALIGN 1 /* multiple of 2 */ + +#define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh) + +static int coda_debug; +module_param(coda_debug, int, 0); +MODULE_PARM_DESC(coda_debug, "Debug level (0-1)"); + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, +}; + +enum coda_fmt_type { + CODA_FMT_ENC, + CODA_FMT_RAW, +}; + +enum coda_inst_type { + CODA_INST_ENCODER, + CODA_INST_DECODER, +}; + +enum coda_product { + CODA_DX6 = 0xf001, +}; + +struct coda_fmt { + char *name; + u32 fourcc; + enum coda_fmt_type type; +}; + +struct coda_devtype { + char *firmware; + enum coda_product product; + struct coda_fmt *formats; + unsigned int num_formats; + size_t workbuf_size; +}; + +/* Per-queue, driver-specific private data */ +struct coda_q_data { + unsigned int width; + unsigned int height; + unsigned int sizeimage; + struct coda_fmt *fmt; +}; + +struct coda_aux_buf { + void *vaddr; + dma_addr_t paddr; + u32 size; +}; + +struct coda_dev { + struct v4l2_device v4l2_dev; + struct video_device vfd; + struct platform_device *plat_dev; + struct coda_devtype *devtype; + + void __iomem *regs_base; + struct clk *clk_per; + struct clk *clk_ahb; + + struct coda_aux_buf codebuf; + struct coda_aux_buf workbuf; + + spinlock_t irqlock; + struct mutex dev_mutex; + struct v4l2_m2m_dev *m2m_dev; + struct vb2_alloc_ctx *alloc_ctx; + int instances; +}; + +struct coda_params { + u8 h264_intra_qp; + u8 h264_inter_qp; + u8 mpeg4_intra_qp; + u8 mpeg4_inter_qp; + u8 gop_size; + int codec_mode; + enum v4l2_mpeg_video_multi_slice_mode slice_mode; + u32 framerate; + u16 bitrate; + u32 slice_max_mb; +}; + +struct coda_ctx { + struct coda_dev *dev; + int aborting; + int rawstreamon; + int compstreamon; + u32 isequence; + struct coda_q_data q_data[2]; + enum coda_inst_type inst_type; + enum v4l2_colorspace colorspace; + struct coda_params params; + struct v4l2_m2m_ctx *m2m_ctx; + struct v4l2_ctrl_handler ctrls; + struct v4l2_fh fh; + struct vb2_buffer *reference; + int gopcounter; + char vpu_header[3][64]; + int vpu_header_size[3]; + struct coda_aux_buf parabuf; + int idx; +}; + +static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg) +{ + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); + writel(data, dev->regs_base + reg); +} + +static inline unsigned int coda_read(struct coda_dev *dev, u32 reg) +{ + u32 data; + data = readl(dev->regs_base + reg); + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); + return data; +} + +static inline unsigned long coda_isbusy(struct coda_dev *dev) +{ + return coda_read(dev, CODA_REG_BIT_BUSY); +} + +static inline int coda_is_initialized(struct coda_dev *dev) +{ + return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0); +} + +static int coda_wait_timeout(struct coda_dev *dev) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + while (coda_isbusy(dev)) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + } + return 0; +} + +static void coda_command_async(struct coda_ctx *ctx, int cmd) +{ + struct coda_dev *dev = ctx->dev; + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + + coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); + coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); + coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); +} + +static int coda_command_sync(struct coda_ctx *ctx, int cmd) +{ + struct coda_dev *dev = ctx->dev; + + coda_command_async(ctx, cmd); + return coda_wait_timeout(dev); +} + +static struct coda_q_data *get_q_data(struct coda_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &(ctx->q_data[V4L2_M2M_SRC]); + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &(ctx->q_data[V4L2_M2M_DST]); + default: + BUG(); + } + return NULL; +} + +/* + * Add one array of supported formats for each version of Coda: + * i.MX27 -> codadx6 + * i.MX51 -> coda7 + * i.MX6 -> coda960 + */ +static struct coda_fmt codadx6_formats[] = { + { + .name = "YUV 4:2:0 Planar", + .fourcc = V4L2_PIX_FMT_YUV420, + .type = CODA_FMT_RAW, + }, + { + .name = "H264 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264, + .type = CODA_FMT_ENC, + }, + { + .name = "MPEG4 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG4, + .type = CODA_FMT_ENC, + }, +}; + +static struct coda_fmt *find_format(struct coda_dev *dev, struct v4l2_format *f) +{ + struct coda_fmt *formats = dev->devtype->formats; + int num_formats = dev->devtype->num_formats; + unsigned int k; + + for (k = 0; k < num_formats; k++) { + if (formats[k].fourcc == f->fmt.pix.pixelformat) + break; + } + + if (k == num_formats) + return NULL; + + return &formats[k]; +} + +/* + * V4L2 ioctl() operations. + */ +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver)); + strlcpy(cap->card, CODA_NAME, sizeof(cap->card)); + strlcpy(cap->bus_info, CODA_NAME, sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT + | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +static int enum_fmt(void *priv, struct v4l2_fmtdesc *f, + enum coda_fmt_type type) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_dev *dev = ctx->dev; + struct coda_fmt *formats = dev->devtype->formats; + struct coda_fmt *fmt; + int num_formats = dev->devtype->num_formats; + int i, num = 0; + + for (i = 0; i < num_formats; i++) { + if (formats[i].type == type) { + if (num == f->index) + break; + ++num; + } + } + + if (i < num_formats) { + fmt = &formats[i]; + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; + return 0; + } + + /* Format not found */ + return -EINVAL; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return enum_fmt(priv, f, CODA_FMT_ENC); +} + +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return enum_fmt(priv, f, CODA_FMT_RAW); +} + +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct vb2_queue *vq; + struct coda_q_data *q_data; + struct coda_ctx *ctx = fh_to_ctx(priv); + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(ctx, f->type); + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = q_data->fmt->fourcc; + f->fmt.pix.width = q_data->width; + f->fmt.pix.height = q_data->height; + if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2); + else /* encoded formats h.264/mpeg4 */ + f->fmt.pix.bytesperline = 0; + + f->fmt.pix.sizeimage = q_data->sizeimage; + f->fmt.pix.colorspace = ctx->colorspace; + + return 0; +} + +static int vidioc_try_fmt(struct coda_dev *dev, struct v4l2_format *f) +{ + enum v4l2_field field; + + field = f->fmt.pix.field; + if (field == V4L2_FIELD_ANY) + field = V4L2_FIELD_NONE; + else if (V4L2_FIELD_NONE != field) + return -EINVAL; + + /* V4L2 specification suggests the driver corrects the format struct + * if any of the dimensions is unsupported */ + f->fmt.pix.field = field; + + if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) { + v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, + W_ALIGN, &f->fmt.pix.height, + MIN_H, MAX_H, H_ALIGN, S_ALIGN); + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2); + f->fmt.pix.sizeimage = f->fmt.pix.height * + f->fmt.pix.bytesperline; + } else { /*encoded formats h.264/mpeg4 */ + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE; + } + + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + struct coda_fmt *fmt; + struct coda_ctx *ctx = fh_to_ctx(priv); + + fmt = find_format(ctx->dev, f); + /* + * Since decoding support is not implemented yet do not allow + * CODA_FMT_RAW formats in the capture interface. + */ + if (!fmt || !(fmt->type == CODA_FMT_ENC)) + f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264; + + f->fmt.pix.colorspace = ctx->colorspace; + + ret = vidioc_try_fmt(ctx->dev, f); + if (ret < 0) + return ret; + + return 0; +} + +static int vidioc_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_fmt *fmt; + int ret; + + fmt = find_format(ctx->dev, f); + /* + * Since decoding support is not implemented yet do not allow + * CODA_FMT formats in the capture interface. + */ + if (!fmt || !(fmt->type == CODA_FMT_RAW)) + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; + + if (!f->fmt.pix.colorspace) + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + + ret = vidioc_try_fmt(ctx->dev, f); + if (ret < 0) + return ret; + + return 0; +} + +static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f) +{ + struct coda_q_data *q_data; + struct vb2_queue *vq; + int ret; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + if (vb2_is_busy(vq)) { + v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + ret = vidioc_try_fmt(ctx->dev, f); + if (ret) + return ret; + + q_data->fmt = find_format(ctx->dev, f); + q_data->width = f->fmt.pix.width; + q_data->height = f->fmt.pix.height; + if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420) { + q_data->sizeimage = q_data->width * q_data->height * 3 / 2; + } else { /* encoded format h.264/mpeg-4 */ + q_data->sizeimage = CODA_MAX_FRAME_SIZE; + } + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "Setting format for type %d, wxh: %dx%d, fmt: %d\n", + f->type, q_data->width, q_data->height, q_data->fmt->fourcc); + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = vidioc_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + return vidioc_s_fmt(fh_to_ctx(priv), f); +} + +static int vidioc_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + int ret; + + ret = vidioc_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + ret = vidioc_s_fmt(fh_to_ctx(priv), f); + if (ret) + ctx->colorspace = f->fmt.pix.colorspace; + + return ret; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); +} + +static const struct v4l2_ioctl_ops coda_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = vidioc_g_fmt, + .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, + + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, +}; + +/* + * Mem-to-mem operations. + */ +static void coda_device_run(void *m2m_priv) +{ + struct coda_ctx *ctx = m2m_priv; + struct coda_q_data *q_data_src, *q_data_dst; + struct vb2_buffer *src_buf, *dst_buf; + struct coda_dev *dev = ctx->dev; + int force_ipicture; + int quant_param = 0; + u32 picture_y, picture_cb, picture_cr; + u32 pic_stream_buffer_addr, pic_stream_buffer_size; + u32 dst_fourcc; + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_fourcc = q_data_dst->fmt->fourcc; + + src_buf->v4l2_buf.sequence = ctx->isequence; + dst_buf->v4l2_buf.sequence = ctx->isequence; + ctx->isequence++; + + /* + * Workaround coda firmware BUG that only marks the first + * frame as IDR. This is a problem for some decoders that can't + * recover when a frame is lost. + */ + if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) { + src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; + src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; + } else { + src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; + } + + /* + * Copy headers at the beginning of the first frame for H.264 only. + * In MPEG4 they are already copied by the coda. + */ + if (src_buf->v4l2_buf.sequence == 0) { + pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(dst_buf, 0) + + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1] + + ctx->vpu_header_size[2]; + pic_stream_buffer_size = CODA_MAX_FRAME_SIZE - + ctx->vpu_header_size[0] - + ctx->vpu_header_size[1] - + ctx->vpu_header_size[2]; + memcpy(vb2_plane_vaddr(dst_buf, 0), + &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); + memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0], + &ctx->vpu_header[1][0], ctx->vpu_header_size[1]); + memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1], &ctx->vpu_header[2][0], + ctx->vpu_header_size[2]); + } else { + pic_stream_buffer_addr = + vb2_dma_contig_plane_dma_addr(dst_buf, 0); + pic_stream_buffer_size = CODA_MAX_FRAME_SIZE; + } + + if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) { + force_ipicture = 1; + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + quant_param = ctx->params.h264_intra_qp; + break; + case V4L2_PIX_FMT_MPEG4: + quant_param = ctx->params.mpeg4_intra_qp; + break; + default: + v4l2_warn(&ctx->dev->v4l2_dev, + "cannot set intra qp, fmt not supported\n"); + break; + } + } else { + force_ipicture = 0; + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + quant_param = ctx->params.h264_inter_qp; + break; + case V4L2_PIX_FMT_MPEG4: + quant_param = ctx->params.mpeg4_inter_qp; + break; + default: + v4l2_warn(&ctx->dev->v4l2_dev, + "cannot set inter qp, fmt not supported\n"); + break; + } + } + + /* submit */ + coda_write(dev, 0, CODA_CMD_ENC_PIC_ROT_MODE); + coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); + + + picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0); + picture_cb = picture_y + q_data_src->width * q_data_src->height; + picture_cr = picture_cb + q_data_src->width / 2 * + q_data_src->height / 2; + + coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y); + coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB); + coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR); + coda_write(dev, force_ipicture << 1 & 0x2, + CODA_CMD_ENC_PIC_OPTION); + + coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); + coda_write(dev, pic_stream_buffer_size / 1024, + CODA_CMD_ENC_PIC_BB_SIZE); + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); +} + +static int coda_job_ready(void *m2m_priv) +{ + struct coda_ctx *ctx = m2m_priv; + + /* + * For both 'P' and 'key' frame cases 1 picture + * and 1 frame are needed. + */ + if (!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) || + !v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "not ready: not enough video buffers.\n"); + return 0; + } + + /* For P frames a reference picture is needed too */ + if ((ctx->gopcounter != (ctx->params.gop_size - 1)) && + !ctx->reference) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "not ready: reference picture not available.\n"); + return 0; + } + + if (coda_isbusy(ctx->dev)) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "not ready: coda is still busy.\n"); + return 0; + } + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "job ready\n"); + return 1; +} + +static void coda_job_abort(void *priv) +{ + struct coda_ctx *ctx = priv; + struct coda_dev *dev = ctx->dev; + + ctx->aborting = 1; + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "Aborting task\n"); + + v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx); +} + +static void coda_lock(void *m2m_priv) +{ + struct coda_ctx *ctx = m2m_priv; + struct coda_dev *pcdev = ctx->dev; + mutex_lock(&pcdev->dev_mutex); +} + +static void coda_unlock(void *m2m_priv) +{ + struct coda_ctx *ctx = m2m_priv; + struct coda_dev *pcdev = ctx->dev; + mutex_unlock(&pcdev->dev_mutex); +} + +static struct v4l2_m2m_ops coda_m2m_ops = { + .device_run = coda_device_run, + .job_ready = coda_job_ready, + .job_abort = coda_job_abort, + .lock = coda_lock, + .unlock = coda_unlock, +}; + +static void set_default_params(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + + ctx->params.codec_mode = CODA_MODE_INVALID; + ctx->colorspace = V4L2_COLORSPACE_REC709; + ctx->params.framerate = 30; + ctx->reference = NULL; + ctx->aborting = 0; + + /* Default formats for output and input queues */ + ctx->q_data[V4L2_M2M_SRC].fmt = &dev->devtype->formats[0]; + ctx->q_data[V4L2_M2M_DST].fmt = &dev->devtype->formats[1]; + ctx->q_data[V4L2_M2M_SRC].width = MAX_W; + ctx->q_data[V4L2_M2M_SRC].height = MAX_H; + ctx->q_data[V4L2_M2M_SRC].sizeimage = (MAX_W * MAX_H * 3) / 2; + ctx->q_data[V4L2_M2M_DST].width = MAX_W; + ctx->q_data[V4L2_M2M_DST].height = MAX_H; + ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE; +} + +/* + * Queue operations + */ +static int coda_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(vq); + unsigned int size; + + if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + *nbuffers = CODA_OUTPUT_BUFS; + if (fmt) + size = fmt->fmt.pix.width * + fmt->fmt.pix.height * 3 / 2; + else + size = MAX_W * + MAX_H * 3 / 2; + } else { + *nbuffers = CODA_CAPTURE_BUFS; + size = CODA_MAX_FRAME_SIZE; + } + + *nplanes = 1; + sizes[0] = size; + + alloc_ctxs[0] = ctx->dev->alloc_ctx; + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "get %d buffer(s) of size %d each.\n", *nbuffers, size); + + return 0; +} + +static int coda_buf_prepare(struct vb2_buffer *vb) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct coda_q_data *q_data; + + q_data = get_q_data(ctx, vb->vb2_queue->type); + + if (vb2_plane_size(vb, 0) < q_data->sizeimage) { + v4l2_warn(&ctx->dev->v4l2_dev, + "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), + (long)q_data->sizeimage); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, q_data->sizeimage); + + return 0; +} + +static void coda_buf_queue(struct vb2_buffer *vb) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); +} + +static void coda_wait_prepare(struct vb2_queue *q) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(q); + coda_unlock(ctx); +} + +static void coda_wait_finish(struct vb2_queue *q) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(q); + coda_lock(ctx); +} + +static int coda_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(q); + struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; + u32 bitstream_buf, bitstream_size; + struct coda_dev *dev = ctx->dev; + struct coda_q_data *q_data_src, *q_data_dst; + u32 dst_fourcc; + struct vb2_buffer *buf; + struct vb2_queue *src_vq; + u32 value; + int i = 0; + + if (count < 1) + return -EINVAL; + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + ctx->rawstreamon = 1; + else + ctx->compstreamon = 1; + + /* Don't start the coda unless both queues are on */ + if (!(ctx->rawstreamon & ctx->compstreamon)) + return 0; + + ctx->gopcounter = ctx->params.gop_size - 1; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + bitstream_size = q_data_dst->sizeimage; + dst_fourcc = q_data_dst->fmt->fourcc; + + /* Find out whether coda must encode or decode */ + if (q_data_src->fmt->type == CODA_FMT_RAW && + q_data_dst->fmt->type == CODA_FMT_ENC) { + ctx->inst_type = CODA_INST_ENCODER; + } else if (q_data_src->fmt->type == CODA_FMT_ENC && + q_data_dst->fmt->type == CODA_FMT_RAW) { + ctx->inst_type = CODA_INST_DECODER; + v4l2_err(v4l2_dev, "decoding not supported.\n"); + return -EINVAL; + } else { + v4l2_err(v4l2_dev, "couldn't tell instance type.\n"); + return -EINVAL; + } + + if (!coda_is_initialized(dev)) { + v4l2_err(v4l2_dev, "coda is not initialized.\n"); + return -EFAULT; + } + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); + coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->idx)); + coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->idx)); + switch (dev->devtype->product) { + case CODA_DX6: + coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | + CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); + break; + default: + coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | + CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); + } + + /* Configure the coda */ + coda_write(dev, 0xffff4c00, CODA_REG_BIT_SEARCH_RAM_BASE_ADDR); + + /* Could set rotation here if needed */ + switch (dev->devtype->product) { + case CODA_DX6: + value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET; + break; + default: + value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; + } + value |= (q_data_src->height & CODA_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; + coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); + coda_write(dev, ctx->params.framerate, + CODA_CMD_ENC_SEQ_SRC_F_RATE); + + switch (dst_fourcc) { + case V4L2_PIX_FMT_MPEG4: + if (dev->devtype->product == CODA_DX6) + ctx->params.codec_mode = CODADX6_MODE_ENCODE_MP4; + else + ctx->params.codec_mode = CODA7_MODE_ENCODE_MP4; + + coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); + break; + case V4L2_PIX_FMT_H264: + if (dev->devtype->product == CODA_DX6) + ctx->params.codec_mode = CODADX6_MODE_ENCODE_H264; + else + ctx->params.codec_mode = CODA7_MODE_ENCODE_H264; + + coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_264_PARA); + break; + default: + v4l2_err(v4l2_dev, + "dst format (0x%08x) invalid.\n", dst_fourcc); + return -EINVAL; + } + + value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; + value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET; + if (ctx->params.slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) + value |= 1 & CODA_SLICING_MODE_MASK; + coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); + value = ctx->params.gop_size & CODA_GOP_SIZE_MASK; + coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); + + if (ctx->params.bitrate) { + /* Rate control enabled */ + value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; + value |= 1 & CODA_RATECONTROL_ENABLE_MASK; + } else { + value = 0; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); + + coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_INTRA_REFRESH); + + coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); + coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); + + /* set default gamma */ + value = (CODA_DEFAULT_GAMMA & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET; + coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_GAMMA); + + value = (CODA_DEFAULT_GAMMA > 0) << CODA_OPTION_GAMMA_OFFSET; + value |= (0 & CODA_OPTION_SLICEREPORT_MASK) << CODA_OPTION_SLICEREPORT_OFFSET; + coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); + + if (dst_fourcc == V4L2_PIX_FMT_H264) { + value = (FMO_SLICE_SAVE_BUF_SIZE << 7); + value |= (0 & CODA_FMOPARAM_TYPE_MASK) << CODA_FMOPARAM_TYPE_OFFSET; + value |= 0 & CODA_FMOPARAM_SLICENUM_MASK; + coda_write(dev, value, CODA_CMD_ENC_SEQ_FMO); + } + + if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); + return -ETIMEDOUT; + } + + if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) + return -EFAULT; + + /* + * Walk the src buffer list and let the codec know the + * addresses of the pictures. + */ + src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + for (i = 0; i < src_vq->num_buffers; i++) { + u32 *p; + + buf = src_vq->bufs[i]; + p = ctx->parabuf.vaddr; + + p[i * 3] = vb2_dma_contig_plane_dma_addr(buf, 0); + p[i * 3 + 1] = p[i * 3] + q_data_src->width * + q_data_src->height; + p[i * 3 + 2] = p[i * 3 + 1] + q_data_src->width / 2 * + q_data_src->height / 2; + } + + coda_write(dev, src_vq->num_buffers, CODA_CMD_SET_FRAME_BUF_NUM); + coda_write(dev, q_data_src->width, CODA_CMD_SET_FRAME_BUF_STRIDE); + if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { + v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); + return -ETIMEDOUT; + } + + /* Save stream headers */ + buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + switch (dst_fourcc) { + case V4L2_PIX_FMT_H264: + /* + * Get SPS in the first frame and copy it to an + * intermediate buffer. + */ + coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START); + coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE); + coda_write(dev, CODA_HEADER_H264_SPS, CODA_CMD_ENC_HEADER_CODE); + if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) { + v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); + return -ETIMEDOUT; + } + ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) - + coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); + memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0), + ctx->vpu_header_size[0]); + + /* + * Get PPS in the first frame and copy it to an + * intermediate buffer. + */ + coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START); + coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE); + coda_write(dev, CODA_HEADER_H264_PPS, CODA_CMD_ENC_HEADER_CODE); + if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) { + v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); + return -ETIMEDOUT; + } + ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) - + coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); + memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0), + ctx->vpu_header_size[1]); + ctx->vpu_header_size[2] = 0; + break; + case V4L2_PIX_FMT_MPEG4: + /* + * Get VOS in the first frame and copy it to an + * intermediate buffer + */ + coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START); + coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE); + coda_write(dev, CODA_HEADER_MP4V_VOS, CODA_CMD_ENC_HEADER_CODE); + if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) { + v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); + return -ETIMEDOUT; + } + ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) - + coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); + memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0), + ctx->vpu_header_size[0]); + + coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START); + coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE); + coda_write(dev, CODA_HEADER_MP4V_VIS, CODA_CMD_ENC_HEADER_CODE); + if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) { + v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n"); + return -ETIMEDOUT; + } + ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) - + coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); + memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0), + ctx->vpu_header_size[1]); + + coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START); + coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE); + coda_write(dev, CODA_HEADER_MP4V_VOL, CODA_CMD_ENC_HEADER_CODE); + if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) { + v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n"); + return -ETIMEDOUT; + } + ctx->vpu_header_size[2] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) - + coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); + memcpy(&ctx->vpu_header[2][0], vb2_plane_vaddr(buf, 0), + ctx->vpu_header_size[2]); + break; + default: + /* No more formats need to save headers at the moment */ + break; + } + + return 0; +} + +static int coda_stop_streaming(struct vb2_queue *q) +{ + struct coda_ctx *ctx = vb2_get_drv_priv(q); + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "%s: output\n", __func__); + ctx->rawstreamon = 0; + } else { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "%s: capture\n", __func__); + ctx->compstreamon = 0; + } + + if (!ctx->rawstreamon && !ctx->compstreamon) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "%s: sent command 'SEQ_END' to coda\n", __func__); + if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { + v4l2_err(&ctx->dev->v4l2_dev, + "CODA_COMMAND_SEQ_END failed\n"); + return -ETIMEDOUT; + } + } + + return 0; +} + +static struct vb2_ops coda_qops = { + .queue_setup = coda_queue_setup, + .buf_prepare = coda_buf_prepare, + .buf_queue = coda_buf_queue, + .wait_prepare = coda_wait_prepare, + .wait_finish = coda_wait_finish, + .start_streaming = coda_start_streaming, + .stop_streaming = coda_stop_streaming, +}; + +static int coda_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct coda_ctx *ctx = + container_of(ctrl->handler, struct coda_ctx, ctrls); + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_BITRATE: + ctx->params.bitrate = ctrl->val / 1000; + break; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + ctx->params.gop_size = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: + ctx->params.h264_intra_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: + ctx->params.h264_inter_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: + ctx->params.mpeg4_intra_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: + ctx->params.mpeg4_inter_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: + ctx->params.slice_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: + ctx->params.slice_max_mb = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: + break; + default: + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "Invalid control, id=%d, val=%d\n", + ctrl->id, ctrl->val); + return -EINVAL; + } + + return 0; +} + +static struct v4l2_ctrl_ops coda_ctrl_ops = { + .s_ctrl = coda_s_ctrl, +}; + +static int coda_ctrls_setup(struct coda_ctx *ctx) +{ + v4l2_ctrl_handler_init(&ctx->ctrls, 9); + + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 1, 51, 1, 25); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 1, 51, 1, 25); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2); + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB, 0, + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1); + v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE), + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); + + if (ctx->ctrls.error) { + v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)", + ctx->ctrls.error); + return -EINVAL; + } + + return v4l2_ctrl_handler_setup(&ctx->ctrls); +} + +static int coda_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct coda_ctx *ctx = priv; + int ret; + + 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 = &coda_qops; + src_vq->mem_ops = &vb2_dma_contig_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 = &coda_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + + return vb2_queue_init(dst_vq); +} + +static int coda_open(struct file *file) +{ + struct coda_dev *dev = video_drvdata(file); + struct coda_ctx *ctx = NULL; + int ret = 0; + + if (dev->instances >= CODA_MAX_INSTANCES) + return -EBUSY; + + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + ctx->dev = dev; + + set_default_params(ctx); + ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, + &coda_queue_init); + if (IS_ERR(ctx->m2m_ctx)) { + int ret = PTR_ERR(ctx->m2m_ctx); + + v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n", + __func__, ret); + goto err; + } + ret = coda_ctrls_setup(ctx); + if (ret) { + v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n"); + goto err; + } + + ctx->fh.ctrl_handler = &ctx->ctrls; + + ctx->parabuf.vaddr = dma_alloc_coherent(&dev->plat_dev->dev, + CODA_PARA_BUF_SIZE, &ctx->parabuf.paddr, GFP_KERNEL); + if (!ctx->parabuf.vaddr) { + v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf"); + ret = -ENOMEM; + goto err; + } + + coda_lock(ctx); + ctx->idx = dev->instances++; + coda_unlock(ctx); + + clk_prepare_enable(dev->clk_per); + clk_prepare_enable(dev->clk_ahb); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n", + ctx->idx, ctx); + + return 0; + +err: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + return ret; +} + +static int coda_release(struct file *file) +{ + struct coda_dev *dev = video_drvdata(file); + struct coda_ctx *ctx = fh_to_ctx(file->private_data); + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n", + ctx); + + coda_lock(ctx); + dev->instances--; + coda_unlock(ctx); + + dma_free_coherent(&dev->plat_dev->dev, CODA_PARA_BUF_SIZE, + ctx->parabuf.vaddr, ctx->parabuf.paddr); + v4l2_m2m_ctx_release(ctx->m2m_ctx); + v4l2_ctrl_handler_free(&ctx->ctrls); + clk_disable_unprepare(dev->clk_per); + clk_disable_unprepare(dev->clk_ahb); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + + return 0; +} + +static unsigned int coda_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct coda_ctx *ctx = fh_to_ctx(file->private_data); + int ret; + + coda_lock(ctx); + ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); + coda_unlock(ctx); + return ret; +} + +static int coda_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct coda_ctx *ctx = fh_to_ctx(file->private_data); + + return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); +} + +static const struct v4l2_file_operations coda_fops = { + .owner = THIS_MODULE, + .open = coda_open, + .release = coda_release, + .poll = coda_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = coda_mmap, +}; + +static irqreturn_t coda_irq_handler(int irq, void *data) +{ + struct vb2_buffer *src_buf, *dst_buf, *tmp_buf; + struct coda_dev *dev = data; + u32 wr_ptr, start_ptr; + struct coda_ctx *ctx; + + /* read status register to attend the IRQ */ + coda_read(dev, CODA_REG_BIT_INT_STATUS); + coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, + CODA_REG_BIT_INT_CLEAR); + + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); + if (ctx == NULL) { + v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n"); + return IRQ_HANDLED; + } + + if (ctx->aborting) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "task has been aborted\n"); + return IRQ_HANDLED; + } + + if (coda_isbusy(ctx->dev)) { + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, + "coda is still busy!!!!\n"); + return IRQ_NONE; + } + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + + /* Get results from the coda */ + coda_read(dev, CODA_RET_ENC_PIC_TYPE); + start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); + wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)); + /* Calculate bytesused field */ + if (dst_buf->v4l2_buf.sequence == 0) { + dst_buf->v4l2_planes[0].bytesused = (wr_ptr - start_ptr) + + ctx->vpu_header_size[0] + + ctx->vpu_header_size[1] + + ctx->vpu_header_size[2]; + } else { + dst_buf->v4l2_planes[0].bytesused = (wr_ptr - start_ptr); + } + + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n", + wr_ptr - start_ptr); + + coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); + coda_read(dev, CODA_RET_ENC_PIC_FLAG); + + if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) { + dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME; + } else { + dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; + dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; + } + + /* Free previous reference picture if available */ + if (ctx->reference) { + v4l2_m2m_buf_done(ctx->reference, VB2_BUF_STATE_DONE); + ctx->reference = NULL; + } + + /* + * For the last frame of the gop we don't need to save + * a reference picture. + */ + v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + tmp_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + if (ctx->gopcounter == 0) + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + else + ctx->reference = tmp_buf; + + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + + ctx->gopcounter--; + if (ctx->gopcounter < 0) + ctx->gopcounter = ctx->params.gop_size - 1; + + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, + "job finished: encoding frame (%d) (%s)\n", + dst_buf->v4l2_buf.sequence, + (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ? + "KEYFRAME" : "PFRAME"); + + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx); + + return IRQ_HANDLED; +} + +static u32 coda_supported_firmwares[] = { + CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), +}; + +static bool coda_firmware_supported(u32 vernum) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) + if (vernum == coda_supported_firmwares[i]) + return true; + return false; +} + +static char *coda_product_name(int product) +{ + static char buf[9]; + + switch (product) { + case CODA_DX6: + return "CodaDx6"; + default: + snprintf(buf, sizeof(buf), "(0x%04x)", product); + return buf; + } +} + +static int coda_hw_init(struct coda_dev *dev, const struct firmware *fw) +{ + u16 product, major, minor, release; + u32 data; + u16 *p; + int i; + + clk_prepare_enable(dev->clk_per); + clk_prepare_enable(dev->clk_ahb); + + /* Copy the whole firmware image to the code buffer */ + memcpy(dev->codebuf.vaddr, fw->data, fw->size); + /* + * Copy the first CODA_ISRAM_SIZE in the internal SRAM. + * This memory seems to be big-endian here, which is weird, since + * the internal ARM processor of the coda is little endian. + * Data in this SRAM survives a reboot. + */ + p = (u16 *)fw->data; + for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) { + data = CODA_DOWN_ADDRESS_SET(i) | + CODA_DOWN_DATA_SET(p[i ^ 1]); + coda_write(dev, data, CODA_REG_BIT_CODE_DOWN); + } + release_firmware(fw); + + /* Tell the BIT where to find everything it needs */ + coda_write(dev, dev->workbuf.paddr, + CODA_REG_BIT_WORK_BUF_ADDR); + coda_write(dev, dev->codebuf.paddr, + CODA_REG_BIT_CODE_BUF_ADDR); + coda_write(dev, 0, CODA_REG_BIT_CODE_RUN); + + /* Set default values */ + switch (dev->devtype->product) { + case CODA_DX6: + coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL); + break; + default: + coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL); + } + coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL); + coda_write(dev, CODA_INT_INTERRUPT_ENABLE, + CODA_REG_BIT_INT_ENABLE); + + /* Reset VPU and start processor */ + data = coda_read(dev, CODA_REG_BIT_CODE_RESET); + data |= CODA_REG_RESET_ENABLE; + coda_write(dev, data, CODA_REG_BIT_CODE_RESET); + udelay(10); + data &= ~CODA_REG_RESET_ENABLE; + coda_write(dev, data, CODA_REG_BIT_CODE_RESET); + coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); + + /* Load firmware */ + coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); + coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); + coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); + coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); + coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); + if (coda_wait_timeout(dev)) { + clk_disable_unprepare(dev->clk_per); + clk_disable_unprepare(dev->clk_ahb); + v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); + return -EIO; + } + + /* Check we are compatible with the loaded firmware */ + data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); + product = CODA_FIRMWARE_PRODUCT(data); + major = CODA_FIRMWARE_MAJOR(data); + minor = CODA_FIRMWARE_MINOR(data); + release = CODA_FIRMWARE_RELEASE(data); + + clk_disable_unprepare(dev->clk_per); + clk_disable_unprepare(dev->clk_ahb); + + if (product != dev->devtype->product) { + v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s," + " Version: %u.%u.%u\n", + coda_product_name(dev->devtype->product), + coda_product_name(product), major, minor, release); + return -EINVAL; + } + + v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", + coda_product_name(product)); + + if (coda_firmware_supported(data)) { + v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", + major, minor, release); + } else { + v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: " + "%u.%u.%u\n", major, minor, release); + } + + return 0; +} + +static void coda_fw_callback(const struct firmware *fw, void *context) +{ + struct coda_dev *dev = context; + struct platform_device *pdev = dev->plat_dev; + int ret; + + if (!fw) { + v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); + return; + } + + /* allocate auxiliary per-device code buffer for the BIT processor */ + dev->codebuf.size = fw->size; + dev->codebuf.vaddr = dma_alloc_coherent(&pdev->dev, fw->size, + &dev->codebuf.paddr, + GFP_KERNEL); + if (!dev->codebuf.vaddr) { + dev_err(&pdev->dev, "failed to allocate code buffer\n"); + return; + } + + ret = coda_hw_init(dev, fw); + if (ret) { + v4l2_err(&dev->v4l2_dev, "HW initialization failed\n"); + return; + } + + dev->vfd.fops = &coda_fops, + dev->vfd.ioctl_ops = &coda_ioctl_ops; + dev->vfd.release = video_device_release_empty, + dev->vfd.lock = &dev->dev_mutex; + dev->vfd.v4l2_dev = &dev->v4l2_dev; + snprintf(dev->vfd.name, sizeof(dev->vfd.name), "%s", CODA_NAME); + video_set_drvdata(&dev->vfd, dev); + + dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(dev->alloc_ctx)) { + v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n"); + return; + } + + dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); + goto rel_ctx; + } + + ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + goto rel_m2m; + } + v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video%d\n", + dev->vfd.num); + + return; + +rel_m2m: + v4l2_m2m_release(dev->m2m_dev); +rel_ctx: + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); +} + +static int coda_firmware_request(struct coda_dev *dev) +{ + char *fw = dev->devtype->firmware; + + dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw, + coda_product_name(dev->devtype->product)); + + return request_firmware_nowait(THIS_MODULE, true, + fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback); +} + +enum coda_platform { + CODA_IMX27, +}; + +static struct coda_devtype coda_devdata[] = { + [CODA_IMX27] = { + .firmware = "v4l-codadx6-imx27.bin", + .product = CODA_DX6, + .formats = codadx6_formats, + .num_formats = ARRAY_SIZE(codadx6_formats), + }, +}; + +static struct platform_device_id coda_platform_ids[] = { + { .name = "coda-imx27", .driver_data = CODA_IMX27 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, coda_platform_ids); + +#ifdef CONFIG_OF +static const struct of_device_id coda_dt_ids[] = { + { .compatible = "fsl,imx27-vpu", .data = &coda_platform_ids[CODA_IMX27] }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, coda_dt_ids); +#endif + +static int __devinit coda_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev); + const struct platform_device_id *pdev_id; + struct coda_dev *dev; + struct resource *res; + int ret, irq; + + dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "Not enough memory for %s\n", + CODA_NAME); + return -ENOMEM; + } + + spin_lock_init(&dev->irqlock); + + dev->plat_dev = pdev; + dev->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(dev->clk_per)) { + dev_err(&pdev->dev, "Could not get per clock\n"); + return PTR_ERR(dev->clk_per); + } + + dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(dev->clk_ahb)) { + dev_err(&pdev->dev, "Could not get ahb clock\n"); + return PTR_ERR(dev->clk_ahb); + } + + /* Get memory for physical registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "failed to get memory region resource\n"); + return -ENOENT; + } + + if (devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), CODA_NAME) == NULL) { + dev_err(&pdev->dev, "failed to request memory region\n"); + return -ENOENT; + } + dev->regs_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!dev->regs_base) { + dev_err(&pdev->dev, "failed to ioremap address region\n"); + return -ENOENT; + } + + /* IRQ */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq resource\n"); + return -ENOENT; + } + + if (devm_request_irq(&pdev->dev, irq, coda_irq_handler, + 0, CODA_NAME, dev) < 0) { + dev_err(&pdev->dev, "failed to request irq\n"); + return -ENOENT; + } + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + return ret; + + mutex_init(&dev->dev_mutex); + + pdev_id = of_id ? of_id->data : platform_get_device_id(pdev); + + if (of_id) { + dev->devtype = of_id->data; + } else if (pdev_id) { + dev->devtype = &coda_devdata[pdev_id->driver_data]; + } else { + v4l2_device_unregister(&dev->v4l2_dev); + return -EINVAL; + } + + /* allocate auxiliary per-device buffers for the BIT processor */ + switch (dev->devtype->product) { + case CODA_DX6: + dev->workbuf.size = CODADX6_WORK_BUF_SIZE; + break; + default: + dev->workbuf.size = CODA7_WORK_BUF_SIZE; + } + dev->workbuf.vaddr = dma_alloc_coherent(&pdev->dev, dev->workbuf.size, + &dev->workbuf.paddr, + GFP_KERNEL); + if (!dev->workbuf.vaddr) { + dev_err(&pdev->dev, "failed to allocate work buffer\n"); + v4l2_device_unregister(&dev->v4l2_dev); + return -ENOMEM; + } + + platform_set_drvdata(pdev, dev); + + return coda_firmware_request(dev); +} + +static int coda_remove(struct platform_device *pdev) +{ + struct coda_dev *dev = platform_get_drvdata(pdev); + + video_unregister_device(&dev->vfd); + if (dev->m2m_dev) + v4l2_m2m_release(dev->m2m_dev); + if (dev->alloc_ctx) + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); + v4l2_device_unregister(&dev->v4l2_dev); + if (dev->codebuf.vaddr) + dma_free_coherent(&pdev->dev, dev->codebuf.size, + &dev->codebuf.vaddr, dev->codebuf.paddr); + if (dev->workbuf.vaddr) + dma_free_coherent(&pdev->dev, dev->workbuf.size, &dev->workbuf.vaddr, + dev->workbuf.paddr); + return 0; +} + +static struct platform_driver coda_driver = { + .probe = coda_probe, + .remove = __devexit_p(coda_remove), + .driver = { + .name = CODA_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(coda_dt_ids), + }, + .id_table = coda_platform_ids, +}; + +module_platform_driver(coda_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Javier Martin "); +MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver"); diff --git a/drivers/media/video/coda.h b/drivers/media/video/coda.h new file mode 100644 index 000000000000..4cf4a043186f --- /dev/null +++ b/drivers/media/video/coda.h @@ -0,0 +1,216 @@ +/* + * linux/drivers/media/video/coda/coda_regs.h + * + * Copyright (C) 2012 Vista Silicon SL + * Javier Martin + * Xavier Duret + * + * 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. + */ + +#ifndef _REGS_CODA_H_ +#define _REGS_CODA_H_ + +/* HW registers */ +#define CODA_REG_BIT_CODE_RUN 0x000 +#define CODA_REG_RUN_ENABLE (1 << 0) +#define CODA_REG_BIT_CODE_DOWN 0x004 +#define CODA_DOWN_ADDRESS_SET(x) (((x) & 0xffff) << 16) +#define CODA_DOWN_DATA_SET(x) ((x) & 0xffff) +#define CODA_REG_BIT_HOST_IN_REQ 0x008 +#define CODA_REG_BIT_INT_CLEAR 0x00c +#define CODA_REG_BIT_INT_CLEAR_SET 0x1 +#define CODA_REG_BIT_INT_STATUS 0x010 +#define CODA_REG_BIT_CODE_RESET 0x014 +#define CODA_REG_RESET_ENABLE (1 << 0) +#define CODA_REG_BIT_CUR_PC 0x018 + +/* Static SW registers */ +#define CODA_REG_BIT_CODE_BUF_ADDR 0x100 +#define CODA_REG_BIT_WORK_BUF_ADDR 0x104 +#define CODA_REG_BIT_PARA_BUF_ADDR 0x108 +#define CODA_REG_BIT_STREAM_CTRL 0x10c +#define CODA7_STREAM_BUF_PIC_RESET (1 << 4) +#define CODADX6_STREAM_BUF_PIC_RESET (1 << 3) +#define CODA7_STREAM_BUF_PIC_FLUSH (1 << 3) +#define CODADX6_STREAM_BUF_PIC_FLUSH (1 << 2) +#define CODA7_STREAM_BUF_DYNALLOC_EN (1 << 5) +#define CODADX6_STREAM_BUF_DYNALLOC_EN (1 << 4) +#define CODA_STREAM_CHKDIS_OFFSET (1 << 1) +#define CODA_STREAM_ENDIAN_SELECT (1 << 0) +#define CODA_REG_BIT_FRAME_MEM_CTRL 0x110 +#define CODA_IMAGE_ENDIAN_SELECT (1 << 0) +#define CODA_REG_BIT_RD_PTR(x) (0x120 + 8 * (x)) +#define CODA_REG_BIT_WR_PTR(x) (0x124 + 8 * (x)) +#define CODA_REG_BIT_SEARCH_RAM_BASE_ADDR 0x140 +#define CODA_REG_BIT_BUSY 0x160 +#define CODA_REG_BIT_BUSY_FLAG 1 +#define CODA_REG_BIT_RUN_COMMAND 0x164 +#define CODA_COMMAND_SEQ_INIT 1 +#define CODA_COMMAND_SEQ_END 2 +#define CODA_COMMAND_PIC_RUN 3 +#define CODA_COMMAND_SET_FRAME_BUF 4 +#define CODA_COMMAND_ENCODE_HEADER 5 +#define CODA_COMMAND_ENC_PARA_SET 6 +#define CODA_COMMAND_DEC_PARA_SET 7 +#define CODA_COMMAND_DEC_BUF_FLUSH 8 +#define CODA_COMMAND_RC_CHANGE_PARAMETER 9 +#define CODA_COMMAND_FIRMWARE_GET 0xf +#define CODA_REG_BIT_RUN_INDEX 0x168 +#define CODA_INDEX_SET(x) ((x) & 0x3) +#define CODA_REG_BIT_RUN_COD_STD 0x16c +#define CODADX6_MODE_DECODE_MP4 0 +#define CODADX6_MODE_ENCODE_MP4 1 +#define CODADX6_MODE_DECODE_H264 2 +#define CODADX6_MODE_ENCODE_H264 3 +#define CODA7_MODE_DECODE_H264 0 +#define CODA7_MODE_DECODE_VC1 1 +#define CODA7_MODE_DECODE_MP2 2 +#define CODA7_MODE_DECODE_MP4 3 +#define CODA7_MODE_DECODE_DV3 3 +#define CODA7_MODE_DECODE_RV 4 +#define CODA7_MODE_DECODE_MJPG 5 +#define CODA7_MODE_ENCODE_H264 8 +#define CODA7_MODE_ENCODE_MP4 11 +#define CODA7_MODE_ENCODE_MJPG 13 +#define CODA_MODE_INVALID 0xffff +#define CODA_REG_BIT_INT_ENABLE 0x170 +#define CODA_INT_INTERRUPT_ENABLE (1 << 3) + +/* + * Commands' mailbox: + * registers with offsets in the range 0x180-0x1d0 + * have different meaning depending on the command being + * issued. + */ + +/* Encoder Sequence Initialization */ +#define CODA_CMD_ENC_SEQ_BB_START 0x180 +#define CODA_CMD_ENC_SEQ_BB_SIZE 0x184 +#define CODA_CMD_ENC_SEQ_OPTION 0x188 +#define CODA_OPTION_GAMMA_OFFSET 7 +#define CODA_OPTION_GAMMA_MASK 0x01 +#define CODA_OPTION_LIMITQP_OFFSET 6 +#define CODA_OPTION_LIMITQP_MASK 0x01 +#define CODA_OPTION_RCINTRAQP_OFFSET 5 +#define CODA_OPTION_RCINTRAQP_MASK 0x01 +#define CODA_OPTION_FMO_OFFSET 4 +#define CODA_OPTION_FMO_MASK 0x01 +#define CODA_OPTION_SLICEREPORT_OFFSET 1 +#define CODA_OPTION_SLICEREPORT_MASK 0x01 +#define CODA_CMD_ENC_SEQ_COD_STD 0x18c +#define CODA_STD_MPEG4 0 +#define CODA_STD_H263 1 +#define CODA_STD_H264 2 +#define CODA_STD_MJPG 3 +#define CODA_CMD_ENC_SEQ_SRC_SIZE 0x190 +#define CODA7_PICWIDTH_OFFSET 16 +#define CODA7_PICWIDTH_MASK 0xffff +#define CODADX6_PICWIDTH_OFFSET 10 +#define CODADX6_PICWIDTH_MASK 0x3ff +#define CODA_PICHEIGHT_OFFSET 0 +#define CODA_PICHEIGHT_MASK 0x3ff +#define CODA_CMD_ENC_SEQ_SRC_F_RATE 0x194 +#define CODA_CMD_ENC_SEQ_MP4_PARA 0x198 +#define CODA_MP4PARAM_VERID_OFFSET 6 +#define CODA_MP4PARAM_VERID_MASK 0x01 +#define CODA_MP4PARAM_INTRADCVLCTHR_OFFSET 2 +#define CODA_MP4PARAM_INTRADCVLCTHR_MASK 0x07 +#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET 1 +#define CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK 0x01 +#define CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET 0 +#define CODA_MP4PARAM_DATAPARTITIONENABLE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_263_PARA 0x19c +#define CODA_263PARAM_ANNEXJENABLE_OFFSET 2 +#define CODA_263PARAM_ANNEXJENABLE_MASK 0x01 +#define CODA_263PARAM_ANNEXKENABLE_OFFSET 1 +#define CODA_263PARAM_ANNEXKENABLE_MASK 0x01 +#define CODA_263PARAM_ANNEXTENABLE_OFFSET 0 +#define CODA_263PARAM_ANNEXTENABLE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_264_PARA 0x1a0 +#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET 12 +#define CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK 0x0f +#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET 8 +#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK 0x0f +#define CODA_264PARAM_DISABLEDEBLK_OFFSET 6 +#define CODA_264PARAM_DISABLEDEBLK_MASK 0x01 +#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET 5 +#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK 0x01 +#define CODA_264PARAM_CHROMAQPOFFSET_OFFSET 0 +#define CODA_264PARAM_CHROMAQPOFFSET_MASK 0x1f +#define CODA_CMD_ENC_SEQ_SLICE_MODE 0x1a4 +#define CODA_SLICING_SIZE_OFFSET 2 +#define CODA_SLICING_SIZE_MASK 0x3fffffff +#define CODA_SLICING_UNIT_OFFSET 1 +#define CODA_SLICING_UNIT_MASK 0x01 +#define CODA_SLICING_MODE_OFFSET 0 +#define CODA_SLICING_MODE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_GOP_SIZE 0x1a8 +#define CODA_GOP_SIZE_OFFSET 0 +#define CODA_GOP_SIZE_MASK 0x3f +#define CODA_CMD_ENC_SEQ_RC_PARA 0x1ac +#define CODA_RATECONTROL_AUTOSKIP_OFFSET 31 +#define CODA_RATECONTROL_AUTOSKIP_MASK 0x01 +#define CODA_RATECONTROL_INITIALDELAY_OFFSET 16 +#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7f +#define CODA_RATECONTROL_BITRATE_OFFSET 1 +#define CODA_RATECONTROL_BITRATE_MASK 0x7f +#define CODA_RATECONTROL_ENABLE_OFFSET 0 +#define CODA_RATECONTROL_ENABLE_MASK 0x01 +#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE 0x1b0 +#define CODA_CMD_ENC_SEQ_INTRA_REFRESH 0x1b4 +#define CODA_CMD_ENC_SEQ_FMO 0x1b8 +#define CODA_FMOPARAM_TYPE_OFFSET 4 +#define CODA_FMOPARAM_TYPE_MASK 1 +#define CODA_FMOPARAM_SLICENUM_OFFSET 0 +#define CODA_FMOPARAM_SLICENUM_MASK 0x0f +#define CODA_CMD_ENC_SEQ_RC_QP_MAX 0x1c8 +#define CODA_QPMAX_OFFSET 0 +#define CODA_QPMAX_MASK 0x3f +#define CODA_CMD_ENC_SEQ_RC_GAMMA 0x1cc +#define CODA_GAMMA_OFFSET 0 +#define CODA_GAMMA_MASK 0xffff +#define CODA_RET_ENC_SEQ_SUCCESS 0x1c0 + +/* Encoder Picture Run */ +#define CODA_CMD_ENC_PIC_SRC_ADDR_Y 0x180 +#define CODA_CMD_ENC_PIC_SRC_ADDR_CB 0x184 +#define CODA_CMD_ENC_PIC_SRC_ADDR_CR 0x188 +#define CODA_CMD_ENC_PIC_QS 0x18c +#define CODA_CMD_ENC_PIC_ROT_MODE 0x190 +#define CODA_CMD_ENC_PIC_OPTION 0x194 +#define CODA_CMD_ENC_PIC_BB_START 0x198 +#define CODA_CMD_ENC_PIC_BB_SIZE 0x19c +#define CODA_RET_ENC_PIC_TYPE 0x1c4 +#define CODA_RET_ENC_PIC_SLICE_NUM 0x1cc +#define CODA_RET_ENC_PIC_FLAG 0x1d0 + +/* Set Frame Buffer */ +#define CODA_CMD_SET_FRAME_BUF_NUM 0x180 +#define CODA_CMD_SET_FRAME_BUF_STRIDE 0x184 + +/* Encoder Header */ +#define CODA_CMD_ENC_HEADER_CODE 0x180 +#define CODA_GAMMA_OFFSET 0 +#define CODA_HEADER_H264_SPS 0 +#define CODA_HEADER_H264_PPS 1 +#define CODA_HEADER_MP4V_VOL 0 +#define CODA_HEADER_MP4V_VOS 1 +#define CODA_HEADER_MP4V_VIS 2 +#define CODA_CMD_ENC_HEADER_BB_START 0x184 +#define CODA_CMD_ENC_HEADER_BB_SIZE 0x188 + +/* Get Version */ +#define CODA_CMD_FIRMWARE_VERNUM 0x1c0 +#define CODA_FIRMWARE_PRODUCT(x) (((x) >> 16) & 0xffff) +#define CODA_FIRMWARE_MAJOR(x) (((x) >> 12) & 0x0f) +#define CODA_FIRMWARE_MINOR(x) (((x) >> 8) & 0x0f) +#define CODA_FIRMWARE_RELEASE(x) ((x) & 0xff) +#define CODA_FIRMWARE_VERNUM(product, major, minor, release) \ + ((product) << 16 | ((major) << 12) | \ + ((minor) << 8) | (release)) + +#endif From b6c14dc29757a546dd0992e5f721b69099e84705 Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Thu, 26 Jul 2012 05:54:19 -0300 Subject: [PATCH 0326/5375] [media] Visstrim M10: Add support for Coda Support the codadx6 that is included in the i.MX27 SoC. Signed-off-by: Javier Martin Acked-by: Sascha Hauer Signed-off-by: Mauro Carvalho Chehab --- arch/arm/mach-imx/mach-imx27_visstrim_m10.c | 24 +++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c index f264ddddd47c..3194362aa782 100644 --- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c +++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c @@ -32,13 +32,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -233,10 +233,8 @@ static void __init visstrim_camera_init(void) static void __init visstrim_reserve(void) { /* reserve 4 MiB for mx2-camera */ - mx2_camera_base = memblock_alloc(MX2_CAMERA_BUF_SIZE, + mx2_camera_base = arm_memblock_steal(2 * MX2_CAMERA_BUF_SIZE, MX2_CAMERA_BUF_SIZE); - memblock_free(mx2_camera_base, MX2_CAMERA_BUF_SIZE); - memblock_remove(mx2_camera_base, MX2_CAMERA_BUF_SIZE); } /* GPIOs used as events for applications */ @@ -405,6 +403,23 @@ static const struct imx_ssi_platform_data visstrim_m10_ssi_pdata __initconst = { .flags = IMX_SSI_DMA | IMX_SSI_SYN, }; +/* coda */ + +static void __init visstrim_coda_init(void) +{ + struct platform_device *pdev; + int dma; + + pdev = imx27_add_coda(); + dma = dma_declare_coherent_memory(&pdev->dev, + mx2_camera_base + MX2_CAMERA_BUF_SIZE, + mx2_camera_base + MX2_CAMERA_BUF_SIZE, + MX2_CAMERA_BUF_SIZE, + DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); + if (!(dma & DMA_MEMORY_MAP)) + return; +} + static void __init visstrim_m10_revision(void) { int exp_version = 0; @@ -468,6 +483,7 @@ static void __init visstrim_m10_board_init(void) &iclink_tvp5150, sizeof(iclink_tvp5150)); gpio_led_register_device(0, &visstrim_m10_led_data); visstrim_camera_init(); + visstrim_coda_init(); } static void __init visstrim_m10_timer_init(void) From 8f0755c06b90a97e9e793cb474f216303cf88c2d Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Thu, 26 Jul 2012 05:55:18 -0300 Subject: [PATCH 0327/5375] [media] media: Add mem2mem deinterlacing driver Some video decoders such as tvp5150 provide separate video fields (V4L2_FIELD_SEQ_TB/BT). This driver uses dmaengine to convert this format to V4L2_FIELD_INTERLACED_TB/BT (weaving) or V4L2_FIELD_NONE (line doubling) so that the image can be displayed or processed. Of course there will be combing effect in the image but this can be accepted for some low quality applications. Currently only YUV420 and YUYV formats are supported but it can be extended later. Signed-off-by: Javier Martin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 8 + drivers/media/video/Makefile | 2 + drivers/media/video/m2m-deinterlace.c | 1119 +++++++++++++++++++++++++ 3 files changed, 1129 insertions(+) create mode 100644 drivers/media/video/m2m-deinterlace.c diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c95954d9692b..d5df1fdebf22 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1233,6 +1233,14 @@ config VIDEO_CODA Coda is a range of video codec IPs that supports H.264, MPEG-4, and other video formats. +config VIDEO_MEM2MEM_DEINTERLACE + tristate "Deinterlace support" + depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + help + Generic deinterlacing V4L2 driver. + config VIDEO_SAMSUNG_S5P_G2D tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 09f704a7f47c..b7ada61f08b1 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -190,6 +190,8 @@ obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o obj-$(CONFIG_VIDEO_CODA) += coda.o +obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o + obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ diff --git a/drivers/media/video/m2m-deinterlace.c b/drivers/media/video/m2m-deinterlace.c new file mode 100644 index 000000000000..11071679d5b2 --- /dev/null +++ b/drivers/media/video/m2m-deinterlace.c @@ -0,0 +1,1119 @@ +/* + * V4L2 deinterlacing support. + * + * Copyright (c) 2012 Vista Silicon S.L. + * Javier Martin + * + * 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 + +#define MEM2MEM_TEST_MODULE_NAME "mem2mem-deinterlace" + +MODULE_DESCRIPTION("mem2mem device which supports deinterlacing using dmaengine"); +MODULE_AUTHOR("Javier Martin v4l2_dev, "%s: " fmt, __func__, ## arg) + +struct deinterlace_fmt { + char *name; + u32 fourcc; + /* Types the format can be used for */ + u32 types; +}; + +static struct deinterlace_fmt formats[] = { + { + .name = "YUV 4:2:0 Planar", + .fourcc = V4L2_PIX_FMT_YUV420, + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, + { + .name = "YUYV 4:2:2", + .fourcc = V4L2_PIX_FMT_YUYV, + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(formats) + +/* Per-queue, driver-specific private data */ +struct deinterlace_q_data { + unsigned int width; + unsigned int height; + unsigned int sizeimage; + struct deinterlace_fmt *fmt; + enum v4l2_field field; +}; + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, +}; + +enum { + YUV420_DMA_Y_ODD, + YUV420_DMA_Y_EVEN, + YUV420_DMA_U_ODD, + YUV420_DMA_U_EVEN, + YUV420_DMA_V_ODD, + YUV420_DMA_V_EVEN, + YUV420_DMA_Y_ODD_DOUBLING, + YUV420_DMA_U_ODD_DOUBLING, + YUV420_DMA_V_ODD_DOUBLING, + YUYV_DMA_ODD, + YUYV_DMA_EVEN, + YUYV_DMA_EVEN_DOUBLING, +}; + +/* Source and destination queue data */ +static struct deinterlace_q_data q_data[2]; + +static struct deinterlace_q_data *get_q_data(enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &q_data[V4L2_M2M_SRC]; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &q_data[V4L2_M2M_DST]; + default: + BUG(); + } + return NULL; +} + +static struct deinterlace_fmt *find_format(struct v4l2_format *f) +{ + struct deinterlace_fmt *fmt; + unsigned int k; + + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &formats[k]; + if ((fmt->types & f->type) && + (fmt->fourcc == f->fmt.pix.pixelformat)) + break; + } + + if (k == NUM_FORMATS) + return NULL; + + return &formats[k]; +} + +struct deinterlace_dev { + struct v4l2_device v4l2_dev; + struct video_device *vfd; + + atomic_t busy; + struct mutex dev_mutex; + spinlock_t irqlock; + + struct dma_chan *dma_chan; + + struct v4l2_m2m_dev *m2m_dev; + struct vb2_alloc_ctx *alloc_ctx; +}; + +struct deinterlace_ctx { + struct deinterlace_dev *dev; + + /* Abort requested by m2m */ + int aborting; + enum v4l2_colorspace colorspace; + dma_cookie_t cookie; + struct v4l2_m2m_ctx *m2m_ctx; + struct dma_interleaved_template *xt; +}; + +/* + * mem2mem callbacks + */ +static int deinterlace_job_ready(void *priv) +{ + struct deinterlace_ctx *ctx = priv; + struct deinterlace_dev *pcdev = ctx->dev; + + if ((v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0) + && (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0) + && (atomic_read(&ctx->dev->busy) == 0)) { + dprintk(pcdev, "Task ready\n"); + return 1; + } + + dprintk(pcdev, "Task not ready to run\n"); + + return 0; +} + +static void deinterlace_job_abort(void *priv) +{ + struct deinterlace_ctx *ctx = priv; + struct deinterlace_dev *pcdev = ctx->dev; + + ctx->aborting = 1; + + dprintk(pcdev, "Aborting task\n"); + + v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx); +} + +static void deinterlace_lock(void *priv) +{ + struct deinterlace_ctx *ctx = priv; + struct deinterlace_dev *pcdev = ctx->dev; + mutex_lock(&pcdev->dev_mutex); +} + +static void deinterlace_unlock(void *priv) +{ + struct deinterlace_ctx *ctx = priv; + struct deinterlace_dev *pcdev = ctx->dev; + mutex_unlock(&pcdev->dev_mutex); +} + +static void dma_callback(void *data) +{ + struct deinterlace_ctx *curr_ctx = data; + struct deinterlace_dev *pcdev = curr_ctx->dev; + struct vb2_buffer *src_vb, *dst_vb; + + atomic_set(&pcdev->busy, 0); + + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + + v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); + + v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx); + + dprintk(pcdev, "dma transfers completed.\n"); +} + +static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op, + int do_callback) +{ + struct deinterlace_q_data *s_q_data, *d_q_data; + struct vb2_buffer *src_buf, *dst_buf; + struct deinterlace_dev *pcdev = ctx->dev; + struct dma_chan *chan = pcdev->dma_chan; + struct dma_device *dmadev = chan->device; + struct dma_async_tx_descriptor *tx; + unsigned int s_width, s_height; + unsigned int d_width, d_height; + unsigned int d_size, s_size; + dma_addr_t p_in, p_out; + enum dma_ctrl_flags flags; + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + + s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT); + s_width = s_q_data->width; + s_height = s_q_data->height; + s_size = s_width * s_height; + + d_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE); + d_width = d_q_data->width; + d_height = d_q_data->height; + d_size = d_width * d_height; + + p_in = (dma_addr_t)vb2_dma_contig_plane_dma_addr(src_buf, 0); + p_out = (dma_addr_t)vb2_dma_contig_plane_dma_addr(dst_buf, 0); + if (!p_in || !p_out) { + v4l2_err(&pcdev->v4l2_dev, + "Acquiring kernel pointers to buffers failed\n"); + return; + } + + switch (op) { + case YUV420_DMA_Y_ODD: + ctx->xt->numf = s_height / 2; + ctx->xt->sgl[0].size = s_width; + ctx->xt->sgl[0].icg = s_width; + ctx->xt->src_start = p_in; + ctx->xt->dst_start = p_out; + break; + case YUV420_DMA_Y_EVEN: + ctx->xt->numf = s_height / 2; + ctx->xt->sgl[0].size = s_width; + ctx->xt->sgl[0].icg = s_width; + ctx->xt->src_start = p_in + s_size / 2; + ctx->xt->dst_start = p_out + s_width; + break; + case YUV420_DMA_U_ODD: + ctx->xt->numf = s_height / 4; + ctx->xt->sgl[0].size = s_width / 2; + ctx->xt->sgl[0].icg = s_width / 2; + ctx->xt->src_start = p_in + s_size; + ctx->xt->dst_start = p_out + s_size; + break; + case YUV420_DMA_U_EVEN: + ctx->xt->numf = s_height / 4; + ctx->xt->sgl[0].size = s_width / 2; + ctx->xt->sgl[0].icg = s_width / 2; + ctx->xt->src_start = p_in + (9 * s_size) / 8; + ctx->xt->dst_start = p_out + s_size + s_width / 2; + break; + case YUV420_DMA_V_ODD: + ctx->xt->numf = s_height / 4; + ctx->xt->sgl[0].size = s_width / 2; + ctx->xt->sgl[0].icg = s_width / 2; + ctx->xt->src_start = p_in + (5 * s_size) / 4; + ctx->xt->dst_start = p_out + (5 * s_size) / 4; + break; + case YUV420_DMA_V_EVEN: + ctx->xt->numf = s_height / 4; + ctx->xt->sgl[0].size = s_width / 2; + ctx->xt->sgl[0].icg = s_width / 2; + ctx->xt->src_start = p_in + (11 * s_size) / 8; + ctx->xt->dst_start = p_out + (5 * s_size) / 4 + s_width / 2; + break; + case YUV420_DMA_Y_ODD_DOUBLING: + ctx->xt->numf = s_height / 2; + ctx->xt->sgl[0].size = s_width; + ctx->xt->sgl[0].icg = s_width; + ctx->xt->src_start = p_in; + ctx->xt->dst_start = p_out + s_width; + break; + case YUV420_DMA_U_ODD_DOUBLING: + ctx->xt->numf = s_height / 4; + ctx->xt->sgl[0].size = s_width / 2; + ctx->xt->sgl[0].icg = s_width / 2; + ctx->xt->src_start = p_in + s_size; + ctx->xt->dst_start = p_out + s_size + s_width / 2; + break; + case YUV420_DMA_V_ODD_DOUBLING: + ctx->xt->numf = s_height / 4; + ctx->xt->sgl[0].size = s_width / 2; + ctx->xt->sgl[0].icg = s_width / 2; + ctx->xt->src_start = p_in + (5 * s_size) / 4; + ctx->xt->dst_start = p_out + (5 * s_size) / 4 + s_width / 2; + break; + case YUYV_DMA_ODD: + ctx->xt->numf = s_height / 2; + ctx->xt->sgl[0].size = s_width * 2; + ctx->xt->sgl[0].icg = s_width * 2; + ctx->xt->src_start = p_in; + ctx->xt->dst_start = p_out; + break; + case YUYV_DMA_EVEN: + ctx->xt->numf = s_height / 2; + ctx->xt->sgl[0].size = s_width * 2; + ctx->xt->sgl[0].icg = s_width * 2; + ctx->xt->src_start = p_in + s_size; + ctx->xt->dst_start = p_out + s_width * 2; + break; + case YUYV_DMA_EVEN_DOUBLING: + default: + ctx->xt->numf = s_height / 2; + ctx->xt->sgl[0].size = s_width * 2; + ctx->xt->sgl[0].icg = s_width * 2; + ctx->xt->src_start = p_in; + ctx->xt->dst_start = p_out + s_width * 2; + break; + } + + /* Common parameters for al transfers */ + ctx->xt->frame_size = 1; + ctx->xt->dir = DMA_MEM_TO_MEM; + ctx->xt->src_sgl = false; + ctx->xt->dst_sgl = true; + flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | + DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SKIP_SRC_UNMAP; + + tx = dmadev->device_prep_interleaved_dma(chan, ctx->xt, flags); + if (tx == NULL) { + v4l2_warn(&pcdev->v4l2_dev, "DMA interleaved prep error\n"); + return; + } + + if (do_callback) { + tx->callback = dma_callback; + tx->callback_param = ctx; + } + + ctx->cookie = dmaengine_submit(tx); + if (dma_submit_error(ctx->cookie)) { + v4l2_warn(&pcdev->v4l2_dev, + "DMA submit error %d with src=0x%x dst=0x%x len=0x%x\n", + ctx->cookie, p_in, p_out, s_size * 3/2); + return; + } + + dma_async_issue_pending(chan); +} + +static void deinterlace_device_run(void *priv) +{ + struct deinterlace_ctx *ctx = priv; + struct deinterlace_q_data *dst_q_data; + + atomic_set(&ctx->dev->busy, 1); + + dprintk(ctx->dev, "%s: DMA try issue.\n", __func__); + + dst_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE); + + /* + * 4 possible field conversions are possible at the moment: + * V4L2_FIELD_SEQ_TB --> V4L2_FIELD_INTERLACED_TB: + * two separate fields in the same input buffer are interlaced + * in the output buffer using weaving. Top field comes first. + * V4L2_FIELD_SEQ_TB --> V4L2_FIELD_NONE: + * top field from the input buffer is copied to the output buffer + * using line doubling. Bottom field from the input buffer is discarded. + * V4L2_FIELD_SEQ_BT --> V4L2_FIELD_INTERLACED_BT: + * two separate fields in the same input buffer are interlaced + * in the output buffer using weaving. Bottom field comes first. + * V4L2_FIELD_SEQ_BT --> V4L2_FIELD_NONE: + * bottom field from the input buffer is copied to the output buffer + * using line doubling. Top field from the input buffer is discarded. + */ + switch (dst_q_data->fmt->fourcc) { + case V4L2_PIX_FMT_YUV420: + switch (dst_q_data->field) { + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + dprintk(ctx->dev, "%s: yuv420 interlaced tb.\n", + __func__); + deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD, 0); + deinterlace_issue_dma(ctx, YUV420_DMA_Y_EVEN, 0); + deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD, 0); + deinterlace_issue_dma(ctx, YUV420_DMA_U_EVEN, 0); + deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD, 0); + deinterlace_issue_dma(ctx, YUV420_DMA_V_EVEN, 1); + break; + case V4L2_FIELD_NONE: + default: + dprintk(ctx->dev, "%s: yuv420 interlaced line doubling.\n", + __func__); + deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD, 0); + deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD_DOUBLING, 0); + deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD, 0); + deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD_DOUBLING, 0); + deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD, 0); + deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD_DOUBLING, 1); + break; + } + break; + case V4L2_PIX_FMT_YUYV: + default: + switch (dst_q_data->field) { + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + dprintk(ctx->dev, "%s: yuyv interlaced_tb.\n", + __func__); + deinterlace_issue_dma(ctx, YUYV_DMA_ODD, 0); + deinterlace_issue_dma(ctx, YUYV_DMA_EVEN, 1); + break; + case V4L2_FIELD_NONE: + default: + dprintk(ctx->dev, "%s: yuyv interlaced line doubling.\n", + __func__); + deinterlace_issue_dma(ctx, YUYV_DMA_ODD, 0); + deinterlace_issue_dma(ctx, YUYV_DMA_EVEN_DOUBLING, 1); + break; + } + break; + } + + dprintk(ctx->dev, "%s: DMA issue done.\n", __func__); +} + +/* + * video ioctls + */ +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strlcpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); + strlcpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); + strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->card)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT + | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) +{ + int i, num; + struct deinterlace_fmt *fmt; + + num = 0; + + for (i = 0; i < NUM_FORMATS; ++i) { + if (formats[i].types & type) { + /* index-th format of type type found ? */ + if (num == f->index) + break; + /* Correct type but haven't reached our index yet, + * just increment per-type index */ + ++num; + } + } + + if (i < NUM_FORMATS) { + /* Format found */ + fmt = &formats[i]; + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; + return 0; + } + + /* Format not found */ + return -EINVAL; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return enum_fmt(f, MEM2MEM_CAPTURE); +} + +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return enum_fmt(f, MEM2MEM_OUTPUT); +} + +static int vidioc_g_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f) +{ + struct vb2_queue *vq; + struct deinterlace_q_data *q_data; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(f->type); + + f->fmt.pix.width = q_data->width; + f->fmt.pix.height = q_data->height; + f->fmt.pix.field = q_data->field; + f->fmt.pix.pixelformat = q_data->fmt->fourcc; + + switch (q_data->fmt->fourcc) { + case V4L2_PIX_FMT_YUV420: + f->fmt.pix.bytesperline = q_data->width * 3 / 2; + break; + case V4L2_PIX_FMT_YUYV: + default: + f->fmt.pix.bytesperline = q_data->width * 2; + } + + f->fmt.pix.sizeimage = q_data->sizeimage; + f->fmt.pix.colorspace = ctx->colorspace; + + return 0; +} + +static int vidioc_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_g_fmt(priv, f); +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_g_fmt(priv, f); +} + +static int vidioc_try_fmt(struct v4l2_format *f, struct deinterlace_fmt *fmt) +{ + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_YUV420: + f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2; + break; + case V4L2_PIX_FMT_YUYV: + default: + f->fmt.pix.bytesperline = f->fmt.pix.width * 2; + } + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct deinterlace_fmt *fmt; + struct deinterlace_ctx *ctx = priv; + + fmt = find_format(f); + if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; + + f->fmt.pix.colorspace = ctx->colorspace; + + if (f->fmt.pix.field != V4L2_FIELD_INTERLACED_TB && + f->fmt.pix.field != V4L2_FIELD_INTERLACED_BT && + f->fmt.pix.field != V4L2_FIELD_NONE) + f->fmt.pix.field = V4L2_FIELD_INTERLACED_TB; + + return vidioc_try_fmt(f, fmt); +} + +static int vidioc_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct deinterlace_fmt *fmt; + + fmt = find_format(f); + if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; + + if (!f->fmt.pix.colorspace) + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + + if (f->fmt.pix.field != V4L2_FIELD_SEQ_TB && + f->fmt.pix.field != V4L2_FIELD_SEQ_BT) + f->fmt.pix.field = V4L2_FIELD_SEQ_TB; + + return vidioc_try_fmt(f, fmt); +} + +static int vidioc_s_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f) +{ + struct deinterlace_q_data *q_data; + struct vb2_queue *vq; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(f->type); + if (!q_data) + return -EINVAL; + + if (vb2_is_busy(vq)) { + v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + q_data->fmt = find_format(f); + if (!q_data->fmt) { + v4l2_err(&ctx->dev->v4l2_dev, + "Couldn't set format type %d, wxh: %dx%d. fmt: %d, field: %d\n", + f->type, f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.pixelformat, f->fmt.pix.field); + return -EINVAL; + } + + q_data->width = f->fmt.pix.width; + q_data->height = f->fmt.pix.height; + q_data->field = f->fmt.pix.field; + + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_YUV420: + f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2; + q_data->sizeimage = (q_data->width * q_data->height * 3) / 2; + break; + case V4L2_PIX_FMT_YUYV: + default: + f->fmt.pix.bytesperline = f->fmt.pix.width * 2; + q_data->sizeimage = q_data->width * q_data->height * 2; + } + + dprintk(ctx->dev, + "Setting format for type %d, wxh: %dx%d, fmt: %d, field: %d\n", + f->type, q_data->width, q_data->height, q_data->fmt->fourcc, + q_data->field); + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = vidioc_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + return vidioc_s_fmt(priv, f); +} + +static int vidioc_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct deinterlace_ctx *ctx = priv; + int ret; + + ret = vidioc_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + ret = vidioc_s_fmt(priv, f); + if (!ret) + ctx->colorspace = f->fmt.pix.colorspace; + + return ret; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct deinterlace_ctx *ctx = priv; + + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct deinterlace_ctx *ctx = priv; + + return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct deinterlace_ctx *ctx = priv; + + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct deinterlace_ctx *ctx = priv; + + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct deinterlace_q_data *s_q_data, *d_q_data; + struct deinterlace_ctx *ctx = priv; + + s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT); + d_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE); + + /* Check that src and dst queues have the same pix format */ + if (s_q_data->fmt->fourcc != d_q_data->fmt->fourcc) { + v4l2_err(&ctx->dev->v4l2_dev, + "src and dst formats don't match.\n"); + return -EINVAL; + } + + /* Check that input and output deinterlacing types are compatible */ + switch (s_q_data->field) { + case V4L2_FIELD_SEQ_BT: + if (d_q_data->field != V4L2_FIELD_NONE && + d_q_data->field != V4L2_FIELD_INTERLACED_BT) { + v4l2_err(&ctx->dev->v4l2_dev, + "src and dst field conversion [(%d)->(%d)] not supported.\n", + s_q_data->field, d_q_data->field); + return -EINVAL; + } + break; + case V4L2_FIELD_SEQ_TB: + if (d_q_data->field != V4L2_FIELD_NONE && + d_q_data->field != V4L2_FIELD_INTERLACED_TB) { + v4l2_err(&ctx->dev->v4l2_dev, + "src and dst field conversion [(%d)->(%d)] not supported.\n", + s_q_data->field, d_q_data->field); + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct deinterlace_ctx *ctx = priv; + + return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); +} + +static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, + .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, + + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, +}; + + +/* + * Queue operations + */ +struct vb2_dc_conf { + struct device *dev; +}; + +static int deinterlace_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq); + struct deinterlace_q_data *q_data; + unsigned int size, count = *nbuffers; + + q_data = get_q_data(vq->type); + + switch (q_data->fmt->fourcc) { + case V4L2_PIX_FMT_YUV420: + size = q_data->width * q_data->height * 3 / 2; + break; + case V4L2_PIX_FMT_YUYV: + default: + size = q_data->width * q_data->height * 2; + } + + *nplanes = 1; + *nbuffers = count; + sizes[0] = size; + + alloc_ctxs[0] = ctx->dev->alloc_ctx; + + dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); + + return 0; +} + +static int deinterlace_buf_prepare(struct vb2_buffer *vb) +{ + struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct deinterlace_q_data *q_data; + + dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); + + q_data = get_q_data(vb->vb2_queue->type); + + 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; + } + + vb2_set_plane_payload(vb, 0, q_data->sizeimage); + + return 0; +} + +static void deinterlace_buf_queue(struct vb2_buffer *vb) +{ + struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); +} + +static struct vb2_ops deinterlace_qops = { + .queue_setup = deinterlace_queue_setup, + .buf_prepare = deinterlace_buf_prepare, + .buf_queue = deinterlace_buf_queue, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct deinterlace_ctx *ctx = priv; + int ret; + + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->ops = &deinterlace_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + q_data[V4L2_M2M_SRC].fmt = &formats[0]; + q_data[V4L2_M2M_SRC].width = 640; + q_data[V4L2_M2M_SRC].height = 480; + q_data[V4L2_M2M_SRC].sizeimage = (640 * 480 * 3) / 2; + q_data[V4L2_M2M_SRC].field = V4L2_FIELD_SEQ_TB; + + 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 | VB2_USERPTR; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->ops = &deinterlace_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + q_data[V4L2_M2M_DST].fmt = &formats[0]; + q_data[V4L2_M2M_DST].width = 640; + q_data[V4L2_M2M_DST].height = 480; + q_data[V4L2_M2M_DST].sizeimage = (640 * 480 * 3) / 2; + q_data[V4L2_M2M_SRC].field = V4L2_FIELD_INTERLACED_TB; + + return vb2_queue_init(dst_vq); +} + +/* + * File operations + */ +static int deinterlace_open(struct file *file) +{ + struct deinterlace_dev *pcdev = video_drvdata(file); + struct deinterlace_ctx *ctx = NULL; + + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + file->private_data = ctx; + ctx->dev = pcdev; + + ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); + if (IS_ERR(ctx->m2m_ctx)) { + int ret = PTR_ERR(ctx->m2m_ctx); + + kfree(ctx); + return ret; + } + + ctx->xt = kzalloc(sizeof(struct dma_async_tx_descriptor) + + sizeof(struct data_chunk), GFP_KERNEL); + if (!ctx->xt) { + int ret = PTR_ERR(ctx->xt); + + kfree(ctx); + return ret; + } + + ctx->colorspace = V4L2_COLORSPACE_REC709; + + dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); + + return 0; +} + +static int deinterlace_release(struct file *file) +{ + struct deinterlace_dev *pcdev = video_drvdata(file); + struct deinterlace_ctx *ctx = file->private_data; + + dprintk(pcdev, "Releasing instance %p\n", ctx); + + v4l2_m2m_ctx_release(ctx->m2m_ctx); + kfree(ctx->xt); + kfree(ctx); + + return 0; +} + +static unsigned int deinterlace_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct deinterlace_ctx *ctx = file->private_data; + int ret; + + deinterlace_lock(ctx); + ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); + deinterlace_unlock(ctx); + + return ret; +} + +static int deinterlace_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct deinterlace_ctx *ctx = file->private_data; + + return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); +} + +static const struct v4l2_file_operations deinterlace_fops = { + .owner = THIS_MODULE, + .open = deinterlace_open, + .release = deinterlace_release, + .poll = deinterlace_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = deinterlace_mmap, +}; + +static struct video_device deinterlace_videodev = { + .name = MEM2MEM_NAME, + .fops = &deinterlace_fops, + .ioctl_ops = &deinterlace_ioctl_ops, + .minor = -1, + .release = video_device_release, +}; + +static struct v4l2_m2m_ops m2m_ops = { + .device_run = deinterlace_device_run, + .job_ready = deinterlace_job_ready, + .job_abort = deinterlace_job_abort, + .lock = deinterlace_lock, + .unlock = deinterlace_unlock, +}; + +static int deinterlace_probe(struct platform_device *pdev) +{ + struct deinterlace_dev *pcdev; + struct video_device *vfd; + dma_cap_mask_t mask; + int ret = 0; + + pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL); + if (!pcdev) + return -ENOMEM; + + spin_lock_init(&pcdev->irqlock); + + dma_cap_zero(mask); + dma_cap_set(DMA_INTERLEAVE, mask); + pcdev->dma_chan = dma_request_channel(mask, NULL, pcdev); + if (!pcdev->dma_chan) + goto free_dev; + + if (!dma_has_cap(DMA_INTERLEAVE, pcdev->dma_chan->device->cap_mask)) { + v4l2_err(&pcdev->v4l2_dev, "DMA does not support INTERLEAVE\n"); + goto rel_dma; + } + + ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev); + if (ret) + goto rel_dma; + + atomic_set(&pcdev->busy, 0); + mutex_init(&pcdev->dev_mutex); + + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto unreg_dev; + } + + *vfd = deinterlace_videodev; + vfd->lock = &pcdev->dev_mutex; + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); + if (ret) { + v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n"); + goto rel_vdev; + } + + video_set_drvdata(vfd, pcdev); + snprintf(vfd->name, sizeof(vfd->name), "%s", deinterlace_videodev.name); + pcdev->vfd = vfd; + v4l2_info(&pcdev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME + " Device registered as /dev/video%d\n", vfd->num); + + platform_set_drvdata(pdev, pcdev); + + pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(pcdev->alloc_ctx)) { + v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n"); + ret = PTR_ERR(pcdev->alloc_ctx); + goto err_ctx; + } + + pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops); + if (IS_ERR(pcdev->m2m_dev)) { + v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(pcdev->m2m_dev); + goto err_m2m; + } + + return 0; + + v4l2_m2m_release(pcdev->m2m_dev); +err_m2m: + video_unregister_device(pcdev->vfd); +err_ctx: + vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); +rel_vdev: + video_device_release(vfd); +unreg_dev: + v4l2_device_unregister(&pcdev->v4l2_dev); +rel_dma: + dma_release_channel(pcdev->dma_chan); +free_dev: + kfree(pcdev); + + return ret; +} + +static int deinterlace_remove(struct platform_device *pdev) +{ + struct deinterlace_dev *pcdev = + (struct deinterlace_dev *)platform_get_drvdata(pdev); + + v4l2_info(&pcdev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME); + v4l2_m2m_release(pcdev->m2m_dev); + video_unregister_device(pcdev->vfd); + v4l2_device_unregister(&pcdev->v4l2_dev); + vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); + dma_release_channel(pcdev->dma_chan); + kfree(pcdev); + + return 0; +} + +static struct platform_driver deinterlace_pdrv = { + .probe = deinterlace_probe, + .remove = deinterlace_remove, + .driver = { + .name = MEM2MEM_NAME, + .owner = THIS_MODULE, + }, +}; + +static void __exit deinterlace_exit(void) +{ + platform_driver_unregister(&deinterlace_pdrv); +} + +static int __init deinterlace_init(void) +{ + return platform_driver_register(&deinterlace_pdrv); +} + +module_init(deinterlace_init); +module_exit(deinterlace_exit); + From 84b3bd462393133e5ba6949c32a26f46b5e9f93d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 6 Aug 2012 09:06:34 -0300 Subject: [PATCH 0328/5375] [media] m2m-deinterlace: fix two warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media/video/m2m-deinterlace.c: In function ‘deinterlace_issue_dma’: drivers/media/video/m2m-deinterlace.c:363:3: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘dma_addr_t’ [-Wformat] drivers/media/video/m2m-deinterlace.c:363:3: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 5 has type ‘dma_addr_t’ [-Wformat] Cc: Javier Martin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/m2m-deinterlace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/m2m-deinterlace.c b/drivers/media/video/m2m-deinterlace.c index 11071679d5b2..a38c15201d1d 100644 --- a/drivers/media/video/m2m-deinterlace.c +++ b/drivers/media/video/m2m-deinterlace.c @@ -362,7 +362,8 @@ static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op, if (dma_submit_error(ctx->cookie)) { v4l2_warn(&pcdev->v4l2_dev, "DMA submit error %d with src=0x%x dst=0x%x len=0x%x\n", - ctx->cookie, p_in, p_out, s_size * 3/2); + ctx->cookie, (unsigned)p_in, (unsigned)p_out, + s_size * 3/2); return; } From 062a15cf24f838749f8f40a8ca6fd33af84052db Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Thu, 26 Jul 2012 05:57:30 -0300 Subject: [PATCH 0329/5375] [media] i.MX27: Visstrim_M10: Add support for deinterlacing driver Visstrim_M10 have a tvp5150 whose video output must be deinterlaced. The new mem2mem deinterlacing driver is very useful for that purpose. Signed-off-by: Javier Martin Signed-off-by: Mauro Carvalho Chehab --- arch/arm/mach-imx/mach-imx27_visstrim_m10.c | 27 ++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c index 3194362aa782..821d6aac411c 100644 --- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c +++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c @@ -233,7 +233,7 @@ static void __init visstrim_camera_init(void) static void __init visstrim_reserve(void) { /* reserve 4 MiB for mx2-camera */ - mx2_camera_base = arm_memblock_steal(2 * MX2_CAMERA_BUF_SIZE, + mx2_camera_base = arm_memblock_steal(3 * MX2_CAMERA_BUF_SIZE, MX2_CAMERA_BUF_SIZE); } @@ -420,6 +420,30 @@ static void __init visstrim_coda_init(void) return; } +/* DMA deinterlace */ +static struct platform_device visstrim_deinterlace = { + .name = "m2m-deinterlace", + .id = 0, +}; + +static void __init visstrim_deinterlace_init(void) +{ + int ret = -ENOMEM; + struct platform_device *pdev = &visstrim_deinterlace; + int dma; + + ret = platform_device_register(pdev); + + dma = dma_declare_coherent_memory(&pdev->dev, + mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE, + mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE, + MX2_CAMERA_BUF_SIZE, + DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); + if (!(dma & DMA_MEMORY_MAP)) + return; +} + + static void __init visstrim_m10_revision(void) { int exp_version = 0; @@ -482,6 +506,7 @@ static void __init visstrim_m10_board_init(void) platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0, &iclink_tvp5150, sizeof(iclink_tvp5150)); gpio_led_register_device(0, &visstrim_m10_led_data); + visstrim_deinterlace_init(); visstrim_camera_init(); visstrim_coda_init(); } From 33eb46a7c2bdd10f9a761390ce1bf51169ff537a Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Mon, 30 Jul 2012 04:37:30 -0300 Subject: [PATCH 0330/5375] [media] media: i.MX27: Fix mx2_emmaprp mem2mem driver clocks This driver wasn't converted to the new clock framework (e038ed50a4a767add205094c035b6943e7b30140). Signed-off-by: Javier Martin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mx2_emmaprp.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/media/video/mx2_emmaprp.c b/drivers/media/video/mx2_emmaprp.c index 5f8a6f5b98f9..728cac339d1a 100644 --- a/drivers/media/video/mx2_emmaprp.c +++ b/drivers/media/video/mx2_emmaprp.c @@ -209,7 +209,7 @@ struct emmaprp_dev { int irq_emma; void __iomem *base_emma; - struct clk *clk_emma; + struct clk *clk_emma_ahb, *clk_emma_ipg; struct resource *res_emma; struct v4l2_m2m_dev *m2m_dev; @@ -804,7 +804,8 @@ static int emmaprp_open(struct file *file) return ret; } - clk_enable(pcdev->clk_emma); + clk_prepare_enable(pcdev->clk_emma_ipg); + clk_prepare_enable(pcdev->clk_emma_ahb); ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1]; ctx->q_data[V4L2_M2M_DST].fmt = &formats[0]; @@ -820,7 +821,8 @@ static int emmaprp_release(struct file *file) dprintk(pcdev, "Releasing instance %p\n", ctx); - clk_disable(pcdev->clk_emma); + clk_disable_unprepare(pcdev->clk_emma_ahb); + clk_disable_unprepare(pcdev->clk_emma_ipg); v4l2_m2m_ctx_release(ctx->m2m_ctx); kfree(ctx); @@ -880,9 +882,15 @@ static int emmaprp_probe(struct platform_device *pdev) spin_lock_init(&pcdev->irqlock); - pcdev->clk_emma = clk_get(&pdev->dev, NULL); - if (IS_ERR(pcdev->clk_emma)) { - ret = PTR_ERR(pcdev->clk_emma); + pcdev->clk_emma_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(pcdev->clk_emma_ipg)) { + ret = PTR_ERR(pcdev->clk_emma_ipg); + goto free_dev; + } + + pcdev->clk_emma_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(pcdev->clk_emma_ipg)) { + ret = PTR_ERR(pcdev->clk_emma_ahb); goto free_dev; } @@ -891,12 +899,12 @@ static int emmaprp_probe(struct platform_device *pdev) if (irq_emma < 0 || res_emma == NULL) { dev_err(&pdev->dev, "Missing platform resources data\n"); ret = -ENODEV; - goto free_clk; + goto free_dev; } ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev); if (ret) - goto free_clk; + goto free_dev; mutex_init(&pcdev->dev_mutex); @@ -969,8 +977,6 @@ rel_vdev: video_device_release(vfd); unreg_dev: v4l2_device_unregister(&pcdev->v4l2_dev); -free_clk: - clk_put(pcdev->clk_emma); free_dev: kfree(pcdev); @@ -987,7 +993,6 @@ static int emmaprp_remove(struct platform_device *pdev) v4l2_m2m_release(pcdev->m2m_dev); vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); v4l2_device_unregister(&pcdev->v4l2_dev); - clk_put(pcdev->clk_emma); kfree(pcdev); return 0; From 69abe02e785f29b52658b74c8084f8d9f4432f19 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 4 Aug 2012 16:03:04 -0300 Subject: [PATCH 0331/5375] [media] dvb-usb-v2: Fix cypress firmware compilation ERROR: "usbv2_cypress_load_firmware" [drivers/media/dvb/dvb-usb-v2/dvb-usb-az6007.ko] undefined! Cypress fimware will never be compiled properly, as the Makefile rule is wrong. Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb-v2/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb-v2/Makefile b/drivers/media/dvb/dvb-usb-v2/Makefile index a98319cd216e..4438dcd6fd49 100644 --- a/drivers/media/dvb/dvb-usb-v2/Makefile +++ b/drivers/media/dvb/dvb-usb-v2/Makefile @@ -1,7 +1,8 @@ dvb_usbv2-objs = dvb_usb_core.o dvb_usb_urb.o usb_urb.o obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o -obj-$(DVB_USB_CYPRESS_FIRMWARE) += dvb_usb_cypress_firmware.o +dvb_usb_cypress_firmware-objs = cypress_firmware.o +obj-$(CONFIG_DVB_USB_CYPRESS_FIRMWARE) += dvb_usb_cypress_firmware.o dvb-usb-af9015-objs = af9015.o obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o From 115ad55e9c10bad551357a4f4d43d57aaa776bf0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 4 Aug 2012 16:05:13 -0300 Subject: [PATCH 0332/5375] [media] dvb-usb-v2: Don't ask user to select Cypress firmware module The dvb-usb-v2 cypress firmware module is not optional, as drivers won't work without it. So, instead of opening a menu for the user to manually select, let the drivers that need it to select, hiding this option from the Kconfig menu. Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb-v2/Kconfig | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/media/dvb/dvb-usb-v2/Kconfig b/drivers/media/dvb/dvb-usb-v2/Kconfig index 81f0f1c03c1c..98b8fb59cd28 100644 --- a/drivers/media/dvb/dvb-usb-v2/Kconfig +++ b/drivers/media/dvb/dvb-usb-v2/Kconfig @@ -16,14 +16,6 @@ config DVB_USB_V2 config DVB_USB_CYPRESS_FIRMWARE tristate "Cypress firmware helper routines" depends on DVB_USB_V2 - help - Common firmware download routine for various Cypress USB interface - chips. - - Supported models are: - Cypress AN2135 - Cypress AN2235 - Cypress FX2 config DVB_USB_AF9015 tristate "Afatech AF9015 DVB-T USB2.0 support" From 255d52f25485e8fe244d15266b76428ba545f022 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 4 Aug 2012 16:05:34 -0300 Subject: [PATCH 0333/5375] [media] az6007: convert it to use dvb-usb-v2 Change it to use dvb-usb-v2. The driver should be working as before. The only functional changes should be at the driver debug logs. This driver needs the cypress firmware load, so, auto-selects it. Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb-v2/Kconfig | 9 + drivers/media/dvb/dvb-usb-v2/Makefile | 3 + .../dvb/{dvb-usb => dvb-usb-v2}/az6007.c | 384 ++++++++---------- drivers/media/dvb/dvb-usb/Kconfig | 8 - drivers/media/dvb/dvb-usb/Makefile | 3 - 5 files changed, 175 insertions(+), 232 deletions(-) rename drivers/media/dvb/{dvb-usb => dvb-usb-v2}/az6007.c (65%) diff --git a/drivers/media/dvb/dvb-usb-v2/Kconfig b/drivers/media/dvb/dvb-usb-v2/Kconfig index 98b8fb59cd28..e7ff148e4a29 100644 --- a/drivers/media/dvb/dvb-usb-v2/Kconfig +++ b/drivers/media/dvb/dvb-usb-v2/Kconfig @@ -68,6 +68,15 @@ config DVB_USB_AU6610 help Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. +config DVB_USB_AZ6007 + tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" + depends on DVB_USB_V2 + select DVB_USB_CYPRESS_FIRMWARE + select DVB_DRXK if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE + help + Say Y here to support the AZ6007 receivers like Terratec H7. + config DVB_USB_CE6230 tristate "Intel CE6230 DVB-T USB2.0 support" depends on DVB_USB_V2 diff --git a/drivers/media/dvb/dvb-usb-v2/Makefile b/drivers/media/dvb/dvb-usb-v2/Makefile index 4438dcd6fd49..a784bf4af4e4 100644 --- a/drivers/media/dvb/dvb-usb-v2/Makefile +++ b/drivers/media/dvb/dvb-usb-v2/Makefile @@ -16,6 +16,9 @@ obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o dvb-usb-au6610-objs = au6610.o obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o +dvb-usb-az6007-objs = az6007.o +obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o + dvb-usb-ce6230-objs = ce6230.o obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb-v2/az6007.c similarity index 65% rename from drivers/media/dvb/dvb-usb/az6007.c rename to drivers/media/dvb/dvb-usb-v2/az6007.c index 86861e6f86d2..9d2ad4965dee 100644 --- a/drivers/media/dvb/dvb-usb/az6007.c +++ b/drivers/media/dvb/dvb-usb-v2/az6007.c @@ -24,20 +24,14 @@ #include "drxk.h" #include "mt2063.h" #include "dvb_ca_en50221.h" +#include "dvb_usb.h" +#include "cypress_firmware.h" -#define DVB_USB_LOG_PREFIX "az6007" -#include "dvb-usb.h" +#define AZ6007_FIRMWARE "dvb-usb-terratec-h7-az6007.fw" -/* debug */ -int dvb_usb_az6007_debug; -module_param_named(debug, dvb_usb_az6007_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." - DVB_USB_DEBUG_STATUS); - -#define deb_info(args...) dprintk(dvb_usb_az6007_debug, 0x01, args) -#define deb_xfer(args...) dprintk(dvb_usb_az6007_debug, 0x02, args) -#define deb_rc(args...) dprintk(dvb_usb_az6007_debug, 0x04, args) -#define deb_fe(args...) dprintk(dvb_usb_az6007_debug, 0x08, args) +static int az6007_xfer_debug; +module_param_named(xfer_debug, az6007_xfer_debug, int, 0644); +MODULE_PARM_DESC(xfer_debug, "Enable xfer debug"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -75,18 +69,13 @@ static struct drxk_config terratec_h7_drxk = { static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { + struct az6007_device_state *st = fe_to_priv(fe); struct dvb_usb_adapter *adap = fe->sec_priv; - struct az6007_device_state *st; int status = 0; - deb_info("%s: %s\n", __func__, enable ? "enable" : "disable"); + pr_debug("%s: %s\n", __func__, enable ? "enable" : "disable"); - if (!adap) - return -EINVAL; - - st = adap->dev->priv; - - if (!st) + if (!adap || !st) return -EINVAL; if (enable) @@ -113,13 +102,16 @@ static int __az6007_read(struct usb_device *udev, u8 req, u16 value, USB_TYPE_VENDOR | USB_DIR_IN, value, index, b, blen, 5000); if (ret < 0) { - warn("usb read operation failed. (%d)", ret); + pr_warn("usb read operation failed. (%d)\n", ret); return -EIO; } - deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, - index); - debug_dump(b, blen, deb_xfer); + if (az6007_xfer_debug) { + printk(KERN_DEBUG "az6007: IN req: %02x, value: %04x, index: %04x\n", + req, value, index); + print_hex_dump_bytes("az6007: payload: ", + DUMP_PREFIX_NONE, b, blen); + } return ret; } @@ -145,13 +137,16 @@ static int __az6007_write(struct usb_device *udev, u8 req, u16 value, { int ret; - deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value, - index); - debug_dump(b, blen, deb_xfer); + if (az6007_xfer_debug) { + printk(KERN_DEBUG "az6007: OUT req: %02x, value: %04x, index: %04x\n", + req, value, index); + print_hex_dump_bytes("az6007: payload: ", + DUMP_PREFIX_NONE, b, blen); + } if (blen > 64) { - err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n", - blen); + pr_err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n", + blen); return -EOPNOTSUPP; } @@ -161,7 +156,7 @@ static int __az6007_write(struct usb_device *udev, u8 req, u16 value, USB_TYPE_VENDOR | USB_DIR_OUT, value, index, b, blen, 5000); if (ret != blen) { - err("usb write operation failed. (%d)", ret); + pr_err("usb write operation failed. (%d)\n", ret); return -EIO; } @@ -184,11 +179,11 @@ static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value, return ret; } -static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +static int az6007_streaming_ctrl(struct dvb_frontend *fe, int onoff) { - struct dvb_usb_device *d = adap->dev; + struct dvb_usb_device *d = fe_to_d(fe); - deb_info("%s: %s", __func__, onoff ? "enable" : "disable"); + pr_debug("%s: %s\n", __func__, onoff ? "enable" : "disable"); return az6007_write(d, 0xbc, onoff, 0, NULL, 0); } @@ -196,7 +191,7 @@ static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) /* remote control stuff (does not work with my box) */ static int az6007_rc_query(struct dvb_usb_device *d) { - struct az6007_device_state *st = d->priv; + struct az6007_device_state *st = d_to_priv(d); unsigned code = 0; az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10); @@ -224,7 +219,7 @@ static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int address) { struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = (struct az6007_device_state *)d->priv; + struct az6007_device_state *state = d_to_priv(d); int ret; u8 req; @@ -249,7 +244,7 @@ static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, ret = az6007_read(d, req, value, index, b, blen); if (ret < 0) { - warn("usb in operation failed. (%d)", ret); + pr_warn("usb in operation failed. (%d)\n", ret); ret = -EINVAL; } else { ret = b[0]; @@ -266,7 +261,7 @@ static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, u8 value) { struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = (struct az6007_device_state *)d->priv; + struct az6007_device_state *state = d_to_priv(d); int ret; u8 req; @@ -274,7 +269,7 @@ static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, u16 index; int blen; - deb_info("%s %d", __func__, slot); + pr_debug("%s(), slot %d\n", __func__, slot); if (slot != 0) return -EINVAL; @@ -286,7 +281,7 @@ static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, ret = az6007_write(d, req, value1, index, NULL, blen); if (ret != 0) - warn("usb out operation failed. (%d)", ret); + pr_warn("usb out operation failed. (%d)\n", ret); mutex_unlock(&state->ca_mutex); return ret; @@ -297,7 +292,7 @@ static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca, u8 address) { struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = (struct az6007_device_state *)d->priv; + struct az6007_device_state *state = d_to_priv(d); int ret; u8 req; @@ -322,14 +317,14 @@ static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca, ret = az6007_read(d, req, value, index, b, blen); if (ret < 0) { - warn("usb in operation failed. (%d)", ret); + pr_warn("usb in operation failed. (%d)\n", ret); ret = -EINVAL; } else { if (b[0] == 0) - warn("Read CI IO error"); + pr_warn("Read CI IO error\n"); ret = b[1]; - deb_info("read cam data = %x from 0x%x", b[1], value); + pr_debug("read cam data = %x from 0x%x\n", b[1], value); } mutex_unlock(&state->ca_mutex); @@ -343,7 +338,7 @@ static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca, u8 value) { struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = (struct az6007_device_state *)d->priv; + struct az6007_device_state *state = d_to_priv(d); int ret; u8 req; @@ -362,7 +357,7 @@ static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca, ret = az6007_write(d, req, value1, index, NULL, blen); if (ret != 0) { - warn("usb out operation failed. (%d)", ret); + pr_warn("usb out operation failed. (%d)\n", ret); goto failed; } @@ -393,7 +388,7 @@ static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) ret = az6007_read(d, req, value, index, b, blen); if (ret < 0) { - warn("usb in operation failed. (%d)", ret); + pr_warn("usb in operation failed. (%d)\n", ret); ret = -EIO; } else{ ret = b[0]; @@ -405,7 +400,7 @@ static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) { struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = (struct az6007_device_state *)d->priv; + struct az6007_device_state *state = d_to_priv(d); int ret, i; u8 req; @@ -422,7 +417,7 @@ static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) ret = az6007_write(d, req, value, index, NULL, blen); if (ret != 0) { - warn("usb out operation failed. (%d)", ret); + pr_warn("usb out operation failed. (%d)\n", ret); goto failed; } @@ -434,7 +429,7 @@ static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) ret = az6007_write(d, req, value, index, NULL, blen); if (ret != 0) { - warn("usb out operation failed. (%d)", ret); + pr_warn("usb out operation failed. (%d)\n", ret); goto failed; } @@ -442,7 +437,7 @@ static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) msleep(100); if (CI_CamReady(ca, slot)) { - deb_info("CAM Ready"); + pr_debug("CAM Ready\n"); break; } } @@ -461,7 +456,7 @@ static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) { struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = (struct az6007_device_state *)d->priv; + struct az6007_device_state *state = d_to_priv(d); int ret; u8 req; @@ -469,7 +464,7 @@ static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) u16 index; int blen; - deb_info("%s", __func__); + pr_debug("%s()\n", __func__); mutex_lock(&state->ca_mutex); req = 0xC7; value = 1; @@ -478,7 +473,7 @@ static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) ret = az6007_write(d, req, value, index, NULL, blen); if (ret != 0) { - warn("usb out operation failed. (%d)", ret); + pr_warn("usb out operation failed. (%d)\n", ret); goto failed; } @@ -490,7 +485,7 @@ failed: static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) { struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; - struct az6007_device_state *state = (struct az6007_device_state *)d->priv; + struct az6007_device_state *state = d_to_priv(d); int ret; u8 req; u16 value; @@ -510,7 +505,7 @@ static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int o ret = az6007_read(d, req, value, index, b, blen); if (ret < 0) { - warn("usb in operation failed. (%d)", ret); + pr_warn("usb in operation failed. (%d)\n", ret); ret = -EIO; } else ret = 0; @@ -530,12 +525,12 @@ static void az6007_ci_uninit(struct dvb_usb_device *d) { struct az6007_device_state *state; - deb_info("%s", __func__); + pr_debug("%s()\n", __func__); if (NULL == d) return; - state = (struct az6007_device_state *)d->priv; + state = d_to_priv(d); if (NULL == state) return; @@ -548,16 +543,15 @@ static void az6007_ci_uninit(struct dvb_usb_device *d) } -static int az6007_ci_init(struct dvb_usb_adapter *a) +static int az6007_ci_init(struct dvb_usb_adapter *adap) { - struct dvb_usb_device *d = a->dev; - struct az6007_device_state *state = (struct az6007_device_state *)d->priv; + struct dvb_usb_device *d = adap_to_d(adap); + struct az6007_device_state *state = adap_to_priv(adap); int ret; - deb_info("%s", __func__); + pr_debug("%s()\n", __func__); mutex_init(&state->ca_mutex); - state->ca.owner = THIS_MODULE; state->ca.read_attribute_mem = az6007_ci_read_attribute_mem; state->ca.write_attribute_mem = az6007_ci_write_attribute_mem; @@ -569,49 +563,51 @@ static int az6007_ci_init(struct dvb_usb_adapter *a) state->ca.poll_slot_status = az6007_ci_poll_slot_status; state->ca.data = d; - ret = dvb_ca_en50221_init(&a->dvb_adap, + ret = dvb_ca_en50221_init(&adap->dvb_adap, &state->ca, 0, /* flags */ 1);/* n_slots */ if (ret != 0) { - err("Cannot initialize CI: Error %d.", ret); + pr_err("Cannot initialize CI: Error %d.\n", ret); memset(&state->ca, 0, sizeof(state->ca)); return ret; } - deb_info("CI initialized."); + pr_debug("CI initialized.\n"); return 0; } -static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) +static int az6007_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6]) { - struct az6007_device_state *st = d->priv; + struct dvb_usb_device *d = adap_to_d(adap); + struct az6007_device_state *st = adap_to_priv(adap); int ret; ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6); memcpy(mac, st->data, 6); if (ret > 0) - deb_info("%s: mac is %pM\n", __func__, mac); + pr_debug("%s: mac is %pM\n", __func__, mac); return ret; } static int az6007_frontend_attach(struct dvb_usb_adapter *adap) { - struct az6007_device_state *st = adap->dev->priv; + struct az6007_device_state *st = adap_to_priv(adap); + struct dvb_usb_device *d = adap_to_d(adap); - deb_info("attaching demod drxk"); + pr_debug("attaching demod drxk\n"); - adap->fe_adap[0].fe = dvb_attach(drxk_attach, &terratec_h7_drxk, - &adap->dev->i2c_adap); - if (!adap->fe_adap[0].fe) + adap->fe[0] = dvb_attach(drxk_attach, &terratec_h7_drxk, + &d->i2c_adap); + if (!adap->fe[0]) return -EINVAL; - adap->fe_adap[0].fe->sec_priv = adap; - st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl; - adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + adap->fe[0]->sec_priv = adap; + st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl; + adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; az6007_ci_init(adap); @@ -620,28 +616,30 @@ static int az6007_frontend_attach(struct dvb_usb_adapter *adap) static int az6007_tuner_attach(struct dvb_usb_adapter *adap) { - deb_info("attaching tuner mt2063"); + struct dvb_usb_device *d = adap_to_d(adap); + + pr_debug("attaching tuner mt2063\n"); /* Attach mt2063 to DVB-C frontend */ - if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) - adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1); - if (!dvb_attach(mt2063_attach, adap->fe_adap[0].fe, + if (adap->fe[0]->ops.i2c_gate_ctrl) + adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 1); + if (!dvb_attach(mt2063_attach, adap->fe[0], &az6007_mt2063_config, - &adap->dev->i2c_adap)) + &d->i2c_adap)) return -EINVAL; - if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl) - adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0); + if (adap->fe[0]->ops.i2c_gate_ctrl) + adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 0); return 0; } int az6007_power_ctrl(struct dvb_usb_device *d, int onoff) { - struct az6007_device_state *st = d->priv; + struct az6007_device_state *st = d_to_priv(d); int ret; - deb_info("%s()\n", __func__); + pr_debug("%s()\n", __func__); if (!st->warm) { mutex_init(&st->mutex); @@ -694,7 +692,7 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - struct az6007_device_state *st = d->priv; + struct az6007_device_state *st = d_to_priv(d); int i, j, len; int ret = 0; u16 index; @@ -717,9 +715,8 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], * the first xfer has just 1 byte length. * Need to join both into one operation */ - if (dvb_usb_az6007_debug & 2) - printk(KERN_DEBUG - "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ", + if (az6007_xfer_debug) + printk(KERN_DEBUG "az6007: I2C W/R addr=0x%x len=%d/%d\n", addr, msgs[i].len, msgs[i + 1].len); req = AZ6007_I2C_RD; index = msgs[i].buf[0]; @@ -729,42 +726,29 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], ret = __az6007_read(d->udev, req, value, index, st->data, length); if (ret >= len) { - for (j = 0; j < len; j++) { + for (j = 0; j < len; j++) msgs[i + 1].buf[j] = st->data[j + 5]; - if (dvb_usb_az6007_debug & 2) - printk(KERN_CONT - "0x%02x ", - msgs[i + 1].buf[j]); - } } else ret = -EIO; i++; } else if (!(msgs[i].flags & I2C_M_RD)) { /* write bytes */ - if (dvb_usb_az6007_debug & 2) - printk(KERN_DEBUG - "az6007 I2C xfer write addr=0x%x len=%d: ", + if (az6007_xfer_debug) + printk(KERN_DEBUG "az6007: I2C W addr=0x%x len=%d\n", addr, msgs[i].len); req = AZ6007_I2C_WR; index = msgs[i].buf[0]; value = addr | (1 << 8); length = msgs[i].len - 1; len = msgs[i].len - 1; - if (dvb_usb_az6007_debug & 2) - printk(KERN_CONT "(0x%02x) ", msgs[i].buf[0]); - for (j = 0; j < len; j++) { + for (j = 0; j < len; j++) st->data[j] = msgs[i].buf[j + 1]; - if (dvb_usb_az6007_debug & 2) - printk(KERN_CONT "0x%02x ", - st->data[j]); - } ret = __az6007_write(d->udev, req, value, index, st->data, length); } else { /* read bytes */ - if (dvb_usb_az6007_debug & 2) - printk(KERN_DEBUG - "az6007 I2C xfer read addr=0x%x len=%d: ", + if (az6007_xfer_debug) + printk(KERN_DEBUG "az6007: I2C R addr=0x%x len=%d\n", addr, msgs[i].len); req = AZ6007_I2C_RD; index = msgs[i].buf[0]; @@ -773,15 +757,9 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], len = msgs[i].len; ret = __az6007_read(d->udev, req, value, index, st->data, length); - for (j = 0; j < len; j++) { + for (j = 0; j < len; j++) msgs[i].buf[j] = st->data[j + 5]; - if (dvb_usb_az6007_debug & 2) - printk(KERN_CONT - "0x%02x ", st->data[j + 5]); - } } - if (dvb_usb_az6007_debug & 2) - printk(KERN_CONT "\n"); if (ret < 0) goto err; } @@ -789,7 +767,7 @@ err: mutex_unlock(&st->mutex); if (ret < 0) { - info("%s ERROR: %i", __func__, ret); + pr_info("%s ERROR: %i\n", __func__, ret); return ret; } return num; @@ -805,151 +783,115 @@ static struct i2c_algorithm az6007_i2c_algo = { .functionality = az6007_i2c_func, }; -int az6007_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, int *cold) +int az6007_identify_state(struct dvb_usb_device *d, const char **name) { int ret; u8 *mac; + pr_debug("Identifying az6007 state\n"); + mac = kmalloc(6, GFP_ATOMIC); if (!mac) return -ENOMEM; /* Try to read the mac address */ - ret = __az6007_read(udev, AZ6007_READ_DATA, 6, 0, mac, 6); + ret = __az6007_read(d->udev, AZ6007_READ_DATA, 6, 0, mac, 6); if (ret == 6) - *cold = 0; + ret = WARM; else - *cold = 1; + ret = COLD; kfree(mac); - if (*cold) { - __az6007_write(udev, 0x09, 1, 0, NULL, 0); - __az6007_write(udev, 0x00, 0, 0, NULL, 0); - __az6007_write(udev, 0x00, 0, 0, NULL, 0); + if (ret == COLD) { + __az6007_write(d->udev, 0x09, 1, 0, NULL, 0); + __az6007_write(d->udev, 0x00, 0, 0, NULL, 0); + __az6007_write(d->udev, 0x00, 0, 0, NULL, 0); } - deb_info("Device is on %s state\n", *cold ? "warm" : "cold"); - return 0; + pr_debug("Device is on %s state\n", + ret == WARM ? "warm" : "cold"); + return ret; } -static struct dvb_usb_device_properties az6007_properties; - static void az6007_usb_disconnect(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); az6007_ci_uninit(d); - dvb_usb_device_exit(intf); + dvb_usbv2_disconnect(intf); } -static int az6007_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { - return dvb_usb_device_init(intf, &az6007_properties, - THIS_MODULE, NULL, adapter_nr); + pr_debug("Getting az6007 Remote Control properties\n"); + + rc->allowed_protos = RC_TYPE_NEC; + rc->query = az6007_rc_query; + rc->interval = 400; + + return 0; } +static int az6007_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + pr_debug("Loading az6007 firmware\n"); + + return usbv2_cypress_load_firmware(d->udev, fw, CYPRESS_FX2); +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_device_properties az6007_props = { + .driver_name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .firmware = AZ6007_FIRMWARE, + + .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct az6007_device_state), + .i2c_algo = &az6007_i2c_algo, + .tuner_attach = az6007_tuner_attach, + .frontend_attach = az6007_frontend_attach, + .streaming_ctrl = az6007_streaming_ctrl, + .get_rc_config = az6007_get_rc_config, + .read_mac_address = az6007_read_mac_addr, + .download_firmware = az6007_download_firmware, + .identify_state = az6007_identify_state, + .power_ctrl = az6007_power_ctrl, + .num_adapters = 1, + .adapter = { + { .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), } + } +}; + static struct usb_device_id az6007_usb_table[] = { - {USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2)}, + {DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007, + &az6007_props, "Azurewave 6007", RC_MAP_EMPTY)}, + {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7, + &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, + {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2, + &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)}, {0}, }; MODULE_DEVICE_TABLE(usb, az6007_usb_table); -static struct dvb_usb_device_properties az6007_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-terratec-h7-az6007.fw", - .no_reconnect = 1, - .size_of_priv = sizeof(struct az6007_device_state), - .identify_state = az6007_identify_state, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .streaming_ctrl = az6007_streaming_ctrl, - .tuner_attach = az6007_tuner_attach, - .frontend_attach = az6007_frontend_attach, - - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 10, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 4096, - } - } - }, - } } - } }, - .power_ctrl = az6007_power_ctrl, - .read_mac_address = az6007_read_mac_addr, - - .rc.core = { - .rc_interval = 400, - .rc_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, - .module_name = "az6007", - .rc_query = az6007_rc_query, - .allowed_protos = RC_TYPE_NEC, - }, - .i2c_algo = &az6007_i2c_algo, - - .num_device_descs = 2, - .devices = { - { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)", - .cold_ids = { &az6007_usb_table[0], NULL }, - .warm_ids = { NULL }, - }, - { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)", - .cold_ids = { &az6007_usb_table[1], &az6007_usb_table[2], NULL }, - .warm_ids = { NULL }, - }, - { NULL }, - } -}; - /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver az6007_usb_driver = { - .name = "dvb_usb_az6007", - .probe = az6007_usb_probe, - .disconnect = az6007_usb_disconnect, + .name = KBUILD_MODNAME, .id_table = az6007_usb_table, + .probe = dvb_usbv2_probe, + .disconnect = az6007_usb_disconnect, + .suspend = dvb_usbv2_suspend, + .resume = dvb_usbv2_resume, + .no_dynamic_id = 1, + .soft_unbind = 1, }; -/* module stuff */ -static int __init az6007_usb_module_init(void) -{ - int result; - deb_info("az6007 usb module init\n"); - - result = usb_register(&az6007_usb_driver); - if (result) { - err("usb_register failed. (%d)", result); - return result; - } - - return 0; -} - -static void __exit az6007_usb_module_exit(void) -{ - /* deregister this driver from the USB subsystem */ - deb_info("az6007 usb module exit\n"); - usb_deregister(&az6007_usb_driver); -} - -module_init(az6007_usb_module_init); -module_exit(az6007_usb_module_exit); +module_usb_driver(az6007_usb_driver); MODULE_AUTHOR("Henry Wang "); MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones"); -MODULE_VERSION("1.1"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(AZ6007_FIRMWARE); diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 67b91b74976f..29bba9a24875 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -296,14 +296,6 @@ config DVB_USB_FRIIO help Say Y here to support the Japanese DTV receiver Friio. -config DVB_USB_AZ6007 - tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" - depends on DVB_USB - select DVB_DRXK if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE - help - Say Y here to support theAfatech AF9005 based DVB-T/DVB-C receivers. - config DVB_USB_AZ6027 tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" depends on DVB_USB diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 4b70599b38d9..5261c7dae982 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -69,9 +69,6 @@ obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o dvb-usb-friio-objs = friio.o friio-fe.o obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o -dvb-usb-az6007-objs = az6007.o -obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o - dvb-usb-az6027-objs = az6027.o obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o From 916c81422a3692cc55164c3905f5d0ce50bc5962 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 4 Aug 2012 21:39:41 -0300 Subject: [PATCH 0334/5375] [media] az6007: fix the I2C W+R logic The test for I2C W+R will never be true. Fix it. Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb-v2/az6007.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/dvb-usb-v2/az6007.c b/drivers/media/dvb/dvb-usb-v2/az6007.c index 9d2ad4965dee..35ed915c0d93 100644 --- a/drivers/media/dvb/dvb-usb-v2/az6007.c +++ b/drivers/media/dvb/dvb-usb-v2/az6007.c @@ -707,7 +707,7 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], addr = msgs[i].addr << 1; if (((i + 1) < num) && (msgs[i].len == 1) - && (!msgs[i].flags & I2C_M_RD) + && ((msgs[i].flags & I2C_M_RD) != I2C_M_RD) && (msgs[i + 1].flags & I2C_M_RD) && (msgs[i].addr == msgs[i + 1].addr)) { /* From caeb5ac7f989e107df589534cc059a47e63e7aa7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 5 Aug 2012 00:10:13 -0300 Subject: [PATCH 0335/5375] [media] az6007: Fix the number of parameters for QAM setup Remove those warning messages: [ 121.696758] drxk: SCU_RESULT_INVPAR while sending cmd 0x0203 with params: [ 121.703401] drxk: 02 00 00 00 10 00 07 00 03 02 .......... [ 121.703587] drxk: Warning -22 on QAMDemodulatorCommand Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb-v2/az6007.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/dvb/dvb-usb-v2/az6007.c b/drivers/media/dvb/dvb-usb-v2/az6007.c index 35ed915c0d93..4671eaa62f8d 100644 --- a/drivers/media/dvb/dvb-usb-v2/az6007.c +++ b/drivers/media/dvb/dvb-usb-v2/az6007.c @@ -64,6 +64,7 @@ static struct drxk_config terratec_h7_drxk = { .no_i2c_bridge = false, .chunk_size = 64, .mpeg_out_clk_strength = 0x02, + .qam_demod_parameter_count = 2, .microcode_name = "dvb-usb-terratec-h7-drxk.fw", }; From 3cb9f4e28269124d304e1886809f4f9fa9899790 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 5 Aug 2012 09:22:23 -0300 Subject: [PATCH 0336/5375] [media] az6007: rename "st" to "state" at az6007_power_ctrl() On all other parts, this var is called state. So, use the same name here, to be consistent. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb-v2/az6007.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/dvb-usb-v2/az6007.c b/drivers/media/dvb/dvb-usb-v2/az6007.c index 4671eaa62f8d..bb7f61de093b 100644 --- a/drivers/media/dvb/dvb-usb-v2/az6007.c +++ b/drivers/media/dvb/dvb-usb-v2/az6007.c @@ -637,13 +637,13 @@ static int az6007_tuner_attach(struct dvb_usb_adapter *adap) int az6007_power_ctrl(struct dvb_usb_device *d, int onoff) { - struct az6007_device_state *st = d_to_priv(d); + struct az6007_device_state *state = d_to_priv(d); int ret; pr_debug("%s()\n", __func__); - if (!st->warm) { - mutex_init(&st->mutex); + if (!state->warm) { + mutex_init(&state->mutex); ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0); if (ret < 0) @@ -674,7 +674,7 @@ int az6007_power_ctrl(struct dvb_usb_device *d, int onoff) if (ret < 0) return ret; - st->warm = true; + state->warm = true; return 0; } From 0ca477ea8dceb13eb2f91b13d8ff25a7b3113f7e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 5 Aug 2012 09:23:17 -0300 Subject: [PATCH 0337/5375] [media] az6007: make all functions static There's no reason why those functions shouldn't be static. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb-v2/az6007.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb-v2/az6007.c b/drivers/media/dvb/dvb-usb-v2/az6007.c index bb7f61de093b..4a0ee6420297 100644 --- a/drivers/media/dvb/dvb-usb-v2/az6007.c +++ b/drivers/media/dvb/dvb-usb-v2/az6007.c @@ -635,7 +635,7 @@ static int az6007_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -int az6007_power_ctrl(struct dvb_usb_device *d, int onoff) +static int az6007_power_ctrl(struct dvb_usb_device *d, int onoff) { struct az6007_device_state *state = d_to_priv(d); int ret; @@ -784,7 +784,7 @@ static struct i2c_algorithm az6007_i2c_algo = { .functionality = az6007_i2c_func, }; -int az6007_identify_state(struct dvb_usb_device *d, const char **name) +static int az6007_identify_state(struct dvb_usb_device *d, const char **name) { int ret; u8 *mac; From 6da74b1da2caf8a659cde68a8faafb766e04037c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 5 Aug 2012 09:25:34 -0300 Subject: [PATCH 0338/5375] [media] az6007: handle CI during suspend/resume The dvb-usb-v2 core doesn't know anything about CI. So, the driver needs to handle it by hand. This patch stops CI just before stopping URB's/RC, and restarts it before URB/RC start. It should be noticed that suspend/resume is not yet working properly, as the PM model requires the implementation of reset_resume: dvb_usb_az6007 1-6:1.0: no reset_resume for driver dvb_usb_az6007? But this is not implemented there at dvb-usb-v2 yet. Cc: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb-v2/az6007.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb-v2/az6007.c b/drivers/media/dvb/dvb-usb-v2/az6007.c index 4a0ee6420297..420cb62fbc75 100644 --- a/drivers/media/dvb/dvb-usb-v2/az6007.c +++ b/drivers/media/dvb/dvb-usb-v2/az6007.c @@ -876,16 +876,37 @@ static struct usb_device_id az6007_usb_table[] = { MODULE_DEVICE_TABLE(usb, az6007_usb_table); +static int az6007_suspend(struct usb_interface *intf, pm_message_t msg) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + + az6007_ci_uninit(d); + return dvb_usbv2_suspend(intf, msg); +} + +static int az6007_resume(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + struct dvb_usb_adapter *adap = &d->adapter[0]; + + az6007_ci_init(adap); + return dvb_usbv2_resume(intf); +} + /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver az6007_usb_driver = { .name = KBUILD_MODNAME, .id_table = az6007_usb_table, .probe = dvb_usbv2_probe, .disconnect = az6007_usb_disconnect, - .suspend = dvb_usbv2_suspend, - .resume = dvb_usbv2_resume, .no_dynamic_id = 1, .soft_unbind = 1, + /* + * FIXME: need to implement reset_resume, likely with + * dvb-usb-v2 core support + */ + .suspend = az6007_suspend, + .resume = az6007_resume, }; module_usb_driver(az6007_usb_driver); From c3707357c6c651652a87a044445eabd7582f90a4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 5 Aug 2012 09:35:02 -0300 Subject: [PATCH 0339/5375] [media] az6007: Update copyright Update copyright comments after dvb-usb-v2 conversion. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb-v2/az6007.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb/dvb-usb-v2/az6007.c b/drivers/media/dvb/dvb-usb-v2/az6007.c index 420cb62fbc75..54f1221d930d 100644 --- a/drivers/media/dvb/dvb-usb-v2/az6007.c +++ b/drivers/media/dvb/dvb-usb-v2/az6007.c @@ -7,9 +7,9 @@ * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz * The original driver's license is GPL, as declared with MODULE_LICENSE() * - * Copyright (c) 2010-2011 Mauro Carvalho Chehab + * Copyright (c) 2010-2012 Mauro Carvalho Chehab * Driver modified by in order to work with upstream drxk driver, and - * tons of bugs got fixed. + * tons of bugs got fixed, and converted to use dvb-usb-v2. * * 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 From 16b854c889673d988285719bc020543a730f9ac6 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Fri, 3 Aug 2012 15:36:52 +0800 Subject: [PATCH 0340/5375] KVM: iommu: fix releasing unmapped page There are two bugs: - the 'error page' is forgot to be released [ it is unneeded after commit a2766325cf9f9, for backport, we still do kvm_release_pfn_clean for the error pfn ] - guest pages are always released regardless of the unmapped page (e,g, caused by hwpoison) Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- virt/kvm/iommu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index c03f1fb26701..6a67bea4019c 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -107,6 +107,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) */ pfn = kvm_pin_pages(slot, gfn, page_size); if (is_error_pfn(pfn)) { + kvm_release_pfn_clean(pfn); gfn += 1; continue; } @@ -300,6 +301,12 @@ static void kvm_iommu_put_pages(struct kvm *kvm, /* Get physical address */ phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn)); + + if (!phys) { + gfn++; + continue; + } + pfn = phys >> PAGE_SHIFT; /* Unmap address from IO address space */ From 6c8ee57be9350c5c2cafdd6a99d0462d528676e2 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Fri, 3 Aug 2012 15:37:54 +0800 Subject: [PATCH 0341/5375] KVM: introduce KVM_PFN_ERR_FAULT After that, the exported and un-inline function, get_fault_pfn, can be removed Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- arch/x86/kvm/mmu.c | 2 +- include/linux/kvm_host.h | 3 ++- virt/kvm/kvm_main.c | 12 +++--------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index aa9a987ddefb..9cf90c8d5843 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -2512,7 +2512,7 @@ static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, no_dirty_log); if (!slot) - return get_fault_pfn(); + return KVM_PFN_ERR_FAULT; hva = gfn_to_hva_memslot(slot, gfn); diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 3c16f0f1fe35..ef5554f47486 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -48,6 +48,8 @@ #define KVM_MAX_MMIO_FRAGMENTS \ (KVM_MMIO_SIZE / KVM_USER_MMIO_SIZE + KVM_EXTRA_MMIO_FRAGMENTS) +#define KVM_PFN_ERR_FAULT (-EFAULT) + /* * vcpu->requests bit members */ @@ -443,7 +445,6 @@ void kvm_release_pfn_clean(pfn_t pfn); void kvm_set_pfn_dirty(pfn_t pfn); void kvm_set_pfn_accessed(pfn_t pfn); void kvm_get_pfn(pfn_t pfn); -pfn_t get_fault_pfn(void); int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset, int len); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 14ec567816ab..ef0491645a10 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -939,12 +939,6 @@ static pfn_t get_bad_pfn(void) return -ENOENT; } -pfn_t get_fault_pfn(void) -{ - return -EFAULT; -} -EXPORT_SYMBOL_GPL(get_fault_pfn); - static pfn_t get_hwpoison_pfn(void) { return -EHWPOISON; @@ -1115,7 +1109,7 @@ static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, struct vm_area_struct *vma; if (atomic) - return get_fault_pfn(); + return KVM_PFN_ERR_FAULT; down_read(¤t->mm->mmap_sem); if (npages == -EHWPOISON || @@ -1127,7 +1121,7 @@ static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, vma = find_vma_intersection(current->mm, addr, addr+1); if (vma == NULL) - pfn = get_fault_pfn(); + pfn = KVM_PFN_ERR_FAULT; else if ((vma->vm_flags & VM_PFNMAP)) { pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; @@ -1135,7 +1129,7 @@ static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, } else { if (async && (vma->vm_flags & VM_WRITE)) *async = true; - pfn = get_fault_pfn(); + pfn = KVM_PFN_ERR_FAULT; } up_read(¤t->mm->mmap_sem); } else From e6c1502b3f933ace20c711ce34ab696f5a67086d Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Fri, 3 Aug 2012 15:38:36 +0800 Subject: [PATCH 0342/5375] KVM: introduce KVM_PFN_ERR_HWPOISON Then, get_hwpoison_pfn and is_hwpoison_pfn can be removed Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- arch/x86/kvm/mmu.c | 2 +- include/linux/kvm_host.h | 2 +- virt/kvm/kvm_main.c | 13 +------------ 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 9cf90c8d5843..d3cdf69da513 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -2649,7 +2649,7 @@ static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct * static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn) { kvm_release_pfn_clean(pfn); - if (is_hwpoison_pfn(pfn)) { + if (pfn == KVM_PFN_ERR_HWPOISON) { kvm_send_hwpoison_signal(gfn_to_hva(vcpu->kvm, gfn), current); return 0; } diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index ef5554f47486..840f44a096c9 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -49,6 +49,7 @@ (KVM_MMIO_SIZE / KVM_USER_MMIO_SIZE + KVM_EXTRA_MMIO_FRAGMENTS) #define KVM_PFN_ERR_FAULT (-EFAULT) +#define KVM_PFN_ERR_HWPOISON (-EHWPOISON) /* * vcpu->requests bit members @@ -395,7 +396,6 @@ extern struct page *bad_page; int is_error_page(struct page *page); int is_error_pfn(pfn_t pfn); -int is_hwpoison_pfn(pfn_t pfn); int is_noslot_pfn(pfn_t pfn); int is_invalid_pfn(pfn_t pfn); int kvm_is_error_hva(unsigned long addr); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index ef0491645a10..7fce2d5787ae 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -939,17 +939,6 @@ static pfn_t get_bad_pfn(void) return -ENOENT; } -static pfn_t get_hwpoison_pfn(void) -{ - return -EHWPOISON; -} - -int is_hwpoison_pfn(pfn_t pfn) -{ - return pfn == -EHWPOISON; -} -EXPORT_SYMBOL_GPL(is_hwpoison_pfn); - int is_noslot_pfn(pfn_t pfn) { return pfn == -ENOENT; @@ -1115,7 +1104,7 @@ static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, if (npages == -EHWPOISON || (!async && check_user_page_hwpoison(addr))) { up_read(¤t->mm->mmap_sem); - return get_hwpoison_pfn(); + return KVM_PFN_ERR_HWPOISON; } vma = find_vma_intersection(current->mm, addr, addr+1); From 950e95097b1c6573ef5e21061ccb56964278c45b Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Fri, 3 Aug 2012 15:39:19 +0800 Subject: [PATCH 0343/5375] KVM: introduce KVM_PFN_ERR_BAD Then, remove get_bad_pfn Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- include/linux/kvm_host.h | 1 + virt/kvm/kvm_main.c | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 840f44a096c9..b2cf3109822e 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -50,6 +50,7 @@ #define KVM_PFN_ERR_FAULT (-EFAULT) #define KVM_PFN_ERR_HWPOISON (-EHWPOISON) +#define KVM_PFN_ERR_BAD (-ENOENT) /* * vcpu->requests bit members diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 7fce2d5787ae..988b2339d846 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -934,11 +934,6 @@ int is_error_pfn(pfn_t pfn) } EXPORT_SYMBOL_GPL(is_error_pfn); -static pfn_t get_bad_pfn(void) -{ - return -ENOENT; -} - int is_noslot_pfn(pfn_t pfn) { return pfn == -ENOENT; @@ -1143,7 +1138,7 @@ static pfn_t __gfn_to_pfn(struct kvm *kvm, gfn_t gfn, bool atomic, bool *async, addr = gfn_to_hva(kvm, gfn); if (kvm_is_error_hva(addr)) - return get_bad_pfn(); + return KVM_PFN_ERR_BAD; return hva_to_pfn(addr, atomic, async, write_fault, writable); } From 83f09228d068911ac8797ae8d6febef886698936 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Fri, 3 Aug 2012 15:39:59 +0800 Subject: [PATCH 0344/5375] KVM: inline is_*_pfn functions These functions are exported and can not inline, move them to kvm_host.h to eliminate the overload of function call Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- include/linux/kvm_host.h | 19 ++++++++++++++++--- virt/kvm/kvm_main.c | 18 ------------------ 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index b2cf3109822e..19d91ceaf5e6 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,21 @@ #define KVM_PFN_ERR_HWPOISON (-EHWPOISON) #define KVM_PFN_ERR_BAD (-ENOENT) +static inline int is_error_pfn(pfn_t pfn) +{ + return IS_ERR_VALUE(pfn); +} + +static inline int is_noslot_pfn(pfn_t pfn) +{ + return pfn == -ENOENT; +} + +static inline int is_invalid_pfn(pfn_t pfn) +{ + return !is_noslot_pfn(pfn) && is_error_pfn(pfn); +} + /* * vcpu->requests bit members */ @@ -396,9 +412,6 @@ id_to_memslot(struct kvm_memslots *slots, int id) extern struct page *bad_page; int is_error_page(struct page *page); -int is_error_pfn(pfn_t pfn); -int is_noslot_pfn(pfn_t pfn); -int is_invalid_pfn(pfn_t pfn); int kvm_is_error_hva(unsigned long addr); int kvm_set_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 988b2339d846..eb73e5f13678 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -928,24 +928,6 @@ int is_error_page(struct page *page) } EXPORT_SYMBOL_GPL(is_error_page); -int is_error_pfn(pfn_t pfn) -{ - return IS_ERR_VALUE(pfn); -} -EXPORT_SYMBOL_GPL(is_error_pfn); - -int is_noslot_pfn(pfn_t pfn) -{ - return pfn == -ENOENT; -} -EXPORT_SYMBOL_GPL(is_noslot_pfn); - -int is_invalid_pfn(pfn_t pfn) -{ - return !is_noslot_pfn(pfn) && is_error_pfn(pfn); -} -EXPORT_SYMBOL_GPL(is_invalid_pfn); - struct page *get_bad_page(void) { return ERR_PTR(-ENOENT); From 9a592a953880fd6981955e69c1476ce541d9bd16 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Fri, 3 Aug 2012 15:40:39 +0800 Subject: [PATCH 0345/5375] KVM: remove the unused declare Remove it since it is not used anymore Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- include/linux/kvm_host.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 19d91ceaf5e6..e2dcc7cb2284 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -409,8 +409,6 @@ id_to_memslot(struct kvm_memslots *slots, int id) return slot; } -extern struct page *bad_page; - int is_error_page(struct page *page); int kvm_is_error_hva(unsigned long addr); int kvm_set_memory_region(struct kvm *kvm, From 6cede2e6794be6b0649f62d3681e0c4aff5a9270 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Fri, 3 Aug 2012 15:41:22 +0800 Subject: [PATCH 0346/5375] KVM: introduce KVM_ERR_PTR_BAD_PAGE It is used to eliminate the overload of function call and cleanup the code Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- include/linux/kvm_host.h | 9 +++++++-- virt/kvm/async_pf.c | 2 +- virt/kvm/kvm_main.c | 13 +------------ 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index e2dcc7cb2284..ce7c32950f4e 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -68,6 +68,13 @@ static inline int is_invalid_pfn(pfn_t pfn) return !is_noslot_pfn(pfn) && is_error_pfn(pfn); } +#define KVM_ERR_PTR_BAD_PAGE (ERR_PTR(-ENOENT)) + +static inline int is_error_page(struct page *page) +{ + return IS_ERR(page); +} + /* * vcpu->requests bit members */ @@ -409,7 +416,6 @@ id_to_memslot(struct kvm_memslots *slots, int id) return slot; } -int is_error_page(struct page *page); int kvm_is_error_hva(unsigned long addr); int kvm_set_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, @@ -436,7 +442,6 @@ void kvm_arch_flush_shadow(struct kvm *kvm); int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages, int nr_pages); -struct page *get_bad_page(void); struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn); void kvm_release_page_clean(struct page *page); diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 79722782d9d7..56f553391896 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -203,7 +203,7 @@ int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu) if (!work) return -ENOMEM; - work->page = get_bad_page(); + work->page = KVM_ERR_PTR_BAD_PAGE; INIT_LIST_HEAD(&work->queue); /* for list_del to work */ spin_lock(&vcpu->async_pf.lock); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index eb73e5f13678..93d3c6e063c8 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -922,17 +922,6 @@ void kvm_disable_largepages(void) } EXPORT_SYMBOL_GPL(kvm_disable_largepages); -int is_error_page(struct page *page) -{ - return IS_ERR(page); -} -EXPORT_SYMBOL_GPL(is_error_page); - -struct page *get_bad_page(void) -{ - return ERR_PTR(-ENOENT); -} - static inline unsigned long bad_hva(void) { return PAGE_OFFSET; @@ -1179,7 +1168,7 @@ static struct page *kvm_pfn_to_page(pfn_t pfn) WARN_ON(kvm_is_mmio_pfn(pfn)); if (is_error_pfn(pfn) || kvm_is_mmio_pfn(pfn)) - return get_bad_page(); + return KVM_ERR_PTR_BAD_PAGE; return pfn_to_page(pfn); } From cb9aaa30b133574b646d9d4766ef08a843211393 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Fri, 3 Aug 2012 15:42:10 +0800 Subject: [PATCH 0347/5375] KVM: do not release the error pfn After commit a2766325cf9f9, the error pfn is replaced by the error code, it need not be released anymore [ The patch has been compiling tested for powerpc ] Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- arch/powerpc/kvm/e500_tlb.c | 1 - arch/x86/kvm/mmu.c | 7 +++---- arch/x86/kvm/mmu_audit.c | 4 +--- arch/x86/kvm/paging_tmpl.h | 8 ++------ virt/kvm/iommu.c | 1 - virt/kvm/kvm_main.c | 16 +++++++++------- 6 files changed, 15 insertions(+), 22 deletions(-) diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c index c8f6c5826742..09ce5ac128f8 100644 --- a/arch/powerpc/kvm/e500_tlb.c +++ b/arch/powerpc/kvm/e500_tlb.c @@ -524,7 +524,6 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, if (is_error_pfn(pfn)) { printk(KERN_ERR "Couldn't get real page for gfn %lx!\n", (long)gfn); - kvm_release_pfn_clean(pfn); return; } diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index d3cdf69da513..9651c2cd0005 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -2496,7 +2496,9 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, rmap_recycle(vcpu, sptep, gfn); } } - kvm_release_pfn_clean(pfn); + + if (!is_error_pfn(pfn)) + kvm_release_pfn_clean(pfn); } static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) @@ -2648,7 +2650,6 @@ static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct * static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn) { - kvm_release_pfn_clean(pfn); if (pfn == KVM_PFN_ERR_HWPOISON) { kvm_send_hwpoison_signal(gfn_to_hva(vcpu->kvm, gfn), current); return 0; @@ -3273,8 +3274,6 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, if (!async) return false; /* *pfn has correct page already */ - kvm_release_pfn_clean(*pfn); - if (!prefault && can_do_async_pf(vcpu)) { trace_kvm_try_async_get_page(gva, gfn); if (kvm_find_async_pf_gfn(vcpu, gfn)) { diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c index ca403f9bb0f2..daff69e21150 100644 --- a/arch/x86/kvm/mmu_audit.c +++ b/arch/x86/kvm/mmu_audit.c @@ -116,10 +116,8 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level) gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt); pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn); - if (is_error_pfn(pfn)) { - kvm_release_pfn_clean(pfn); + if (is_error_pfn(pfn)) return; - } hpa = pfn << PAGE_SHIFT; if ((*sptep & PT64_BASE_ADDR_MASK) != hpa) diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index bb7cf01cae76..bf8c42bf50fe 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -370,10 +370,8 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte); pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte, true); pfn = gfn_to_pfn_atomic(vcpu->kvm, gpte_to_gfn(gpte)); - if (mmu_invalid_pfn(pfn)) { - kvm_release_pfn_clean(pfn); + if (mmu_invalid_pfn(pfn)) return; - } /* * we call mmu_set_spte() with host_writable = true because that @@ -448,10 +446,8 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw, gfn = gpte_to_gfn(gpte); pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn, pte_access & ACC_WRITE_MASK); - if (mmu_invalid_pfn(pfn)) { - kvm_release_pfn_clean(pfn); + if (mmu_invalid_pfn(pfn)) break; - } mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0, NULL, PT_PAGE_TABLE_LEVEL, gfn, diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index 6a67bea4019c..037cb6730e68 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -107,7 +107,6 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) */ pfn = kvm_pin_pages(slot, gfn, page_size); if (is_error_pfn(pfn)) { - kvm_release_pfn_clean(pfn); gfn += 1; continue; } diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 93d3c6e063c8..eafba99d1070 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -102,9 +102,6 @@ static bool largepages_enabled = true; bool kvm_is_mmio_pfn(pfn_t pfn) { - if (is_error_pfn(pfn)) - return false; - if (pfn_valid(pfn)) { int reserved; struct page *tail = pfn_to_page(pfn); @@ -1165,11 +1162,14 @@ EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic); static struct page *kvm_pfn_to_page(pfn_t pfn) { - WARN_ON(kvm_is_mmio_pfn(pfn)); - - if (is_error_pfn(pfn) || kvm_is_mmio_pfn(pfn)) + if (is_error_pfn(pfn)) return KVM_ERR_PTR_BAD_PAGE; + if (kvm_is_mmio_pfn(pfn)) { + WARN_ON(1); + return KVM_ERR_PTR_BAD_PAGE; + } + return pfn_to_page(pfn); } @@ -1193,7 +1193,9 @@ EXPORT_SYMBOL_GPL(kvm_release_page_clean); void kvm_release_pfn_clean(pfn_t pfn) { - if (!is_error_pfn(pfn) && !kvm_is_mmio_pfn(pfn)) + WARN_ON(is_error_pfn(pfn)); + + if (!kvm_is_mmio_pfn(pfn)) put_page(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); From 32cad84f44d186654492f1a50a1424c8906ccbd9 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Fri, 3 Aug 2012 15:42:52 +0800 Subject: [PATCH 0348/5375] KVM: do not release the error page After commit a2766325cf9f9, the error page is replaced by the error code, it need not be released anymore [ The patch has been compiling tested for powerpc ] Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- arch/powerpc/kvm/44x_tlb.c | 1 - arch/powerpc/kvm/book3s_pr.c | 4 +--- arch/x86/kvm/svm.c | 1 - arch/x86/kvm/vmx.c | 5 ++--- arch/x86/kvm/x86.c | 9 +++------ include/linux/kvm_host.h | 2 +- virt/kvm/async_pf.c | 4 ++-- virt/kvm/kvm_main.c | 5 +++-- 8 files changed, 12 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c index 33aa715dab28..5dd3ab469976 100644 --- a/arch/powerpc/kvm/44x_tlb.c +++ b/arch/powerpc/kvm/44x_tlb.c @@ -319,7 +319,6 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, if (is_error_page(new_page)) { printk(KERN_ERR "Couldn't get guest page for gfn %llx!\n", (unsigned long long)gfn); - kvm_release_page_clean(new_page); return; } hpaddr = page_to_phys(new_page); diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index a1baec340f7e..05c28f59f77f 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -242,10 +242,8 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) int i; hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT); - if (is_error_page(hpage)) { - kvm_release_page_clean(hpage); + if (is_error_page(hpage)) return; - } hpage_offset = pte->raddr & ~PAGE_MASK; hpage_offset &= ~0xFFFULL; diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 687d0c30e559..31be4a557447 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -2105,7 +2105,6 @@ static void *nested_svm_map(struct vcpu_svm *svm, u64 gpa, struct page **_page) return kmap(page); error: - kvm_release_page_clean(page); kvm_inject_gp(&svm->vcpu, 0); return NULL; diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index d6e4cbc42b8e..cc8ad9836927 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -596,10 +596,9 @@ static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu) static struct page *nested_get_page(struct kvm_vcpu *vcpu, gpa_t addr) { struct page *page = gfn_to_page(vcpu->kvm, addr >> PAGE_SHIFT); - if (is_error_page(page)) { - kvm_release_page_clean(page); + if (is_error_page(page)) return NULL; - } + return page; } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ebf2109318e0..7953a9e7cb17 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1639,10 +1639,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) vcpu->arch.time_page = gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT); - if (is_error_page(vcpu->arch.time_page)) { - kvm_release_page_clean(vcpu->arch.time_page); + if (is_error_page(vcpu->arch.time_page)) vcpu->arch.time_page = NULL; - } + break; } case MSR_KVM_ASYNC_PF_EN: @@ -3945,10 +3944,8 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt, goto emul_write; page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); - if (is_error_page(page)) { - kvm_release_page_clean(page); + if (is_error_page(page)) goto emul_write; - } kaddr = kmap_atomic(page); kaddr += offset_in_page(gpa); diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index ce7c32950f4e..07226f820e6c 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -457,7 +457,7 @@ pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn); pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault, bool *writable); pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn); -void kvm_release_pfn_dirty(pfn_t); +void kvm_release_pfn_dirty(pfn_t pfn); void kvm_release_pfn_clean(pfn_t pfn); void kvm_set_pfn_dirty(pfn_t pfn); void kvm_set_pfn_accessed(pfn_t pfn); diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 56f553391896..ea475cd03511 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -111,7 +111,7 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu) list_entry(vcpu->async_pf.done.next, typeof(*work), link); list_del(&work->link); - if (work->page) + if (!is_error_page(work->page)) kvm_release_page_clean(work->page); kmem_cache_free(async_pf_cache, work); } @@ -138,7 +138,7 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu) list_del(&work->queue); vcpu->async_pf.queued--; - if (work->page) + if (!is_error_page(work->page)) kvm_release_page_clean(work->page); kmem_cache_free(async_pf_cache, work); } diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index eafba99d1070..a2e85af847c1 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1186,8 +1186,9 @@ EXPORT_SYMBOL_GPL(gfn_to_page); void kvm_release_page_clean(struct page *page) { - if (!is_error_page(page)) - kvm_release_pfn_clean(page_to_pfn(page)); + WARN_ON(is_error_page(page)); + + kvm_release_pfn_clean(page_to_pfn(page)); } EXPORT_SYMBOL_GPL(kvm_release_page_clean); From 9c5b11728344e1085593f494ddc8838497e7ffde Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Fri, 3 Aug 2012 15:43:51 +0800 Subject: [PATCH 0349/5375] KVM: let the error pfn not depend on error code Currently, we use the error code as error pfn to indicat the error condition, it is not straightforward and it will not work on PAE 32-bit cpu with huge memory, since the valid physical address can be at most 52 bits For the normal pfn, the highest 12 bits should be zero, so we can mask these bits to indicate the error. Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- include/linux/kvm_host.h | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 07226f820e6c..d2b897ee3ac4 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -49,28 +49,34 @@ #define KVM_MAX_MMIO_FRAGMENTS \ (KVM_MMIO_SIZE / KVM_USER_MMIO_SIZE + KVM_EXTRA_MMIO_FRAGMENTS) -#define KVM_PFN_ERR_FAULT (-EFAULT) -#define KVM_PFN_ERR_HWPOISON (-EHWPOISON) -#define KVM_PFN_ERR_BAD (-ENOENT) +/* + * For the normal pfn, the highest 12 bits should be zero, + * so we can mask these bits to indicate the error. + */ +#define KVM_PFN_ERR_MASK (0xfffULL << 52) -static inline int is_error_pfn(pfn_t pfn) +#define KVM_PFN_ERR_FAULT (KVM_PFN_ERR_MASK) +#define KVM_PFN_ERR_HWPOISON (KVM_PFN_ERR_MASK + 1) +#define KVM_PFN_ERR_BAD (KVM_PFN_ERR_MASK + 2) + +static inline bool is_error_pfn(pfn_t pfn) { - return IS_ERR_VALUE(pfn); + return !!(pfn & KVM_PFN_ERR_MASK); } -static inline int is_noslot_pfn(pfn_t pfn) +static inline bool is_noslot_pfn(pfn_t pfn) { - return pfn == -ENOENT; + return pfn == KVM_PFN_ERR_BAD; } -static inline int is_invalid_pfn(pfn_t pfn) +static inline bool is_invalid_pfn(pfn_t pfn) { return !is_noslot_pfn(pfn) && is_error_pfn(pfn); } #define KVM_ERR_PTR_BAD_PAGE (ERR_PTR(-ENOENT)) -static inline int is_error_page(struct page *page) +static inline bool is_error_page(struct page *page) { return IS_ERR(page); } From 8a5a87d9b7aef24bcdba763d8ee14982477b0a2e Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 5 Aug 2012 15:58:26 +0300 Subject: [PATCH 0350/5375] KVM: clean up kvm_(set|get)_apic_base kvm_get_apic_base() needlessly checks irqchip_in_kernel although it does the same no matter what result of the check is. kvm_set_apic_base() also checks for irqchip_in_kernel, but kvm_lapic_set_base() can handle this case. Signed-off-by: Gleb Natapov Signed-off-by: Avi Kivity --- arch/x86/kvm/x86.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 7953a9e7cb17..3cafbb12ae05 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -246,20 +246,14 @@ static void drop_user_return_notifiers(void *ignore) u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) { - if (irqchip_in_kernel(vcpu->kvm)) - return vcpu->arch.apic_base; - else - return vcpu->arch.apic_base; + return vcpu->arch.apic_base; } EXPORT_SYMBOL_GPL(kvm_get_apic_base); void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) { /* TODO: reserve bits check */ - if (irqchip_in_kernel(vcpu->kvm)) - kvm_lapic_set_base(vcpu, data); - else - vcpu->arch.apic_base = data; + kvm_lapic_set_base(vcpu, data); } EXPORT_SYMBOL_GPL(kvm_set_apic_base); From 5dbc8f3fed0b4cb04dfb276150294f21c5f0fc66 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 5 Aug 2012 15:58:27 +0300 Subject: [PATCH 0351/5375] KVM: use kvm_lapic_set_base() to change apic_base Do not change apic_base directly. Use kvm_lapic_set_base() instead. Signed-off-by: Gleb Natapov Signed-off-by: Avi Kivity --- arch/x86/kvm/lapic.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 0cd431c85d38..49f4ac047f60 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1185,7 +1185,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) update_divide_count(apic); atomic_set(&apic->lapic_timer.pending, 0); if (kvm_vcpu_is_bsp(vcpu)) - vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP; + kvm_lapic_set_base(vcpu, + vcpu->arch.apic_base | MSR_IA32_APICBASE_BSP); vcpu->arch.pv_eoi.msr_val = 0; apic_update_ppr(apic); @@ -1310,8 +1311,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) HRTIMER_MODE_ABS); apic->lapic_timer.timer.function = apic_timer_fn; - apic->base_address = APIC_DEFAULT_PHYS_BASE; - vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE; + kvm_lapic_set_base(vcpu, APIC_DEFAULT_PHYS_BASE); kvm_lapic_reset(vcpu); kvm_iodevice_init(&apic->dev, &apic_mmio_ops); @@ -1380,8 +1380,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - apic->base_address = vcpu->arch.apic_base & - MSR_IA32_APICBASE_BASE; + kvm_lapic_set_base(vcpu, vcpu->arch.apic_base); kvm_apic_set_version(vcpu); apic_update_ppr(apic); From 6aed64a8a440360be875f31eabeacaddb83ef25f Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 5 Aug 2012 15:58:28 +0300 Subject: [PATCH 0352/5375] KVM: mark apic enabled on start up According to SDM apic is enabled on start up. Signed-off-by: Gleb Natapov Signed-off-by: Avi Kivity --- arch/x86/kvm/lapic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 49f4ac047f60..c3f14fe51e9b 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1311,7 +1311,8 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) HRTIMER_MODE_ABS); apic->lapic_timer.timer.function = apic_timer_fn; - kvm_lapic_set_base(vcpu, APIC_DEFAULT_PHYS_BASE); + kvm_lapic_set_base(vcpu, + APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE); kvm_lapic_reset(vcpu); kvm_iodevice_init(&apic->dev, &apic_mmio_ops); From 3b09efd1decb2b36ba2c7eb88ae4893f0581e470 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:34 +0530 Subject: [PATCH 0353/5375] ASoC: tlv320aic32x4: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index b0a73d37ed52..f230292ba96b 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -746,24 +746,7 @@ static struct i2c_driver aic32x4_i2c_driver = { .id_table = aic32x4_i2c_id, }; -static int __init aic32x4_modinit(void) -{ - int ret = 0; - - ret = i2c_add_driver(&aic32x4_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register aic32x4 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(aic32x4_modinit); - -static void __exit aic32x4_exit(void) -{ - i2c_del_driver(&aic32x4_i2c_driver); -} -module_exit(aic32x4_exit); +module_i2c_driver(aic32x4_i2c_driver); MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver"); MODULE_AUTHOR("Javier Martin "); From a3627e9c0a22283cb1f73fa1170f70fe604315d9 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:35 +0530 Subject: [PATCH 0354/5375] ASoC: max9877: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/max9877.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 3a2ba3d8fd6d..d15e5943c85e 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -291,17 +291,7 @@ static struct i2c_driver max9877_i2c_driver = { .id_table = max9877_i2c_id, }; -static int __init max9877_init(void) -{ - return i2c_add_driver(&max9877_i2c_driver); -} -module_init(max9877_init); - -static void __exit max9877_exit(void) -{ - i2c_del_driver(&max9877_i2c_driver); -} -module_exit(max9877_exit); +module_i2c_driver(max9877_i2c_driver); MODULE_DESCRIPTION("ASoC MAX9877 amp driver"); MODULE_AUTHOR("Joonyoung Shim "); From 96124c2910a5317b5ea9fbfd9e07b135fdc1dd28 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:39 +0530 Subject: [PATCH 0355/5375] ASoC: wm9090: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm9090.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 2c2346fdd637..c7ddc56175d1 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -695,17 +695,7 @@ static struct i2c_driver wm9090_i2c_driver = { .id_table = wm9090_id, }; -static int __init wm9090_init(void) -{ - return i2c_add_driver(&wm9090_i2c_driver); -} -module_init(wm9090_init); - -static void __exit wm9090_exit(void) -{ - i2c_del_driver(&wm9090_i2c_driver); -} -module_exit(wm9090_exit); +module_i2c_driver(wm9090_i2c_driver); MODULE_AUTHOR("Mark Brown "); MODULE_DESCRIPTION("WM9090 ASoC driver"); From 38ece8db99e1c7954608a6452bbe8b331d269ad6 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:40 +0530 Subject: [PATCH 0356/5375] ASoC: wm8991: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm8991.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 9ac31ba9b82e..b9dbfebbda13 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1400,23 +1400,7 @@ static struct i2c_driver wm8991_i2c_driver = { .id_table = wm8991_i2c_id, }; -static int __init wm8991_modinit(void) -{ - int ret; - ret = i2c_add_driver(&wm8991_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8991 I2C driver: %d\n", - ret); - } - return 0; -} -module_init(wm8991_modinit); - -static void __exit wm8991_exit(void) -{ - i2c_del_driver(&wm8991_i2c_driver); -} -module_exit(wm8991_exit); +module_i2c_driver(wm8991_i2c_driver); MODULE_DESCRIPTION("ASoC WM8991 driver"); MODULE_AUTHOR("Graeme Gregory"); From 5e383f53e80f4c644bc49a17b5590b110bad5832 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:41 +0530 Subject: [PATCH 0357/5375] ASoC: cs4270: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/cs4270.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index fd11bb646d40..44a176f74170 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -752,17 +752,7 @@ static struct i2c_driver cs4270_i2c_driver = { .remove = cs4270_i2c_remove, }; -static int __init cs4270_init(void) -{ - return i2c_add_driver(&cs4270_i2c_driver); -} -module_init(cs4270_init); - -static void __exit cs4270_exit(void) -{ - i2c_del_driver(&cs4270_i2c_driver); -} -module_exit(cs4270_exit); +module_i2c_driver(cs4270_i2c_driver); MODULE_AUTHOR("Timur Tabi "); MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); From fd39d14b9676cfd3dbd5b7bfdefe3ec6149b9e1a Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:42 +0530 Subject: [PATCH 0358/5375] ASoC: tlv320aic3x: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index dc78f5a4bcbf..01485bd51404 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1499,23 +1499,7 @@ static struct i2c_driver aic3x_i2c_driver = { .id_table = aic3x_i2c_id, }; -static int __init aic3x_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&aic3x_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n", - ret); - } - return ret; -} -module_init(aic3x_modinit); - -static void __exit aic3x_exit(void) -{ - i2c_del_driver(&aic3x_i2c_driver); -} -module_exit(aic3x_exit); +module_i2c_driver(aic3x_i2c_driver); MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); MODULE_AUTHOR("Vladimir Barinov"); From 0ead1136bda75d04cc134960bd265eebe210f74b Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:43 +0530 Subject: [PATCH 0359/5375] ASoC: sta32x: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/sta32x.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 8d717f4b5a87..51b7313a4c14 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -1006,17 +1006,7 @@ static struct i2c_driver sta32x_i2c_driver = { .id_table = sta32x_i2c_id, }; -static int __init sta32x_init(void) -{ - return i2c_add_driver(&sta32x_i2c_driver); -} -module_init(sta32x_init); - -static void __exit sta32x_exit(void) -{ - i2c_del_driver(&sta32x_i2c_driver); -} -module_exit(sta32x_exit); +module_i2c_driver(sta32x_i2c_driver); MODULE_DESCRIPTION("ASoC STA32X driver"); MODULE_AUTHOR("Johannes Stezenbach "); From 63a47a7544c65f0d4ca28f3ffa54468bc5f6cc6c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:44 +0530 Subject: [PATCH 0360/5375] ASoC: tlv320dac33: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 0dd41077ab79..d2e16c5d7d1f 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1621,24 +1621,7 @@ static struct i2c_driver tlv320dac33_i2c_driver = { .id_table = tlv320dac33_i2c_id, }; -static int __init dac33_module_init(void) -{ - int r; - r = i2c_add_driver(&tlv320dac33_i2c_driver); - if (r < 0) { - printk(KERN_ERR "DAC33: driver registration failed\n"); - return r; - } - return 0; -} -module_init(dac33_module_init); - -static void __exit dac33_module_exit(void) -{ - i2c_del_driver(&tlv320dac33_i2c_driver); -} -module_exit(dac33_module_exit); - +module_i2c_driver(tlv320dac33_i2c_driver); MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver"); MODULE_AUTHOR("Peter Ujfalusi "); From beb22de07e87a2f6802cc0e916b2f5c6aeb3f59f Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:45 +0530 Subject: [PATCH 0361/5375] ASoC: adau1701: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/adau1701.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 3d50fc8646b6..51f2f3cd8136 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -527,17 +527,7 @@ static struct i2c_driver adau1701_i2c_driver = { .id_table = adau1701_i2c_id, }; -static int __init adau1701_init(void) -{ - return i2c_add_driver(&adau1701_i2c_driver); -} -module_init(adau1701_init); - -static void __exit adau1701_exit(void) -{ - i2c_del_driver(&adau1701_i2c_driver); -} -module_exit(adau1701_exit); +module_i2c_driver(adau1701_i2c_driver); MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver"); MODULE_AUTHOR("Cliff Cai "); From 4abdc8c8fd25fa2f85d86babcbdb4fbbf759c86a Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:46 +0530 Subject: [PATCH 0362/5375] ASoC: max9850: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/max9850.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index a1913091f56c..efe535c37b39 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -369,17 +369,7 @@ static struct i2c_driver max9850_i2c_driver = { .id_table = max9850_i2c_id, }; -static int __init max9850_init(void) -{ - return i2c_add_driver(&max9850_i2c_driver); -} -module_init(max9850_init); - -static void __exit max9850_exit(void) -{ - i2c_del_driver(&max9850_i2c_driver); -} -module_exit(max9850_exit); +module_i2c_driver(max9850_i2c_driver); MODULE_AUTHOR("Christian Glindkamp "); MODULE_DESCRIPTION("ASoC MAX9850 codec driver"); From 28285b96c9e75a79b7698bc4286aa1cb94e5c9cb Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:47 +0530 Subject: [PATCH 0363/5375] ASoC: wm8971: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm8971.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index eef783f6b6d6..5ce647758443 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -721,23 +721,7 @@ static struct i2c_driver wm8971_i2c_driver = { .id_table = wm8971_i2c_id, }; -static int __init wm8971_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8971_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8971_modinit); - -static void __exit wm8971_exit(void) -{ - i2c_del_driver(&wm8971_i2c_driver); -} -module_exit(wm8971_exit); +module_i2c_driver(wm8971_i2c_driver); MODULE_DESCRIPTION("ASoC WM8971 driver"); MODULE_AUTHOR("Lab126"); From 0ecbbb4fe5f0aae4cd70ec02383fd6b96aedb052 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:48 +0530 Subject: [PATCH 0364/5375] ASoC: ak4671: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/ak4671.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 5fb7c2a80e6d..2b457976a7bf 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -696,17 +696,7 @@ static struct i2c_driver ak4671_i2c_driver = { .id_table = ak4671_i2c_id, }; -static int __init ak4671_modinit(void) -{ - return i2c_add_driver(&ak4671_i2c_driver); -} -module_init(ak4671_modinit); - -static void __exit ak4671_exit(void) -{ - i2c_del_driver(&ak4671_i2c_driver); -} -module_exit(ak4671_exit); +module_i2c_driver(ak4671_i2c_driver); MODULE_DESCRIPTION("ASoC AK4671 codec driver"); MODULE_AUTHOR("Joonyoung Shim "); From f6ec139f2dc5380c542fa3100dbe1c73324be432 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:49 +0530 Subject: [PATCH 0365/5375] ASoC: lm4857: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/lm4857.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index ba4fafb93e56..81a328c78838 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -250,17 +250,7 @@ static struct i2c_driver lm4857_i2c_driver = { .id_table = lm4857_i2c_id, }; -static int __init lm4857_init(void) -{ - return i2c_add_driver(&lm4857_i2c_driver); -} -module_init(lm4857_init); - -static void __exit lm4857_exit(void) -{ - i2c_del_driver(&lm4857_i2c_driver); -} -module_exit(lm4857_exit); +module_i2c_driver(lm4857_i2c_driver); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("LM4857 amplifier driver"); From 0b34ac810ac079735f9e7e2c58d467f849a67ede Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:50 +0530 Subject: [PATCH 0366/5375] ASoC: wm8978: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm8978.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index a5be3adecf75..5421fd9fbcb5 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1105,23 +1105,7 @@ static struct i2c_driver wm8978_i2c_driver = { .id_table = wm8978_i2c_id, }; -static int __init wm8978_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8978_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8978_modinit); - -static void __exit wm8978_exit(void) -{ - i2c_del_driver(&wm8978_i2c_driver); -} -module_exit(wm8978_exit); +module_i2c_driver(wm8978_i2c_driver); MODULE_DESCRIPTION("ASoC WM8978 codec driver"); MODULE_AUTHOR("Guennadi Liakhovetski "); From 2342a07f2ca81c8e076ed6d5c6d19ac36794c848 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:51 +0530 Subject: [PATCH 0367/5375] ASoC: max98088: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index af7324b79dd0..3264a5169306 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -2107,23 +2107,7 @@ static struct i2c_driver max98088_i2c_driver = { .id_table = max98088_i2c_id, }; -static int __init max98088_init(void) -{ - int ret; - - ret = i2c_add_driver(&max98088_i2c_driver); - if (ret) - pr_err("Failed to register max98088 I2C driver: %d\n", ret); - - return ret; -} -module_init(max98088_init); - -static void __exit max98088_exit(void) -{ - i2c_del_driver(&max98088_i2c_driver); -} -module_exit(max98088_exit); +module_i2c_driver(max98088_i2c_driver); MODULE_DESCRIPTION("ALSA SoC MAX98088 driver"); MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin"); From 07c9c32be01db1705db2655922ee66173594b230 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:52 +0530 Subject: [PATCH 0368/5375] ASoC: wm8955: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm8955.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 61fe97433e73..2f1c075755b1 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -1071,23 +1071,7 @@ static struct i2c_driver wm8955_i2c_driver = { .id_table = wm8955_i2c_id, }; -static int __init wm8955_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8955_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8955_modinit); - -static void __exit wm8955_exit(void) -{ - i2c_del_driver(&wm8955_i2c_driver); -} -module_exit(wm8955_exit); +module_i2c_driver(wm8955_i2c_driver); MODULE_DESCRIPTION("ASoC WM8955 driver"); MODULE_AUTHOR("Mark Brown "); From a9418ddca69db1c4b5d2d7b5f091e50893387be3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:53 +0530 Subject: [PATCH 0369/5375] ASoC: wm2200: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 32682c1b7cde..71debd0a3822 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2270,17 +2270,7 @@ static struct i2c_driver wm2200_i2c_driver = { .id_table = wm2200_i2c_id, }; -static int __init wm2200_modinit(void) -{ - return i2c_add_driver(&wm2200_i2c_driver); -} -module_init(wm2200_modinit); - -static void __exit wm2200_exit(void) -{ - i2c_del_driver(&wm2200_i2c_driver); -} -module_exit(wm2200_exit); +module_i2c_driver(wm2200_i2c_driver); MODULE_DESCRIPTION("ASoC WM2200 driver"); MODULE_AUTHOR("Mark Brown "); From 3a4bfd88af87b065e8a650211a7730b3f1e58e3e Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:54 +0530 Subject: [PATCH 0370/5375] ASoC: wm2000: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm2000.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 3fd5b29dc933..89cd6fcad015 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -858,17 +858,7 @@ static struct i2c_driver wm2000_i2c_driver = { .id_table = wm2000_i2c_id, }; -static int __init wm2000_init(void) -{ - return i2c_add_driver(&wm2000_i2c_driver); -} -module_init(wm2000_init); - -static void __exit wm2000_exit(void) -{ - i2c_del_driver(&wm2000_i2c_driver); -} -module_exit(wm2000_exit); +module_i2c_driver(wm2000_i2c_driver); MODULE_DESCRIPTION("ASoC WM2000 driver"); MODULE_AUTHOR("Mark Brown "); From 794836b959e95b4e4705e11e7bdf2a688c72e2f7 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:55 +0530 Subject: [PATCH 0371/5375] ASoC: wm8940: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm8940.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 481a3d9cfe48..b20aa4e7c3f9 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -785,23 +785,7 @@ static struct i2c_driver wm8940_i2c_driver = { .id_table = wm8940_i2c_id, }; -static int __init wm8940_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8940_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8940_modinit); - -static void __exit wm8940_exit(void) -{ - i2c_del_driver(&wm8940_i2c_driver); -} -module_exit(wm8940_exit); +module_i2c_driver(wm8940_i2c_driver); MODULE_DESCRIPTION("ASoC WM8940 driver"); MODULE_AUTHOR("Jonathan Cameron"); From 8b08eb28c761aea8434e0228a0f080e31e16d791 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:56 +0530 Subject: [PATCH 0372/5375] ASoC: wm8961: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm8961.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 01edbcc754d2..719fb69a17c8 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -1114,23 +1114,7 @@ static struct i2c_driver wm8961_i2c_driver = { .id_table = wm8961_i2c_id, }; -static int __init wm8961_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8961_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8961 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8961_modinit); - -static void __exit wm8961_exit(void) -{ - i2c_del_driver(&wm8961_i2c_driver); -} -module_exit(wm8961_exit); +module_i2c_driver(wm8961_i2c_driver); MODULE_DESCRIPTION("ASoC WM8961 driver"); MODULE_AUTHOR("Mark Brown "); From 5c86ea44bba82641b6173419c88c0de7cf09b60a Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:57 +0530 Subject: [PATCH 0373/5375] ASoC: wm8903: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 73f1c8d7bafb..839414f9e2ed 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -2241,23 +2241,7 @@ static struct i2c_driver wm8903_i2c_driver = { .id_table = wm8903_i2c_id, }; -static int __init wm8903_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8903_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8903_modinit); - -static void __exit wm8903_exit(void) -{ - i2c_del_driver(&wm8903_i2c_driver); -} -module_exit(wm8903_exit); +module_i2c_driver(wm8903_i2c_driver); MODULE_DESCRIPTION("ASoC WM8903 driver"); MODULE_AUTHOR("Mark Brown "); From d0b2d4fabb262dd7200382ee834d4292f6d76b1e Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:58 +0530 Subject: [PATCH 0374/5375] ASoC: adau1373: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/adau1373.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 44f59064d8de..704544bfc90d 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1392,17 +1392,7 @@ static struct i2c_driver adau1373_i2c_driver = { .id_table = adau1373_i2c_id, }; -static int __init adau1373_init(void) -{ - return i2c_add_driver(&adau1373_i2c_driver); -} -module_init(adau1373_init); - -static void __exit adau1373_exit(void) -{ - i2c_del_driver(&adau1373_i2c_driver); -} -module_exit(adau1373_exit); +module_i2c_driver(adau1373_i2c_driver); MODULE_DESCRIPTION("ASoC ADAU1373 driver"); MODULE_AUTHOR("Lars-Peter Clausen "); From 3c010e60ee54ee19dc2f39b4efa43dea03d65aaa Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:36 +0530 Subject: [PATCH 0375/5375] ASoC: wm8960: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 96518ac8e24c..804f4116912f 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1010,23 +1010,7 @@ static struct i2c_driver wm8960_i2c_driver = { .id_table = wm8960_i2c_id, }; -static int __init wm8960_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8960_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8960_modinit); - -static void __exit wm8960_exit(void) -{ - i2c_del_driver(&wm8960_i2c_driver); -} -module_exit(wm8960_exit); +module_i2c_driver(wm8960_i2c_driver); MODULE_DESCRIPTION("ASoC WM8960 driver"); MODULE_AUTHOR("Liam Girdwood"); From 2be59418f76dac590b98027586ac1714be17fcae Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:59 +0530 Subject: [PATCH 0376/5375] ASoC: wm8974: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/wm8974.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index d93c03f820c9..9a39511af52a 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -659,23 +659,7 @@ static struct i2c_driver wm8974_i2c_driver = { .id_table = wm8974_i2c_id, }; -static int __init wm8974_modinit(void) -{ - int ret = 0; - ret = i2c_add_driver(&wm8974_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n", - ret); - } - return ret; -} -module_init(wm8974_modinit); - -static void __exit wm8974_exit(void) -{ - i2c_del_driver(&wm8974_i2c_driver); -} -module_exit(wm8974_exit); +module_i2c_driver(wm8974_i2c_driver); MODULE_DESCRIPTION("ASoC WM8974 driver"); MODULE_AUTHOR("Liam Girdwood"); From a8af02cf62e32644c02566adc462bba9ae148154 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:26:00 +0530 Subject: [PATCH 0377/5375] ASoC: max98095: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/max98095.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 7cd508e16a5c..38d43c59d3f4 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2533,23 +2533,7 @@ static struct i2c_driver max98095_i2c_driver = { .id_table = max98095_i2c_id, }; -static int __init max98095_init(void) -{ - int ret; - - ret = i2c_add_driver(&max98095_i2c_driver); - if (ret) - pr_err("Failed to register max98095 I2C driver: %d\n", ret); - - return ret; -} -module_init(max98095_init); - -static void __exit max98095_exit(void) -{ - i2c_del_driver(&max98095_i2c_driver); -} -module_exit(max98095_exit); +module_i2c_driver(max98095_i2c_driver); MODULE_DESCRIPTION("ALSA SoC MAX98095 driver"); MODULE_AUTHOR("Peter Hsiang"); From cee4fcfa9dba7f13b0b45810832208df48ff4ca4 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:37 +0530 Subject: [PATCH 0378/5375] ASoC: cs42l51: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l51.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 091d0193f507..1e0fa3b5f79a 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -614,24 +614,7 @@ static struct i2c_driver cs42l51_i2c_driver = { .remove = cs42l51_i2c_remove, }; -static int __init cs42l51_init(void) -{ - int ret; - - ret = i2c_add_driver(&cs42l51_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "%s: can't add i2c driver\n", __func__); - return ret; - } - return 0; -} -module_init(cs42l51_init); - -static void __exit cs42l51_exit(void) -{ - i2c_del_driver(&cs42l51_i2c_driver); -} -module_exit(cs42l51_exit); +module_i2c_driver(cs42l51_i2c_driver); MODULE_AUTHOR("Arnaud Patard "); MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver"); From f062e2b64153e9769adf5370103f787971c9cd95 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Aug 2012 17:25:38 +0530 Subject: [PATCH 0379/5375] ASoC: tpa6130a2: Use module_i2c_driver module_i2c_driver makes the code simpler by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/tpa6130a2.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 6fe4aa3ac544..565ff39ad3a3 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -487,19 +487,8 @@ static struct i2c_driver tpa6130a2_i2c_driver = { .id_table = tpa6130a2_id, }; -static int __init tpa6130a2_init(void) -{ - return i2c_add_driver(&tpa6130a2_i2c_driver); -} - -static void __exit tpa6130a2_exit(void) -{ - i2c_del_driver(&tpa6130a2_i2c_driver); -} +module_i2c_driver(tpa6130a2_i2c_driver); MODULE_AUTHOR("Peter Ujfalusi "); MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver"); MODULE_LICENSE("GPL"); - -module_init(tpa6130a2_init); -module_exit(tpa6130a2_exit); From a181dc14ed23f7a499542ff4c78532b5f24bb18f Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 5 Aug 2012 15:58:29 +0300 Subject: [PATCH 0380/5375] jump_label: Export jump_label_rate_limit() CC: Jason Baron CC: Ingo Molnar CC: Peter Zijlstra Signed-off-by: Gleb Natapov Acked-by: Jason Baron Signed-off-by: Avi Kivity --- kernel/jump_label.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 43049192b5ec..60f48fa0fd0d 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -118,6 +118,7 @@ void jump_label_rate_limit(struct static_key_deferred *key, key->timeout = rl; INIT_DELAYED_WORK(&key->work, jump_label_update_timeout); } +EXPORT_SYMBOL_GPL(jump_label_rate_limit); static int addr_conflict(struct jump_entry *entry, void *start, void *end) { From c5cc421ba3219b90f11d151bc55f1608c12830fa Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 5 Aug 2012 15:58:30 +0300 Subject: [PATCH 0381/5375] KVM: use jump label to optimize checking for HW enabled APIC in APIC_BASE MSR Usually all APICs are HW enabled so the check can be optimized out. Signed-off-by: Gleb Natapov Signed-off-by: Avi Kivity --- arch/x86/kvm/lapic.c | 29 ++++++++++++++++++++++++++++- arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/x86.c | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index c3f14fe51e9b..5b46cab044a5 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "kvm_cache_regs.h" #include "irq.h" #include "trace.h" @@ -117,9 +118,13 @@ static inline int __apic_test_and_clear_vector(int vec, void *bitmap) return __test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); } +struct static_key_deferred apic_hw_disabled __read_mostly; + static inline int apic_hw_enabled(struct kvm_lapic *apic) { - return (apic)->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE; + if (static_key_false(&apic_hw_disabled.key)) + return apic->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE; + return MSR_IA32_APICBASE_ENABLE; } static inline int apic_sw_enabled(struct kvm_lapic *apic) @@ -1055,6 +1060,9 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu) hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer); + if (!(vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE)) + static_key_slow_dec_deferred(&apic_hw_disabled); + if (vcpu->arch.apic->regs) free_page((unsigned long)vcpu->arch.apic->regs); @@ -1125,6 +1133,14 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) return; } + /* update jump label if enable bit changes */ + if ((vcpu->arch.apic_base ^ value) & MSR_IA32_APICBASE_ENABLE) { + if (value & MSR_IA32_APICBASE_ENABLE) + static_key_slow_dec_deferred(&apic_hw_disabled); + else + static_key_slow_inc(&apic_hw_disabled.key); + } + if (!kvm_vcpu_is_bsp(apic->vcpu)) value &= ~MSR_IA32_APICBASE_BSP; @@ -1311,6 +1327,11 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) HRTIMER_MODE_ABS); apic->lapic_timer.timer.function = apic_timer_fn; + /* + * APIC is created enabled. This will prevent kvm_lapic_set_base from + * thinking that APIC satet has changed. + */ + vcpu->arch.apic_base = MSR_IA32_APICBASE_ENABLE; kvm_lapic_set_base(vcpu, APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE); @@ -1598,3 +1619,9 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data) return kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.pv_eoi.data, addr); } + +void kvm_lapic_init(void) +{ + /* do not patch jump label more than once per second */ + jump_label_rate_limit(&apic_hw_disabled, HZ); +} diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 166766fffd9f..73fa299b68e8 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -78,4 +78,5 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu) } int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data); +void kvm_lapic_init(void); #endif diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3cafbb12ae05..29fa18d27e6e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4903,6 +4903,7 @@ int kvm_arch_init(void *opaque) if (cpu_has_xsave) host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); + kvm_lapic_init(); return 0; out: From f8c1ea103947038b7197bdd4c8451886a58af0c0 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 5 Aug 2012 15:58:31 +0300 Subject: [PATCH 0382/5375] KVM: use jump label to optimize checking for SW enabled apic in spurious interrupt register Usually all APICs are SW enabled so the check can be optimized out. Signed-off-by: Gleb Natapov Signed-off-by: Avi Kivity --- arch/x86/kvm/lapic.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 5b46cab044a5..7f77e96ac5e8 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -127,9 +127,24 @@ static inline int apic_hw_enabled(struct kvm_lapic *apic) return MSR_IA32_APICBASE_ENABLE; } -static inline int apic_sw_enabled(struct kvm_lapic *apic) +struct static_key_deferred apic_sw_disabled __read_mostly; + +static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) { - return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; + if ((apic_get_reg(apic, APIC_SPIV) ^ val) & APIC_SPIV_APIC_ENABLED) { + if (val & APIC_SPIV_APIC_ENABLED) + static_key_slow_dec_deferred(&apic_sw_disabled); + else + static_key_slow_inc(&apic_sw_disabled.key); + } + apic_set_reg(apic, APIC_SPIV, val); +} + +static inline int apic_sw_enabled(struct kvm_lapic *apic) +{ + if (static_key_false(&apic_sw_disabled.key)) + return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; + return APIC_SPIV_APIC_ENABLED; } static inline int apic_enabled(struct kvm_lapic *apic) @@ -918,7 +933,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) u32 mask = 0x3ff; if (apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI) mask |= APIC_SPIV_DIRECTED_EOI; - apic_set_reg(apic, APIC_SPIV, val & mask); + apic_set_spiv(apic, val & mask); if (!(val & APIC_SPIV_APIC_ENABLED)) { int i; u32 lvt_val; @@ -1055,18 +1070,23 @@ EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); void kvm_free_lapic(struct kvm_vcpu *vcpu) { + struct kvm_lapic *apic = vcpu->arch.apic; + if (!vcpu->arch.apic) return; - hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer); + hrtimer_cancel(&apic->lapic_timer.timer); if (!(vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE)) static_key_slow_dec_deferred(&apic_hw_disabled); - if (vcpu->arch.apic->regs) - free_page((unsigned long)vcpu->arch.apic->regs); + if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED)) + static_key_slow_dec_deferred(&apic_sw_disabled); - kfree(vcpu->arch.apic); + if (apic->regs) + free_page((unsigned long)apic->regs); + + kfree(apic); } /* @@ -1182,7 +1202,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); apic_set_reg(apic, APIC_DFR, 0xffffffffU); - apic_set_reg(apic, APIC_SPIV, 0xff); + apic_set_spiv(apic, 0xff); apic_set_reg(apic, APIC_TASKPRI, 0); apic_set_reg(apic, APIC_LDR, 0); apic_set_reg(apic, APIC_ESR, 0); @@ -1335,6 +1355,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) kvm_lapic_set_base(vcpu, APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE); + static_key_slow_inc(&apic_sw_disabled.key); /* sw disabled at reset */ kvm_lapic_reset(vcpu); kvm_iodevice_init(&apic->dev, &apic_mmio_ops); @@ -1404,6 +1425,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) kvm_lapic_set_base(vcpu, vcpu->arch.apic_base); kvm_apic_set_version(vcpu); + apic_set_spiv(apic, apic_get_reg(apic, APIC_SPIV)); apic_update_ppr(apic); hrtimer_cancel(&apic->lapic_timer.timer); @@ -1624,4 +1646,5 @@ void kvm_lapic_init(void) { /* do not patch jump label more than once per second */ jump_label_rate_limit(&apic_hw_disabled, HZ); + jump_label_rate_limit(&apic_sw_disabled, HZ); } From 54e9818f3903902a4ea3046035739b8770880092 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 5 Aug 2012 15:58:32 +0300 Subject: [PATCH 0383/5375] KVM: use jump label to optimize checking for in kernel local apic presence Usually all vcpus have local apic pointer initialized, so the check may be completely skipped. Signed-off-by: Gleb Natapov Signed-off-by: Avi Kivity --- arch/x86/kvm/lapic.c | 62 ++++++++++++++++++++++++-------------------- arch/x86/kvm/x86.c | 7 ++++- arch/x86/kvm/x86.h | 1 + 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 7f77e96ac5e8..650379ba73af 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -152,6 +152,13 @@ static inline int apic_enabled(struct kvm_lapic *apic) return apic_sw_enabled(apic) && apic_hw_enabled(apic); } +static inline bool vcpu_has_lapic(struct kvm_vcpu *vcpu) +{ + if (static_key_false(&kvm_no_apic_vcpu)) + return vcpu->arch.apic; + return true; +} + #define LVT_MASK \ (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK) @@ -204,7 +211,7 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu) struct kvm_cpuid_entry2 *feat; u32 v = APIC_VERSION; - if (!irqchip_in_kernel(vcpu->kvm)) + if (!vcpu_has_lapic(vcpu)) return; feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0); @@ -305,7 +312,6 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic) int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) { - struct kvm_lapic *apic = vcpu->arch.apic; int highest_irr; /* This may race with setting of irr in __apic_accept_irq() and @@ -313,9 +319,9 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) * will cause vmexit immediately and the value will be recalculated * on the next vmentry. */ - if (!apic) + if (!vcpu_has_lapic(vcpu)) return 0; - highest_irr = apic_find_highest_irr(apic); + highest_irr = apic_find_highest_irr(vcpu->arch.apic); return highest_irr; } @@ -1061,9 +1067,7 @@ static int apic_mmio_write(struct kvm_io_device *this, void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu) { - struct kvm_lapic *apic = vcpu->arch.apic; - - if (apic) + if (vcpu_has_lapic(vcpu)) apic_reg_write(vcpu->arch.apic, APIC_EOI, 0); } EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); @@ -1098,10 +1102,9 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu) u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!apic) - return 0; - if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic)) + if (!vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) || + apic_lvtt_period(apic)) return 0; return apic->lapic_timer.tscdeadline; @@ -1110,10 +1113,9 @@ u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu) void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!apic) - return; - if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic)) + if (!vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) || + apic_lvtt_period(apic)) return; hrtimer_cancel(&apic->lapic_timer.timer); @@ -1125,20 +1127,21 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!apic) + if (!vcpu_has_lapic(vcpu)) return; + apic_set_tpr(apic, ((cr8 & 0x0f) << 4) | (apic_get_reg(apic, APIC_TASKPRI) & 4)); } u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) { - struct kvm_lapic *apic = vcpu->arch.apic; u64 tpr; - if (!apic) + if (!vcpu_has_lapic(vcpu)) return 0; - tpr = (u64) apic_get_reg(apic, APIC_TASKPRI); + + tpr = (u64) apic_get_reg(vcpu->arch.apic, APIC_TASKPRI); return (tpr & 0xf0) >> 4; } @@ -1237,7 +1240,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) bool kvm_apic_present(struct kvm_vcpu *vcpu) { - return vcpu->arch.apic && apic_hw_enabled(vcpu->arch.apic); + return vcpu_has_lapic(vcpu) && apic_hw_enabled(vcpu->arch.apic); } int kvm_lapic_enabled(struct kvm_vcpu *vcpu) @@ -1258,10 +1261,11 @@ static bool lapic_is_periodic(struct kvm_lapic *apic) int apic_has_pending_timer(struct kvm_vcpu *vcpu) { - struct kvm_lapic *lapic = vcpu->arch.apic; + struct kvm_lapic *apic = vcpu->arch.apic; - if (lapic && apic_enabled(lapic) && apic_lvt_enabled(lapic, APIC_LVTT)) - return atomic_read(&lapic->lapic_timer.pending); + if (vcpu_has_lapic(vcpu) && apic_enabled(apic) && + apic_lvt_enabled(apic, APIC_LVTT)) + return atomic_read(&apic->lapic_timer.pending); return 0; } @@ -1371,7 +1375,7 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) struct kvm_lapic *apic = vcpu->arch.apic; int highest_irr; - if (!apic || !apic_enabled(apic)) + if (!vcpu_has_lapic(vcpu) || !apic_enabled(apic)) return -1; apic_update_ppr(apic); @@ -1399,7 +1403,10 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - if (apic && atomic_read(&apic->lapic_timer.pending) > 0) { + if (!vcpu_has_lapic(vcpu)) + return; + + if (atomic_read(&apic->lapic_timer.pending) > 0) { if (kvm_apic_local_deliver(apic, APIC_LVTT)) atomic_dec(&apic->lapic_timer.pending); } @@ -1439,13 +1446,12 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) { - struct kvm_lapic *apic = vcpu->arch.apic; struct hrtimer *timer; - if (!apic) + if (!vcpu_has_lapic(vcpu)) return; - timer = &apic->lapic_timer.timer; + timer = &vcpu->arch.apic->lapic_timer.timer; if (hrtimer_cancel(timer)) hrtimer_start_expires(timer, HRTIMER_MODE_ABS); } @@ -1602,7 +1608,7 @@ int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 reg, u64 data) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!irqchip_in_kernel(vcpu->kvm)) + if (!vcpu_has_lapic(vcpu)) return 1; /* if this is ICR write vector before command */ @@ -1616,7 +1622,7 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data) struct kvm_lapic *apic = vcpu->arch.apic; u32 low, high = 0; - if (!irqchip_in_kernel(vcpu->kvm)) + if (!vcpu_has_lapic(vcpu)) return 1; if (apic_reg_read(apic, reg, 4, &low)) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 29fa18d27e6e..8ebf65c349eb 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6152,6 +6152,8 @@ bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL); } +struct static_key kvm_no_apic_vcpu __read_mostly; + int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) { struct page *page; @@ -6184,7 +6186,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) r = kvm_create_lapic(vcpu); if (r < 0) goto fail_mmu_destroy; - } + } else + static_key_slow_inc(&kvm_no_apic_vcpu); vcpu->arch.mce_banks = kzalloc(KVM_MAX_MCE_BANKS * sizeof(u64) * 4, GFP_KERNEL); @@ -6224,6 +6227,8 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) kvm_mmu_destroy(vcpu); srcu_read_unlock(&vcpu->kvm->srcu, idx); free_page((unsigned long)vcpu->arch.pio_data); + if (!irqchip_in_kernel(vcpu->kvm)) + static_key_slow_dec(&kvm_no_apic_vcpu); } int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 3d1134ddb885..2b5219c12ac8 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -124,4 +124,5 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, extern u64 host_xcr0; +extern struct static_key kvm_no_apic_vcpu; #endif From c48f14966cc41957d88c66dfe49a439e708ab7b8 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Sun, 5 Aug 2012 15:58:33 +0300 Subject: [PATCH 0384/5375] KVM: inline kvm_apic_present() and kvm_lapic_enabled() Those functions are used during interrupt injection. When inlined they become nops on the fast path. Signed-off-by: Gleb Natapov Signed-off-by: Avi Kivity --- arch/x86/kvm/lapic.c | 143 ++++++++++++++++--------------------------- arch/x86/kvm/lapic.h | 45 +++++++++++++- 2 files changed, 96 insertions(+), 92 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 650379ba73af..333c27fa6e9f 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -73,11 +73,6 @@ static unsigned int min_timer_period_us = 500; module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR); -static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off) -{ - return *((u32 *) (apic->regs + reg_off)); -} - static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val) { *((u32 *) (apic->regs + reg_off)) = val; @@ -119,19 +114,11 @@ static inline int __apic_test_and_clear_vector(int vec, void *bitmap) } struct static_key_deferred apic_hw_disabled __read_mostly; - -static inline int apic_hw_enabled(struct kvm_lapic *apic) -{ - if (static_key_false(&apic_hw_disabled.key)) - return apic->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE; - return MSR_IA32_APICBASE_ENABLE; -} - struct static_key_deferred apic_sw_disabled __read_mostly; static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) { - if ((apic_get_reg(apic, APIC_SPIV) ^ val) & APIC_SPIV_APIC_ENABLED) { + if ((kvm_apic_get_reg(apic, APIC_SPIV) ^ val) & APIC_SPIV_APIC_ENABLED) { if (val & APIC_SPIV_APIC_ENABLED) static_key_slow_dec_deferred(&apic_sw_disabled); else @@ -140,23 +127,9 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) apic_set_reg(apic, APIC_SPIV, val); } -static inline int apic_sw_enabled(struct kvm_lapic *apic) -{ - if (static_key_false(&apic_sw_disabled.key)) - return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; - return APIC_SPIV_APIC_ENABLED; -} - static inline int apic_enabled(struct kvm_lapic *apic) { - return apic_sw_enabled(apic) && apic_hw_enabled(apic); -} - -static inline bool vcpu_has_lapic(struct kvm_vcpu *vcpu) -{ - if (static_key_false(&kvm_no_apic_vcpu)) - return vcpu->arch.apic; - return true; + return kvm_apic_sw_enabled(apic) && kvm_apic_hw_enabled(apic); } #define LVT_MASK \ @@ -168,34 +141,34 @@ static inline bool vcpu_has_lapic(struct kvm_vcpu *vcpu) static inline int kvm_apic_id(struct kvm_lapic *apic) { - return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff; + return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; } static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type) { - return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); + return !(kvm_apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); } static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type) { - return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; + return kvm_apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; } static inline int apic_lvtt_oneshot(struct kvm_lapic *apic) { - return ((apic_get_reg(apic, APIC_LVTT) & + return ((kvm_apic_get_reg(apic, APIC_LVTT) & apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_ONESHOT); } static inline int apic_lvtt_period(struct kvm_lapic *apic) { - return ((apic_get_reg(apic, APIC_LVTT) & + return ((kvm_apic_get_reg(apic, APIC_LVTT) & apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_PERIODIC); } static inline int apic_lvtt_tscdeadline(struct kvm_lapic *apic) { - return ((apic_get_reg(apic, APIC_LVTT) & + return ((kvm_apic_get_reg(apic, APIC_LVTT) & apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_TSCDEADLINE); } @@ -211,7 +184,7 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu) struct kvm_cpuid_entry2 *feat; u32 v = APIC_VERSION; - if (!vcpu_has_lapic(vcpu)) + if (!kvm_vcpu_has_lapic(vcpu)) return; feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0); @@ -319,7 +292,7 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) * will cause vmexit immediately and the value will be recalculated * on the next vmentry. */ - if (!vcpu_has_lapic(vcpu)) + if (!kvm_vcpu_has_lapic(vcpu)) return 0; highest_irr = apic_find_highest_irr(vcpu->arch.apic); @@ -404,8 +377,8 @@ static void apic_update_ppr(struct kvm_lapic *apic) u32 tpr, isrv, ppr, old_ppr; int isr; - old_ppr = apic_get_reg(apic, APIC_PROCPRI); - tpr = apic_get_reg(apic, APIC_TASKPRI); + old_ppr = kvm_apic_get_reg(apic, APIC_PROCPRI); + tpr = kvm_apic_get_reg(apic, APIC_TASKPRI); isr = apic_find_highest_isr(apic); isrv = (isr != -1) ? isr : 0; @@ -441,13 +414,13 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) u32 logical_id; if (apic_x2apic_mode(apic)) { - logical_id = apic_get_reg(apic, APIC_LDR); + logical_id = kvm_apic_get_reg(apic, APIC_LDR); return logical_id & mda; } - logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR)); + logical_id = GET_APIC_LOGICAL_ID(kvm_apic_get_reg(apic, APIC_LDR)); - switch (apic_get_reg(apic, APIC_DFR)) { + switch (kvm_apic_get_reg(apic, APIC_DFR)) { case APIC_DFR_FLAT: if (logical_id & mda) result = 1; @@ -459,7 +432,7 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) break; default: apic_debug("Bad DFR vcpu %d: %08x\n", - apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR)); + apic->vcpu->vcpu_id, kvm_apic_get_reg(apic, APIC_DFR)); break; } @@ -617,7 +590,7 @@ static int apic_set_eoi(struct kvm_lapic *apic) apic_clear_isr(vector, apic); apic_update_ppr(apic); - if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) && + if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) && kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) { int trigger_mode; if (apic_test_vector(vector, apic->regs + APIC_TMR)) @@ -632,8 +605,8 @@ static int apic_set_eoi(struct kvm_lapic *apic) static void apic_send_ipi(struct kvm_lapic *apic) { - u32 icr_low = apic_get_reg(apic, APIC_ICR); - u32 icr_high = apic_get_reg(apic, APIC_ICR2); + u32 icr_low = kvm_apic_get_reg(apic, APIC_ICR); + u32 icr_high = kvm_apic_get_reg(apic, APIC_ICR2); struct kvm_lapic_irq irq; irq.vector = icr_low & APIC_VECTOR_MASK; @@ -668,7 +641,7 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic) ASSERT(apic != NULL); /* if initial count is 0, current count should also be 0 */ - if (apic_get_reg(apic, APIC_TMICT) == 0) + if (kvm_apic_get_reg(apic, APIC_TMICT) == 0) return 0; remaining = hrtimer_get_remaining(&apic->lapic_timer.timer); @@ -724,13 +697,13 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset) break; case APIC_PROCPRI: apic_update_ppr(apic); - val = apic_get_reg(apic, offset); + val = kvm_apic_get_reg(apic, offset); break; case APIC_TASKPRI: report_tpr_access(apic, false); /* fall thru */ default: - val = apic_get_reg(apic, offset); + val = kvm_apic_get_reg(apic, offset); break; } @@ -782,7 +755,7 @@ static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len, static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr) { - return apic_hw_enabled(apic) && + return kvm_apic_hw_enabled(apic) && addr >= apic->base_address && addr < apic->base_address + LAPIC_MMIO_LENGTH; } @@ -805,7 +778,7 @@ static void update_divide_count(struct kvm_lapic *apic) { u32 tmp1, tmp2, tdcr; - tdcr = apic_get_reg(apic, APIC_TDCR); + tdcr = kvm_apic_get_reg(apic, APIC_TDCR); tmp1 = tdcr & 0xf; tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; apic->divide_count = 0x1 << (tmp2 & 0x7); @@ -822,7 +795,7 @@ static void start_apic_timer(struct kvm_lapic *apic) if (apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) { /* lapic timer in oneshot or periodic mode */ now = apic->lapic_timer.timer.base->get_time(); - apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT) + apic->lapic_timer.period = (u64)kvm_apic_get_reg(apic, APIC_TMICT) * APIC_BUS_CYCLE_NS * apic->divide_count; if (!apic->lapic_timer.period) @@ -854,7 +827,7 @@ static void start_apic_timer(struct kvm_lapic *apic) "timer initial count 0x%x, period %lldns, " "expire @ 0x%016" PRIx64 ".\n", __func__, APIC_BUS_CYCLE_NS, ktime_to_ns(now), - apic_get_reg(apic, APIC_TMICT), + kvm_apic_get_reg(apic, APIC_TMICT), apic->lapic_timer.period, ktime_to_ns(ktime_add_ns(now, apic->lapic_timer.period))); @@ -886,7 +859,7 @@ static void start_apic_timer(struct kvm_lapic *apic) static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val) { - int nmi_wd_enabled = apic_lvt_nmi_mode(apic_get_reg(apic, APIC_LVT0)); + int nmi_wd_enabled = apic_lvt_nmi_mode(kvm_apic_get_reg(apic, APIC_LVT0)); if (apic_lvt_nmi_mode(lvt0_val)) { if (!nmi_wd_enabled) { @@ -937,7 +910,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) case APIC_SPIV: { u32 mask = 0x3ff; - if (apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI) + if (kvm_apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI) mask |= APIC_SPIV_DIRECTED_EOI; apic_set_spiv(apic, val & mask); if (!(val & APIC_SPIV_APIC_ENABLED)) { @@ -945,7 +918,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) u32 lvt_val; for (i = 0; i < APIC_LVT_NUM; i++) { - lvt_val = apic_get_reg(apic, + lvt_val = kvm_apic_get_reg(apic, APIC_LVTT + 0x10 * i); apic_set_reg(apic, APIC_LVTT + 0x10 * i, lvt_val | APIC_LVT_MASKED); @@ -974,7 +947,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) case APIC_LVT1: case APIC_LVTERR: /* TODO: Check vector */ - if (!apic_sw_enabled(apic)) + if (!kvm_apic_sw_enabled(apic)) val |= APIC_LVT_MASKED; val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4]; @@ -983,12 +956,12 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) break; case APIC_LVTT: - if ((apic_get_reg(apic, APIC_LVTT) & + if ((kvm_apic_get_reg(apic, APIC_LVTT) & apic->lapic_timer.timer_mode_mask) != (val & apic->lapic_timer.timer_mode_mask)) hrtimer_cancel(&apic->lapic_timer.timer); - if (!apic_sw_enabled(apic)) + if (!kvm_apic_sw_enabled(apic)) val |= APIC_LVT_MASKED; val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask); apic_set_reg(apic, APIC_LVTT, val); @@ -1067,7 +1040,7 @@ static int apic_mmio_write(struct kvm_io_device *this, void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu) { - if (vcpu_has_lapic(vcpu)) + if (kvm_vcpu_has_lapic(vcpu)) apic_reg_write(vcpu->arch.apic, APIC_EOI, 0); } EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); @@ -1084,7 +1057,7 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu) if (!(vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE)) static_key_slow_dec_deferred(&apic_hw_disabled); - if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED)) + if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED)) static_key_slow_dec_deferred(&apic_sw_disabled); if (apic->regs) @@ -1103,7 +1076,7 @@ u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) || + if (!kvm_vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) || apic_lvtt_period(apic)) return 0; @@ -1114,7 +1087,7 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) || + if (!kvm_vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) || apic_lvtt_period(apic)) return; @@ -1127,21 +1100,21 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!vcpu_has_lapic(vcpu)) + if (!kvm_vcpu_has_lapic(vcpu)) return; apic_set_tpr(apic, ((cr8 & 0x0f) << 4) - | (apic_get_reg(apic, APIC_TASKPRI) & 4)); + | (kvm_apic_get_reg(apic, APIC_TASKPRI) & 4)); } u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) { u64 tpr; - if (!vcpu_has_lapic(vcpu)) + if (!kvm_vcpu_has_lapic(vcpu)) return 0; - tpr = (u64) apic_get_reg(vcpu->arch.apic, APIC_TASKPRI); + tpr = (u64) kvm_apic_get_reg(vcpu->arch.apic, APIC_TASKPRI); return (tpr & 0xf0) >> 4; } @@ -1238,16 +1211,6 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) vcpu->arch.apic_base, apic->base_address); } -bool kvm_apic_present(struct kvm_vcpu *vcpu) -{ - return vcpu_has_lapic(vcpu) && apic_hw_enabled(vcpu->arch.apic); -} - -int kvm_lapic_enabled(struct kvm_vcpu *vcpu) -{ - return kvm_apic_present(vcpu) && apic_sw_enabled(vcpu->arch.apic); -} - /* *---------------------------------------------------------------------- * timer interface @@ -1263,7 +1226,7 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - if (vcpu_has_lapic(vcpu) && apic_enabled(apic) && + if (kvm_vcpu_has_lapic(vcpu) && apic_enabled(apic) && apic_lvt_enabled(apic, APIC_LVTT)) return atomic_read(&apic->lapic_timer.pending); @@ -1272,10 +1235,10 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu) int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type) { - u32 reg = apic_get_reg(apic, lvt_type); + u32 reg = kvm_apic_get_reg(apic, lvt_type); int vector, mode, trig_mode; - if (apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) { + if (kvm_apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) { vector = reg & APIC_VECTOR_MASK; mode = reg & APIC_MODE_MASK; trig_mode = reg & APIC_LVT_LEVEL_TRIGGER; @@ -1375,23 +1338,23 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) struct kvm_lapic *apic = vcpu->arch.apic; int highest_irr; - if (!vcpu_has_lapic(vcpu) || !apic_enabled(apic)) + if (!kvm_vcpu_has_lapic(vcpu) || !apic_enabled(apic)) return -1; apic_update_ppr(apic); highest_irr = apic_find_highest_irr(apic); if ((highest_irr == -1) || - ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI))) + ((highest_irr & 0xF0) <= kvm_apic_get_reg(apic, APIC_PROCPRI))) return -1; return highest_irr; } int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu) { - u32 lvt0 = apic_get_reg(vcpu->arch.apic, APIC_LVT0); + u32 lvt0 = kvm_apic_get_reg(vcpu->arch.apic, APIC_LVT0); int r = 0; - if (!apic_hw_enabled(vcpu->arch.apic)) + if (!kvm_apic_hw_enabled(vcpu->arch.apic)) r = 1; if ((lvt0 & APIC_LVT_MASKED) == 0 && GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT) @@ -1403,7 +1366,7 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!vcpu_has_lapic(vcpu)) + if (!kvm_vcpu_has_lapic(vcpu)) return; if (atomic_read(&apic->lapic_timer.pending) > 0) { @@ -1432,7 +1395,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) kvm_lapic_set_base(vcpu, vcpu->arch.apic_base); kvm_apic_set_version(vcpu); - apic_set_spiv(apic, apic_get_reg(apic, APIC_SPIV)); + apic_set_spiv(apic, kvm_apic_get_reg(apic, APIC_SPIV)); apic_update_ppr(apic); hrtimer_cancel(&apic->lapic_timer.timer); @@ -1448,7 +1411,7 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) { struct hrtimer *timer; - if (!vcpu_has_lapic(vcpu)) + if (!kvm_vcpu_has_lapic(vcpu)) return; timer = &vcpu->arch.apic->lapic_timer.timer; @@ -1549,7 +1512,7 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu) if (!test_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention)) return; - tpr = apic_get_reg(apic, APIC_TASKPRI) & 0xff; + tpr = kvm_apic_get_reg(apic, APIC_TASKPRI) & 0xff; max_irr = apic_find_highest_irr(apic); if (max_irr < 0) max_irr = 0; @@ -1608,7 +1571,7 @@ int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 reg, u64 data) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!vcpu_has_lapic(vcpu)) + if (!kvm_vcpu_has_lapic(vcpu)) return 1; /* if this is ICR write vector before command */ @@ -1622,7 +1585,7 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data) struct kvm_lapic *apic = vcpu->arch.apic; u32 low, high = 0; - if (!vcpu_has_lapic(vcpu)) + if (!kvm_vcpu_has_lapic(vcpu)) return 1; if (apic_reg_read(apic, reg, 4, &low)) diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 73fa299b68e8..2ad9caa06f94 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -55,8 +55,6 @@ int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type); u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); -int kvm_lapic_enabled(struct kvm_vcpu *vcpu); -bool kvm_apic_present(struct kvm_vcpu *vcpu); int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu); @@ -79,4 +77,47 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu) int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data); void kvm_lapic_init(void); + +static inline u32 kvm_apic_get_reg(struct kvm_lapic *apic, int reg_off) +{ + return *((u32 *) (apic->regs + reg_off)); +} + +extern struct static_key kvm_no_apic_vcpu; + +static inline bool kvm_vcpu_has_lapic(struct kvm_vcpu *vcpu) +{ + if (static_key_false(&kvm_no_apic_vcpu)) + return vcpu->arch.apic; + return true; +} + +extern struct static_key_deferred apic_hw_disabled; + +static inline int kvm_apic_hw_enabled(struct kvm_lapic *apic) +{ + if (static_key_false(&apic_hw_disabled.key)) + return apic->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE; + return MSR_IA32_APICBASE_ENABLE; +} + +extern struct static_key_deferred apic_sw_disabled; + +static inline int kvm_apic_sw_enabled(struct kvm_lapic *apic) +{ + if (static_key_false(&apic_sw_disabled.key)) + return kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; + return APIC_SPIV_APIC_ENABLED; +} + +static inline bool kvm_apic_present(struct kvm_vcpu *vcpu) +{ + return kvm_vcpu_has_lapic(vcpu) && kvm_apic_hw_enabled(vcpu->arch.apic); +} + +static inline int kvm_lapic_enabled(struct kvm_vcpu *vcpu) +{ + return kvm_apic_present(vcpu) && kvm_apic_sw_enabled(vcpu->arch.apic); +} + #endif From 8defe59969cb8d863fe46867809316350ec0fc8f Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 3 Aug 2012 18:07:20 -0700 Subject: [PATCH 0385/5375] MAINTAINERS: Add pstore maintainers Signed-off-by: Anton Vorontsov Acked-by: Tony Luck Acked-by: Kees Cook --- MAINTAINERS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 94b823f71e94..9aa40c1b29e4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5496,6 +5496,18 @@ L: cbe-oss-dev@lists.ozlabs.org S: Maintained F: drivers/block/ps3vram.c +PSTORE FILESYSTEM +M: Anton Vorontsov +M: Colin Cross +M: Kees Cook +M: Tony Luck +S: Maintained +T: git git://git.infradead.org/users/cbou/linux-pstore.git +F: fs/pstore/ +F: include/linux/pstore* +F: drivers/firmware/efivars.c +F: drivers/acpi/apei/erst.c + PTP HARDWARE CLOCK SUPPORT M: Richard Cochran S: Maintained From adfa06dc177f91e07ce6b4c472befc35ea7dc6ab Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 6 Aug 2012 13:59:06 -0300 Subject: [PATCH 0386/5375] ARM: mxs_defconfig: Add LED, PWM and MTD_CHAR support Add LED, PWM and MTD_CHAR support. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- arch/arm/configs/mxs_defconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index e3487e491f9a..4cb61700e65e 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -60,6 +60,7 @@ CONFIG_DEVTMPFS=y # CONFIG_FIRMWARE_IN_KERNEL is not set # CONFIG_BLK_DEV is not set CONFIG_MTD=y +CONFIG_MTD_CHAR=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_GPMI_NAND=y CONFIG_NETDEVICES=y @@ -118,12 +119,23 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_MMC=y CONFIG_MMC_MXS=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_GPIO=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=m CONFIG_RTC_DRV_STMP=y CONFIG_DMADEVICES=y CONFIG_MXS_DMA=y CONFIG_COMMON_CLK_DEBUG=y +CONFIG_PWM=y +CONFIG_PWM_MXS=y CONFIG_EXT3_FS=y # CONFIG_DNOTIFY is not set CONFIG_FSCACHE=m From 209ffe19ff98f5c0133bd98a689fc4fb42202de3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 7 Aug 2012 12:07:27 +0530 Subject: [PATCH 0387/5375] ASoC: cs42l52: Remove duplicate inclusion of slab.h header file slab.h header file was included twice. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 628daf6a1d97..61599298fb26 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include From 5f800080ca6840326b3048202fb63fc4a71a4c49 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 7 Aug 2012 10:24:13 +0300 Subject: [PATCH 0388/5375] ASoC: core: Set dapm->idle_bias_off for DAIs not mapped with a codec The idle_bias_off flag is not configured for DAIs not mapped with a codec. This causes the pm counter to be increased at probe time for the CPU dai which unbalances the pm counter handling. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f81c5976b961..f10f00b5d29f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3715,6 +3715,9 @@ int snd_soc_register_dai(struct device *dev, } } + if (!dai->codec) + dai->dapm.idle_bias_off = 1; + list_add(&dai->list, &dai_list); mutex_unlock(&client_mutex); @@ -3803,6 +3806,9 @@ int snd_soc_register_dais(struct device *dev, } } + if (!dai->codec) + dai->dapm.idle_bias_off = 1; + list_add(&dai->list, &dai_list); mutex_unlock(&client_mutex); From 730963f8190b7650b0445a76e701fdef20c31cfb Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 7 Aug 2012 01:29:43 -0300 Subject: [PATCH 0389/5375] ASoC: mxs-saif: Use devm_clk_get() Using devm_clk_get can make the code simpler and smaller. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-saif.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index b3030718c228..aa037b292f3d 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -704,7 +704,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) return ret; } - saif->clk = clk_get(&pdev->dev, NULL); + saif->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(saif->clk)) { ret = PTR_ERR(saif->clk); dev_err(&pdev->dev, "Cannot get the clock: %d\n", @@ -717,8 +717,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) saif->base = devm_request_and_ioremap(&pdev->dev, iores); if (!saif->base) { dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENODEV; - goto failed_get_resource; + return -ENODEV; } dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); @@ -731,7 +730,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) &saif->dma_param.chan_num); if (ret) { dev_err(&pdev->dev, "failed to get dma channel\n"); - goto failed_get_resource; + return ret; } } else { saif->dma_param.chan_num = dmares->start; @@ -742,7 +741,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) ret = saif->irq; dev_err(&pdev->dev, "failed to get irq resource: %d\n", ret); - goto failed_get_resource; + return ret; } saif->dev = &pdev->dev; @@ -750,7 +749,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) "mxs-saif", saif); if (ret) { dev_err(&pdev->dev, "failed to request irq\n"); - goto failed_get_resource; + return ret; } saif->dma_param.chan_irq = platform_get_irq(pdev, 1); @@ -758,7 +757,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) ret = saif->dma_param.chan_irq; dev_err(&pdev->dev, "failed to get dma irq resource: %d\n", ret); - goto failed_get_resource; + return ret; } platform_set_drvdata(pdev, saif); @@ -766,7 +765,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai); if (ret) { dev_err(&pdev->dev, "register DAI failed\n"); - goto failed_get_resource; + return ret; } ret = mxs_pcm_platform_register(&pdev->dev); @@ -779,19 +778,14 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev) failed_pdev_alloc: snd_soc_unregister_dai(&pdev->dev); -failed_get_resource: - clk_put(saif->clk); return ret; } static int __devexit mxs_saif_remove(struct platform_device *pdev) { - struct mxs_saif *saif = platform_get_drvdata(pdev); - mxs_pcm_platform_unregister(&pdev->dev); snd_soc_unregister_dai(&pdev->dev); - clk_put(saif->clk); return 0; } From 5a213a55c6d39fd24eaba4610dac21444090a365 Mon Sep 17 00:00:00 2001 From: Leela Krishna Amudala Date: Wed, 8 Aug 2012 09:44:49 +0900 Subject: [PATCH 0390/5375] include/video: move fimd register headers from platform to include/video This patch moves the contents from regs-fb-v4.h and regs-fb.h to include/video/samsung_fimd.h. Also updates the header inclusion in machine files and driver files accordingly. Signed-off-by: Leela Krishna Amudala Cc: Florian Tobias Schandinat Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/mach-nuri.c | 2 +- arch/arm/mach-exynos/mach-origen.c | 2 +- arch/arm/mach-exynos/mach-smdk4x12.c | 2 +- arch/arm/mach-exynos/mach-smdkv310.c | 2 +- arch/arm/mach-exynos/mach-universal_c210.c | 2 +- arch/arm/mach-exynos/setup-fimd0.c | 2 +- arch/arm/mach-s3c24xx/mach-smdk2416.c | 2 +- arch/arm/mach-s3c64xx/mach-anw6410.c | 2 +- arch/arm/mach-s3c64xx/mach-crag6410.c | 2 +- arch/arm/mach-s3c64xx/mach-hmt.c | 2 +- arch/arm/mach-s3c64xx/mach-mini6410.c | 2 +- arch/arm/mach-s3c64xx/mach-ncp.c | 2 +- arch/arm/mach-s3c64xx/mach-real6410.c | 2 +- arch/arm/mach-s3c64xx/mach-smartq5.c | 2 +- arch/arm/mach-s3c64xx/mach-smartq7.c | 2 +- arch/arm/mach-s3c64xx/mach-smdk6410.c | 2 +- arch/arm/mach-s5p64x0/mach-smdk6440.c | 2 +- arch/arm/mach-s5p64x0/mach-smdk6450.c | 2 +- arch/arm/mach-s5pc100/mach-smdkc100.c | 2 +- arch/arm/mach-s5pv210/mach-aquila.c | 2 +- arch/arm/mach-s5pv210/mach-goni.c | 2 +- arch/arm/mach-s5pv210/mach-smdkv210.c | 2 +- .../plat-samsung/include/plat/regs-fb-v4.h | 159 ------------------ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 +- drivers/video/s3c-fb.c | 2 +- .../regs-fb.h => include/video/samsung_fimd.h | 145 ++++++++++++++-- 26 files changed, 158 insertions(+), 194 deletions(-) delete mode 100644 arch/arm/plat-samsung/include/plat/regs-fb-v4.h rename arch/arm/plat-samsung/include/plat/regs-fb.h => include/video/samsung_fimd.h (74%) diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index ea785fcaf6c3..90d8daa6cf24 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -29,6 +29,7 @@ #include #include