From 14f8351a313f364afbc565f1ddcd43f8cfdccf52 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Thu, 6 Jan 2005 21:16:45 +0000 Subject: [MTD] slram driver cleanup Add error checks to read/write functions and add an eraseblock size. Makes slram a suitable device for JFFS2. Signed-off-by: Josh Boyer Signed-off-by: Thomas Gleixner --- drivers/mtd/devices/slram.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 5ab15e643be..84fa91392a8 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -1,6 +1,6 @@ /*====================================================================== - $Id: slram.c,v 1.33 2005/01/05 18:05:13 dwmw2 Exp $ + $Id: slram.c,v 1.34 2005/01/06 21:16:42 jwboyer Exp $ This driver provides a method to access memory not used by the kernel itself (i.e. if the kernel commandline mem=xxx is used). To actually @@ -50,6 +50,7 @@ #include #define SLRAM_MAX_DEVICES_PARAMS 6 /* 3 parameters / device */ +#define SLRAM_BLK_SZ 0x4000 #define T(fmt, args...) printk(KERN_DEBUG fmt, ## args) #define E(fmt, args...) printk(KERN_NOTICE fmt, ## args) @@ -108,6 +109,9 @@ static int slram_point(struct mtd_info *mtd, loff_t from, size_t len, { slram_priv_t *priv = mtd->priv; + if (from + len > mtd->size) + return -EINVAL; + *mtdbuf = priv->start + from; *retlen = len; return(0); @@ -121,7 +125,13 @@ static int slram_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { slram_priv_t *priv = mtd->priv; - + + if (from > mtd->size) + return -EINVAL; + + if (from + len > mtd->size) + len = mtd->size - from; + memcpy(buf, priv->start + from, len); *retlen = len; @@ -133,6 +143,9 @@ static int slram_write(struct mtd_info *mtd, loff_t to, size_t len, { slram_priv_t *priv = mtd->priv; + if (to + len > mtd->size) + return -EINVAL; + memcpy(priv->start + to, buf, len); *retlen = len; @@ -188,7 +201,7 @@ static int register_device(char *name, unsigned long start, unsigned long length (*curmtd)->mtdinfo->name = name; (*curmtd)->mtdinfo->size = length; (*curmtd)->mtdinfo->flags = MTD_CLEAR_BITS | MTD_SET_BITS | - MTD_WRITEB_WRITEABLE | MTD_VOLATILE; + MTD_WRITEB_WRITEABLE | MTD_VOLATILE | MTD_CAP_RAM; (*curmtd)->mtdinfo->erase = slram_erase; (*curmtd)->mtdinfo->point = slram_point; (*curmtd)->mtdinfo->unpoint = slram_unpoint; @@ -196,7 +209,7 @@ static int register_device(char *name, unsigned long start, unsigned long length (*curmtd)->mtdinfo->write = slram_write; (*curmtd)->mtdinfo->owner = THIS_MODULE; (*curmtd)->mtdinfo->type = MTD_RAM; - (*curmtd)->mtdinfo->erasesize = 0x0; + (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ; if (add_mtd_device((*curmtd)->mtdinfo)) { E("slram: Failed to register new device\n"); @@ -261,7 +274,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) } T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n", devname, devstart, devlength); - if ((devstart < 0) || (devlength < 0)) { + if ((devstart < 0) || (devlength < 0) || (devlength % SLRAM_BLK_SZ != 0)) { E("slram: Illegal start / length parameter.\n"); return(-EINVAL); } -- cgit v1.2.3 From 8ea2e06fc8d2f03b49cef7732ae8e290e2f0b183 Mon Sep 17 00:00:00 2001 From: Herbert Valerio Riedel Date: Mon, 17 Jan 2005 13:47:24 +0000 Subject: [MTD] FTL Fix missing pointer assignment For the case that mtd partitions are enabled it would cause a 0-pointer dereferencing in mtdpart.c:mtd_erase_callback() Signed-off-by: Herbert Valerio Riedel Signed-off-by: Thomas Gleixner --- drivers/mtd/ftl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 18cc8846e73..d9ab60b36fd 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -1,5 +1,5 @@ /* This version ported to the Linux-MTD system by dwmw2@infradead.org - * $Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $ + * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $ * * Fixes: Arnaldo Carvalho de Melo * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups @@ -357,6 +357,7 @@ static int erase_xfer(partition_t *part, if (!erase) return -ENOMEM; + erase->mtd = part->mbd.mtd; erase->callback = ftl_erase_callback; erase->addr = xfer->Offset; erase->len = 1 << part->header.EraseUnitSize; @@ -1096,7 +1097,7 @@ struct mtd_blktrans_ops ftl_tr = { int init_ftl(void) { - DEBUG(0, "$Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $\n"); + DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n"); return register_mtd_blktrans(&ftl_tr); } -- cgit v1.2.3 From 28a48de72b876af794853593cc1412119ada9efc Mon Sep 17 00:00:00 2001 From: "David A. Marlin" Date: Mon, 17 Jan 2005 18:29:21 +0000 Subject: [MTD] NAND extended commands, badb block table autorefresh Added extended commands for AG-AND device and added option for BBT_AUTO_REFRESH. Signed-off-by: David A. Marlin Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_ids.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 2d8c4321275..9756797c92f 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -3,7 +3,7 @@ * * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $ + * $Id: nand_ids.c,v 1.11 2005/01/17 18:26:27 dmarlin Exp $ * * 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 @@ -103,7 +103,7 @@ struct nand_flash_dev nand_flash_ids[] = { * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go * There are more speed improvements for reads and writes possible, but not implemented now */ - {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY}, + {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, {NULL,} }; -- cgit v1.2.3 From 30f464b74b51127b9b9a170157b75c7e8e80d2c4 Mon Sep 17 00:00:00 2001 From: "David A. Marlin" Date: Mon, 17 Jan 2005 18:35:25 +0000 Subject: [MTD] NAND workaround for AG-AND disturb issue. AG-AND recovery Added workaround for Renesas AG-AND chips "disturb" issue for Bad Block Table. Added support for the device recovery command sequence for Renesas AG-AND chips. Signed-off-by: David A. Marlin Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 74 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 44d5b128911..2ac452e3ad6 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -28,6 +28,20 @@ * among multiple independend devices. Suggestions and initial patch * from Ben Dooks * + * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue. + * Basically, any block not rewritten may lose data when surrounding blocks + * are rewritten many times. JFFS2 ensures this doesn't happen for blocks + * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they + * do not lose data, force them to be rewritten when some of the surrounding + * blocks are erased. Rather than tracking a specific nearby block (which + * could itself go bad), use a page address 'mask' to select several blocks + * in the same area, and rewrite the BBT when any of them are erased. + * + * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas + * AG-AND chips. If there was a sudden loss of power during an erase operation, + * a "device recovery" operation must be performed when power is restored + * to ensure correct operation. + * * Credits: * David Woodhouse for adding multichip support * @@ -41,7 +55,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen Exp $ + * $Id: nand_base.c,v 1.127 2005/01/17 18:35:22 dmarlin Exp $ * * 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 @@ -619,7 +633,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, /* Begin command latch cycle */ this->hwcontrol(mtd, NAND_CTL_SETCLE); /* Write out the command to the device. */ - this->write_byte(mtd, command); + this->write_byte(mtd, (command & 0xff)); /* End command latch cycle */ this->hwcontrol(mtd, NAND_CTL_CLRCLE); @@ -647,8 +661,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, /* * program and erase have their own busy handlers - * status and sequential in needs no delay - */ + * status, sequential in, and deplete1 need no delay + */ switch (command) { case NAND_CMD_CACHEDPROG: @@ -657,8 +671,19 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, case NAND_CMD_ERASE2: case NAND_CMD_SEQIN: case NAND_CMD_STATUS: + case NAND_CMD_DEPLETE1: return; + /* + * read error status commands require only a short delay + */ + case NAND_CMD_STATUS_ERROR: + case NAND_CMD_STATUS_ERROR0: + case NAND_CMD_STATUS_ERROR1: + case NAND_CMD_STATUS_ERROR2: + case NAND_CMD_STATUS_ERROR3: + udelay(this->chip_delay); + return; case NAND_CMD_RESET: if (this->dev_ready) @@ -1051,7 +1076,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd ,FL_READING); + nand_get_device (this, mtd, FL_READING); /* use userspace supplied oobinfo, if zero */ if (oobsel == NULL) @@ -1987,6 +2012,7 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) return nand_erase_nand (mtd, instr, 0); } +#define BBT_PAGE_MASK 0xffffff3f /** * nand_erase_intern - [NAND Interface] erase block(s) * @mtd: MTD device structure @@ -1999,6 +2025,10 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb { int page, len, status, pages_per_block, ret, chipnr; struct nand_chip *this = mtd->priv; + int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */ + unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */ + /* It is used to see if the current page is in the same */ + /* 256 block group and the same bank as the bbt. */ DEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); @@ -2044,6 +2074,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb goto erase_exit; } + /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */ + if (this->options & BBT_AUTO_REFRESH) { + bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; + } else { + bbt_masked_page = 0xffffffff; /* should not match anything */ + } + /* Loop through the pages */ len = instr->len; @@ -2073,6 +2110,14 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb instr->fail_addr = (page << this->page_shift); goto erase_exit; } + + /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */ + if (this->options & BBT_AUTO_REFRESH) { + if (((page & BBT_PAGE_MASK) == bbt_masked_page) && + (page != this->bbt_td->pages[chipnr])) { + rewrite_bbt[chipnr] = (page << this->page_shift); + } + } /* Increment page address and decrement length */ len -= (1 << this->phys_erase_shift); @@ -2083,6 +2128,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb chipnr++; this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); + + /* if BBT requires refresh and BBT-PERCHIP, + * set the BBT page mask to see if this BBT should be rewritten */ + if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) { + bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; + } + } } instr->state = MTD_ERASE_DONE; @@ -2097,6 +2149,18 @@ erase_exit: /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); + /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */ + if ((this->options & BBT_AUTO_REFRESH) && (!ret)) { + for (chipnr = 0; chipnr < this->numchips; chipnr++) { + if (rewrite_bbt[chipnr]) { + /* update the BBT for chip */ + DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", + chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]); + nand_update_bbt (mtd, rewrite_bbt[chipnr]); + } + } + } + /* Return more or less happy */ return ret; } -- cgit v1.2.3 From 97f1a087dc83cac54d740bf24888e565962b8f4d Mon Sep 17 00:00:00 2001 From: "David A. Marlin" Date: Mon, 17 Jan 2005 19:44:39 +0000 Subject: [MTD] Renesas AG-AND device recovery Add routine to perform device recovery (deplete) procedure. Clean up some compiler warnings. Signed-off-by: David A. Marlin Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/rtc_from4.c | 48 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 02305a2adca..a4d8d2e62e9 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -6,7 +6,7 @@ * Derived from drivers/mtd/nand/spia.c * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: rtc_from4.c,v 1.7 2004/11/04 12:53:10 gleixner Exp $ + * $Id: rtc_from4.c,v 1.8 2005/01/17 19:44:36 dmarlin Exp $ * * 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 @@ -89,7 +89,7 @@ static struct mtd_info *rtc_from4_mtd = NULL; /* * Module stuff */ -static void __iomem *rtc_from4_fio_base = P2SEGADDR(RTC_FROM4_FIO_BASE); +static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE); const static struct mtd_partition partition_info[] = { { @@ -286,6 +286,40 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd) } + +/* + * deplete - code to perform device recovery in case there was a power loss + * @mtd: MTD device structure + * @chip: Chip to select (0 == slot 3, 1 == slot 4) + * + * If there was a sudden loss of power during an erase operation, a + * "device recovery" operation must be performed when power is restored + * to ensure correct operation. This routine performs the required steps + * for the requested chip. + * + * See page 86 of the data sheet for details. + * + */ +static void deplete(struct mtd_info *mtd, int chip) +{ + struct nand_chip *this = mtd->priv; + + /* wait until device is ready */ + while (!this->dev_ready(mtd)); + + this->select_chip(mtd, chip); + + /* Send the commands for device recovery, phase 1 */ + this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); + this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); + + /* Send the commands for device recovery, phase 2 */ + this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004); + this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); + +} + + #ifdef RTC_FROM4_HWECC /* * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function @@ -374,7 +408,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha { int i, j, res; unsigned short status; - uint16_t par[6], syn[6], tmp; + uint16_t par[6], syn[6]; uint8_t ecc[8]; volatile unsigned short *rs_ecc; @@ -416,7 +450,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha } /* Let the library code do its magic.*/ - res = decode_rs8(rs_decoder, buf, par, 512, syn, 0, NULL, 0xff, NULL); + res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL); if (res > 0) { DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); @@ -432,6 +466,7 @@ int __init rtc_from4_init (void) { struct nand_chip *this; unsigned short bcr1, bcr2, wcr2; + int i; /* Allocate memory for MTD device structure and private data */ rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), @@ -504,6 +539,11 @@ int __init rtc_from4_init (void) return -ENXIO; } + /* Perform 'device recovery' for each chip in case there was a power loss. */ + for (i=0; i < this->numchips; i++) { + deplete(rtc_from4_mtd, i); + } + /* Register the partitions */ add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); -- cgit v1.2.3 From 6fc93d8ca7a093feb403aca4ee3cb5bda338392c Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 18 Jan 2005 11:13:50 +0000 Subject: [MTD] bast-flash partitions fixup Ensure the whole device is added if there are no partitions found on the device, so that at least the flash can be read/written. Replace some of the constants with their SZ_xxx counterparts Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/bast-flash.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c index 44de3a81b27..0c45464e3f7 100644 --- a/drivers/mtd/maps/bast-flash.c +++ b/drivers/mtd/maps/bast-flash.c @@ -1,14 +1,15 @@ /* linux/drivers/mtd/maps/bast_flash.c * - * Copyright (c) 2004 Simtec Electronics - * Ben Dooks + * Copyright (c) 2004-2005 Simtec Electronics + * Ben Dooks * * Simtec Bast (EB2410ITX) NOR MTD Mapping driver * * Changelog: * 20-Sep-2004 BJD Initial version + * 17-Jan-2005 BJD Add whole device if no partitions found * - * $Id: bast-flash.c,v 1.1 2004/09/21 14:29:04 bjd Exp $ + * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $ * * 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 @@ -46,9 +47,9 @@ #include #ifdef CONFIG_MTD_BAST_MAXSIZE -#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * (1024*1024)) +#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * SZ_1M) #else -#define AREA_MAXSIZE (32*1024*1024) +#define AREA_MAXSIZE (32 * SZ_1M) #endif #define PFX "bast-flash: " @@ -189,6 +190,8 @@ static int bast_flash_probe(struct device *dev) err = add_mtd_partitions(info->mtd, info->partitions, err); if (err) printk(KERN_ERR PFX "cannot add/parse partitions\n"); + } else { + err = add_mtd_device(info->mtd); } if (err == 0) -- cgit v1.2.3 From 15266bb74d0156556f9541c9817b778286ffe5d6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 18 Jan 2005 16:15:00 +0000 Subject: [MTD] NAND replace yield Replace yield by msleep. M.Wilcox stared at it and frowned Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 2ac452e3ad6..68a6014f556 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -55,7 +55,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.127 2005/01/17 18:35:22 dmarlin Exp $ + * $Id: nand_base.c,v 1.128 2005/01/18 16:14:56 gleixner Exp $ * * 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 @@ -810,7 +810,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) if (this->read_byte(mtd) & NAND_STATUS_READY) break; } - yield (); + msleep(1); } status = (int) this->read_byte(mtd); return status; -- cgit v1.2.3 From 7ba48c4583f7da5b05cf9859337195323df67b6d Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Sun, 23 Jan 2005 11:09:22 +0000 Subject: [MTD] NAND SharpSL fix default partition size Correct Poodle default partition size Signed-off-by: Richard Purdie Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/sharpsl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 29572793334..9853b87bb75 100755 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -3,7 +3,7 @@ * * Copyright (C) 2004 Richard Purdie * - * $Id: sharpsl.c,v 1.3 2005/01/03 14:53:50 rpurdie Exp $ + * $Id: sharpsl.c,v 1.4 2005/01/23 11:09:19 rpurdie Exp $ * * Based on Sharp's NAND driver sharp_sl.c * @@ -216,7 +216,7 @@ sharpsl_nand_init(void) nr_partitions = DEFAULT_NUM_PARTITIONS; sharpsl_partition_info = sharpsl_nand_default_partition_info; if (machine_is_poodle()) { - sharpsl_partition_info[1].size=22 * 1024 * 1024; + sharpsl_partition_info[1].size=30 * 1024 * 1024; } else if (machine_is_corgi() || machine_is_shepherd()) { sharpsl_partition_info[1].size=25 * 1024 * 1024; } else if (machine_is_husky()) { -- cgit v1.2.3 From a4ab4c5d32b66a440fb2e00f975f919f559f001d Mon Sep 17 00:00:00 2001 From: "David A. Marlin" Date: Sun, 23 Jan 2005 18:30:53 +0000 Subject: [MTD] NAND use symbols instead of literals Replace some literals with defined symbols. Signed-off-by: David A. Marlin Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 68a6014f556..9f7c42ceecf 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -55,7 +55,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.128 2005/01/18 16:14:56 gleixner Exp $ + * $Id: nand_base.c,v 1.129 2005/01/23 18:30:50 dmarlin Exp $ * * 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 @@ -480,7 +480,7 @@ static int nand_check_wp (struct mtd_info *mtd) struct nand_chip *this = mtd->priv; /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - return (this->read_byte(mtd) & 0x80) ? 0 : 1; + return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; } /** @@ -585,7 +585,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in this->hwcontrol(mtd, NAND_CTL_SETCLE); this->write_byte(mtd, NAND_CMD_STATUS); this->hwcontrol(mtd, NAND_CTL_CLRCLE); - while ( !(this->read_byte(mtd) & 0x40)); + while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); return; /* This applies to read commands */ @@ -692,7 +692,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, this->hwcontrol(mtd, NAND_CTL_SETCLE); this->write_byte(mtd, NAND_CMD_STATUS); this->hwcontrol(mtd, NAND_CTL_CLRCLE); - while ( !(this->read_byte(mtd) & 0x40)); + while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); return; case NAND_CMD_READ0: @@ -897,7 +897,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa /* call wait ready function */ status = this->waitfunc (mtd, this, FL_WRITING); /* See if device thinks it succeeded */ - if (status & 0x01) { + if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); return -EIO; } @@ -1758,7 +1758,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * status = this->waitfunc (mtd, this, FL_WRITING); /* See if device thinks it succeeded */ - if (status & 0x01) { + if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); ret = -EIO; goto out; @@ -2104,7 +2104,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb status = this->waitfunc (mtd, this, FL_ERASING); /* See if block erase succeeded */ - if (status & 0x01) { + if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; instr->fail_addr = (page << this->page_shift); -- cgit v1.2.3 From 99f2a8aea18c9779c141050c6f95a8f1da63bbe4 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 24 Jan 2005 00:37:04 +0000 Subject: [MTD] Platform RAM Driver Driver for generic RAM blocks which are exported by an platform_device from the device driver system. Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/Kconfig | 12 +- drivers/mtd/maps/Makefile | 3 +- drivers/mtd/maps/plat-ram.c | 286 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 299 insertions(+), 2 deletions(-) create mode 100644 drivers/mtd/maps/plat-ram.c (limited to 'drivers') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 8480057eadb..7d21d432f38 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.42 2005/01/05 16:59:50 dwmw2 Exp $ +# $Id: Kconfig,v 1.43 2005/01/24 00:35:21 bjd Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -659,5 +659,15 @@ config MTD_SHARP_SL help This enables access to the flash chip on the Sharp SL Series of PDAs. +config MTD_PLATRAM + tristate "Map driver for platfrom device RAM (mtd-ram)" + depends on MTD + select MTD_RAM + help + Map driver for RAM areas described via the platform device + system. + + This selection automatically selects the map_ram driver. + endmenu diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 7ffe02b8530..d2e6dcc8705 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile.common,v 1.23 2005/01/05 17:06:36 dwmw2 Exp $ +# $Id: Makefile.common,v 1.24 2005/01/24 00:35:21 bjd Exp $ ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) obj-$(CONFIG_MTD) += map_funcs.o @@ -71,3 +71,4 @@ obj-$(CONFIG_MTD_IXP2000) += ixp2000.o obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o obj-$(CONFIG_MTD_DMV182) += dmv182.o obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o +obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c new file mode 100644 index 00000000000..808f94346ad --- /dev/null +++ b/drivers/mtd/maps/plat-ram.c @@ -0,0 +1,286 @@ +/* drivers/mtd/maps/plat-ram.c + * + * (c) 2004-2005 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * Ben Dooks + * + * Generic platfrom device based RAM map + * + * $Id: plat-ram.c,v 1.1 2005/01/24 00:37:02 bjd Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* private structure for each mtd platform ram device created */ + +struct platram_info { + struct device *dev; + struct mtd_info *mtd; + struct map_info map; + struct mtd_partition *partitions; + struct resource *area; + struct platdata_mtd_ram *pdata; +}; + +/* to_platram_info() + * + * device private data to struct platram_info conversion +*/ + +static inline struct platram_info *to_platram_info(struct device *dev) +{ + return (struct platram_info *)dev_get_drvdata(dev); +} + +/* platram_setrw + * + * call the platform device's set rw/ro control + * + * to = 0 => read-only + * = 1 => read-write +*/ + +static inline void platram_setrw(struct platram_info *info, int to) +{ + if (info->pdata == NULL) + return; + + if (info->pdata->set_rw != NULL) + (info->pdata->set_rw)(info->dev, to); +} + +/* platram_remove + * + * called to remove the device from the driver's control +*/ + +static int platram_remove(struct device *dev) +{ + struct platram_info *info = to_platram_info(dev); + + dev_set_drvdata(dev, NULL); + + dev_dbg(dev, "removing device\n"); + + if (info == NULL) + return 0; + + if (info->mtd) { +#ifdef CONFIG_MTD_PARTITIONS + if (info->partitions) { + del_mtd_partitions(info->mtd); + kfree(info->partitions); + } +#endif + del_mtd_device(info->mtd); + map_destroy(info->mtd); + } + + /* ensure ram is left read-only */ + + platram_setrw(info, PLATRAM_RO); + + /* release resources */ + + if (info->area) { + release_resource(info->area); + kfree(info->area); + } + + if (info->map.virt != NULL) + iounmap(info->map.virt); + + kfree(info); + + return 0; +} + +/* platram_probe + * + * called from device drive system when a device matching our + * driver is found. +*/ + +static int platram_probe(struct device *dev) +{ + struct platform_device *pd = to_platform_device(dev); + struct platdata_mtd_ram *pdata; + struct platram_info *info; + struct resource *res; + int err = 0; + + dev_dbg(dev, "probe entered\n"); + + if (dev->platform_data == NULL) { + dev_err(dev, "no platform data supplied\n"); + err = -ENOENT; + goto exit_error; + } + + pdata = dev->platform_data; + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + dev_err(dev, "no memory for flash info\n"); + err = -ENOMEM; + goto exit_error; + } + + memzero(info, sizeof(*info)); + dev_set_drvdata(dev, info); + + info->dev = dev; + info->pdata = pdata; + + /* get the resource for the memory mapping */ + + res = platform_get_resource(pd, IORESOURCE_MEM, 0); + + if (res == NULL) { + dev_err(dev, "no memory resource specified\n"); + err = -ENOENT; + goto exit_free; + } + + dev_dbg(dev, "got platform resource %p (0x%lx)\n", res, res->start); + + /* setup map parameters */ + + info->map.phys = res->start; + info->map.size = (res->end - res->start) + 1; + info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name; + info->map.bankwidth = pdata->bankwidth; + + /* register our usage of the memory area */ + + info->area = request_mem_region(res->start, info->map.size, pd->name); + if (info->area == NULL) { + dev_err(dev, "failed to request memory region\n"); + err = -EIO; + goto exit_free; + } + + /* remap the memory area */ + + info->map.virt = ioremap(res->start, info->map.size); + dev_dbg(dev, "virt %p, %d bytes\n", info->map.virt, info->map.size); + + if (info->map.virt == NULL) { + dev_err(dev, "failed to ioremap() region\n"); + err = -EIO; + goto exit_free; + } + + { + unsigned int *p = (unsigned int *)info->map.virt; + printk("%08x %08x %08x %08x\n", + readl(p), readl(p+1), readl(p+2), readl(p+3)); + } + + simple_map_init(&info->map); + + dev_dbg(dev, "initialised map, probing for mtd\n"); + + /* probe for the right mtd map driver */ + + info->mtd = do_map_probe("map_ram" , &info->map); + if (info->mtd == NULL) { + dev_err(dev, "failed to probe for map_ram\n"); + err = -ENOMEM; + goto exit_free; + } + + info->mtd->owner = THIS_MODULE; + + platram_setrw(info, PLATRAM_RW); + + /* check to see if there are any available partitions, or wether + * to add this device whole */ + +#ifdef CONFIG_MTD_PARTITIONS + if (pdata->nr_partitions > 0) { + const char **probes = { NULL }; + + if (pdata->probes) + probes = (const char **)pdata->probes; + + err = parse_mtd_partitions(info->mtd, probes, + &info->partitions, 0); + if (err > 0) { + err = add_mtd_partitions(info->mtd, info->partitions, + err); + } + } +#endif /* CONFIG_MTD_PARTITIONS */ + + if (add_mtd_device(info->mtd)) { + dev_err(dev, "add_mtd_device() failed\n"); + err = -ENOMEM; + } + + dev_info(dev, "registered mtd device\n"); + return err; + + exit_free: + platram_remove(dev); + exit_error: + return err; +} + +/* device driver info */ + +static struct device_driver platram_driver = { + .name = "mtd-ram", + .bus = &platform_bus_type, + .probe = platram_probe, + .remove = platram_remove, +}; + +/* module init/exit */ + +static int __init platram_init(void) +{ + printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n"); + return driver_register(&platram_driver); +} + +static void __exit platram_exit(void) +{ + driver_unregister(&platram_driver); +} + +module_init(platram_init); +module_exit(platram_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("MTD platform RAM map driver"); -- cgit v1.2.3 From 068e3c0a002c79a5e3cc7c42cb749c4bb126288c Mon Sep 17 00:00:00 2001 From: "David A. Marlin" Date: Mon, 24 Jan 2005 03:07:46 +0000 Subject: [MTD] NAND Add optional ECC status check callback Add optional hardware specific callback routine to perform extra error status checks on erase and write failures for devices with hardware ECC. Signed-off-by: David A. Marlin Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 65 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 9f7c42ceecf..7094dd5716d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -42,6 +42,10 @@ * a "device recovery" operation must be performed when power is restored * to ensure correct operation. * + * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to + * perform extra error status checks on erase and write failures. This required + * adding a wrapper function for nand_read_ecc. + * * Credits: * David Woodhouse for adding multichip support * @@ -55,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.129 2005/01/23 18:30:50 dmarlin Exp $ + * $Id: nand_base.c,v 1.130 2005/01/24 03:07:43 dmarlin Exp $ * * 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 @@ -896,6 +900,12 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa if (!cached) { /* call wait ready function */ status = this->waitfunc (mtd, this, FL_WRITING); + + /* See if operation failed and additional status checks are available */ + if ((status & NAND_STATUS_FAIL) && (this->errstat)) { + status = this->errstat(mtd, this, FL_WRITING, status, page); + } + /* See if device thinks it succeeded */ if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); @@ -1022,23 +1032,24 @@ out: #endif /** - * nand_read - [MTD Interface] MTD compability function for nand_read_ecc + * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd: MTD device structure * @from: offset to read from * @len: number of bytes to read * @retlen: pointer to variable to store the number of read bytes * @buf: the databuffer to put data * - * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL -*/ + * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL + * and flags = 0xff + */ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) { - return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); + return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff); } /** - * nand_read_ecc - [MTD Interface] Read data with ECC + * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd: MTD device structure * @from: offset to read from * @len: number of bytes to read @@ -1047,10 +1058,34 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re * @oob_buf: filesystem supplied oob data buffer * @oobsel: oob selection structure * - * NAND read with ECC + * This function simply calls nand_do_read_ecc with flags = 0xff */ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) +{ + return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff); +} + + +/** + * nand_do_read_ecc - [MTD Interface] Read data with ECC + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @buf: the databuffer to put data + * @oob_buf: filesystem supplied oob data buffer + * @oobsel: oob selection structure + * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed + * and how many corrected error bits are acceptable: + * bits 0..7 - number of tolerable errors + * bit 8 - 0 == do not get/release chip, 1 == get/release chip + * + * NAND read with ECC + */ +int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf, u_char * oob_buf, + struct nand_oobinfo *oobsel, int flags) { int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; @@ -1076,7 +1111,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_READING); + if (flags & NAND_GET_DEVICE) + nand_get_device (this, mtd, FL_READING); /* use userspace supplied oobinfo, if zero */ if (oobsel == NULL) @@ -1180,7 +1216,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* We calc error correction directly, it checks the hw * generator for an error, reads back the syndrome and * does the error correction on the fly */ - if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { + ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); + if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); ecc_failed++; @@ -1219,7 +1256,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, p[i] = ecc_status; } - if (ecc_status == -1) { + if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } @@ -1289,7 +1326,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); + if (flags & NAND_GET_DEVICE) + nand_release_device(mtd); /* * Return success, if no ECC failures, else -EBADMSG @@ -2103,6 +2141,11 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb status = this->waitfunc (mtd, this, FL_ERASING); + /* See if operation failed and additional status checks are available */ + if ((status & NAND_STATUS_FAIL) && (this->errstat)) { + status = this->errstat(mtd, this, FL_ERASING, status, page); + } + /* See if block erase succeeded */ if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); -- cgit v1.2.3 From ed3786a599f5639c99dfcceaef1b064ab5e2e9f9 Mon Sep 17 00:00:00 2001 From: "David A. Marlin" Date: Mon, 24 Jan 2005 20:40:15 +0000 Subject: [MTD] rtc_from4 error status check, disable virtual erase blocks Added routine to perform extra error status checks on erase and write failures to determine if errors are correctable. Added option to prevent JFFS2 from using virtual erase blocks. Performed minor cleanup on whitespace and comments. Signed-off-by: David A. Marlin Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/rtc_from4.c | 94 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index a4d8d2e62e9..031051cbde7 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -6,7 +6,7 @@ * Derived from drivers/mtd/nand/spia.c * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: rtc_from4.c,v 1.8 2005/01/17 19:44:36 dmarlin Exp $ + * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $ * * 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 @@ -83,9 +83,14 @@ static struct mtd_info *rtc_from4_mtd = NULL; #define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070) #define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7) +#define ERR_STAT_ECC_AVAILABLE 0x20 + /* Undefine for software ECC */ #define RTC_FROM4_HWECC 1 +/* Define as 1 for no virtual erase blocks (in JFFS2) */ +#define RTC_FROM4_NO_VIRTBLOCKS 0 + /* * Module stuff */ @@ -267,7 +272,6 @@ static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip) } - /* * rtc_from4_nand_device_ready - hardware specific ready/busy check * @mtd: MTD device structure @@ -363,6 +367,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) } + /* * rtc_from4_calculate_ecc - hardware specific code to read ECC code * @mtd: MTD device structure @@ -390,6 +395,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c ecc_code[7] |= 0x0f; /* set the last four bits (not used) */ } + /* * rtc_from4_correct_data - hardware specific code to correct data using ECC code * @mtd: MTD device structure @@ -399,10 +405,8 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c * * The FPGA tells us fast, if there's an error or not. If no, we go back happy * else we read the ecc results from the fpga and call the rs library to decode - * and hopefully correct the error + * and hopefully correct the error. * - * For now I use the code, which we read from the FLASH to use the RS lib, - * as the syndrom conversion has a unresolved issue. */ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) { @@ -457,8 +461,79 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha } return res; } + + +/** + * rtc_from4_errstat - perform additional error status checks + * @mtd: MTD device structure + * @this: NAND chip structure + * @state: state or the operation + * @status: status code returned from read status + * @page: startpage inside the chip, must be called with (page & this->pagemask) + * + * Perform additional error status checks on erase and write failures + * to determine if errors are correctable. For this device, correctable + * 1-bit errors on erase and write are considered acceptable. + * + * note: see pages 34..37 of data sheet for details. + * + */ +static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page) +{ + int er_stat=0; + int rtn, retlen; + size_t len; + uint8_t *buf; + int i; + + this->cmdfunc (mtd, NAND_CMD_STATUS_CLEAR, -1, -1); + + if (state == FL_ERASING) { + for (i=0; i<4; i++) { + if (status & 1<<(i+1)) { + this->cmdfunc (mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1); + rtn = this->read_byte(mtd); + this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); + if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { + er_stat |= 1<<(i+1); /* err_ecc_not_avail */ + } + } + } + } else if (state == FL_WRITING) { + /* single bank write logic */ + this->cmdfunc (mtd, NAND_CMD_STATUS_ERROR, -1, -1); + rtn = this->read_byte(mtd); + this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); + if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { + er_stat |= 1<<1; /* err_ecc_not_avail */ + } else { + len = mtd->oobblock; + buf = kmalloc (len, GFP_KERNEL); + if (!buf) { + printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n"); + er_stat = 1; /* if we can't check, assume failed */ + } else { + /* recovery read */ + /* page read */ + rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1); + if (rtn) { /* if read failed or > 1-bit error corrected */ + er_stat |= 1<<1; /* ECC read failed */ + } + kfree(buf); + } + } + } + + rtn = status; + if (er_stat == 0) { /* if ECC is available */ + rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */ + } + + return rtn; +} #endif + /* * Main initialization routine */ @@ -518,6 +593,8 @@ int __init rtc_from4_init (void) this->eccmode = NAND_ECC_HW8_512; this->options |= NAND_HWECC_SYNDROME; + /* return the status of extra status and ECC checks */ + this->errstat = rtc_from4_errstat; /* set the nand_oobinfo to support FPGA H/W error detection */ this->autooob = &rtc_from4_nand_oobinfo; this->enable_hwecc = rtc_from4_enable_hwecc; @@ -544,6 +621,13 @@ int __init rtc_from4_init (void) deplete(rtc_from4_mtd, i); } +#if RTC_FROM4_NO_VIRTBLOCKS + /* use a smaller erase block to minimize wasted space when a block is bad */ + /* note: this uses eight times as much RAM as using the default and makes */ + /* mounts take four times as long. */ + rtc_from4_mtd->flags |= MTD_NO_VIRTBLOCKS; +#endif + /* Register the partitions */ add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); -- cgit v1.2.3 From 6170b43401a3230756ff76287ee07db0d75eddde Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 24 Jan 2005 23:49:54 +0000 Subject: [MTD] Fix MTD device probing Try larger numbers of chips before smaller numbers of chips across the bus width. This means we'll avoid misdetecting a 2 x16 array as 1 x32 if the high 16-bits happen to read as zeros in the QRY area. Signed-off-by: Russell King Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/gen_probe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index fc982c4671f..dc065b22f79 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c @@ -2,7 +2,7 @@ * Routines common to all CFI-type probes. * (C) 2001-2003 Red Hat, Inc. * GPL'd - * $Id: gen_probe.c,v 1.21 2004/08/14 15:14:05 dwmw2 Exp $ + * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $ */ #include @@ -162,7 +162,7 @@ static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, int max_chips = map_bankwidth(map); /* And minimum 1 */ int nr_chips, type; - for (nr_chips = min_chips; nr_chips <= max_chips; nr_chips <<= 1) { + for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) { if (!cfi_interleave_supported(nr_chips)) continue; -- cgit v1.2.3 From 651078ba3a9225ab3fbef146359390ac498ff9fe Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 31 Jan 2005 20:36:46 +0000 Subject: [MTD] DiskOnChip use CONFIG_ options instead of random symbols Using the CONFIG_ options from KConfig seems to work better :8 Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/diskonchip.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 02135c3ac29..5a586707eed 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -16,7 +16,7 @@ * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $ + * $Id: diskonchip.c,v 1.46 2005/01/31 20:36:42 gleixner Exp $ */ #include @@ -35,13 +35,13 @@ #include /* Where to look for the devices? */ -#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS -#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0 +#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS +#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0 #endif static unsigned long __initdata doc_locations[] = { #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) -#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH +#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, @@ -123,7 +123,7 @@ static int inftl_bbt_write=0; #endif module_param(inftl_bbt_write, int, 0); -static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS; +static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS; module_param(doc_config_location, ulong, 0); MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip"); -- cgit v1.2.3 From 39605398cd45941b4ed2026c666a1a9f39c40490 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 31 Jan 2005 22:21:18 +0000 Subject: [MTD] DiskOnChip code cleanup Remove commented ugliness Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/diskonchip.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 5a586707eed..39224012030 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -16,7 +16,7 @@ * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.46 2005/01/31 20:36:42 gleixner Exp $ + * $Id: diskonchip.c,v 1.47 2005/01/31 22:21:15 gleixner Exp $ */ #include @@ -1122,8 +1122,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out; mh = (struct NFTLMediaHeader *) buf; -//#ifdef CONFIG_MTD_DEBUG_VERBOSE -// if (CONFIG_MTD_DEBUG_VERBOSE >= 2) printk(KERN_INFO " DataOrgID = %s\n" " NumEraseUnits = %d\n" " FirstPhysicalEUN = %d\n" @@ -1132,7 +1130,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, mh->DataOrgID, mh->NumEraseUnits, mh->FirstPhysicalEUN, mh->FormattedSize, mh->UnitSizeFactor); -//#endif blocks = mtd->size >> this->phys_erase_shift; maxblocks = min(32768U, mtd->erasesize - psize); @@ -1175,10 +1172,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, offs <<= this->page_shift; offs += mtd->erasesize; - //parts[0].name = " DiskOnChip Boot / Media Header partition"; - //parts[0].offset = 0; - //parts[0].size = offs; - parts[0].name = " DiskOnChip BDTL partition"; parts[0].offset = offs; parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift; @@ -1233,8 +1226,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, mh->FormatFlags = le32_to_cpu(mh->FormatFlags); mh->PercentUsed = le32_to_cpu(mh->PercentUsed); -//#ifdef CONFIG_MTD_DEBUG_VERBOSE -// if (CONFIG_MTD_DEBUG_VERBOSE >= 2) printk(KERN_INFO " bootRecordID = %s\n" " NoOfBootImageBlocks = %d\n" " NoOfBinaryPartitions = %d\n" @@ -1252,7 +1243,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, ((unsigned char *) &mh->OsakVersion)[2] & 0xf, ((unsigned char *) &mh->OsakVersion)[3] & 0xf, mh->PercentUsed); -//#endif vshift = this->phys_erase_shift + mh->BlockMultiplierBits; @@ -1278,8 +1268,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, ip->spareUnits = le32_to_cpu(ip->spareUnits); ip->Reserved0 = le32_to_cpu(ip->Reserved0); -//#ifdef CONFIG_MTD_DEBUG_VERBOSE -// if (CONFIG_MTD_DEBUG_VERBOSE >= 2) printk(KERN_INFO " PARTITION[%d] ->\n" " virtualUnits = %d\n" " firstUnit = %d\n" @@ -1289,16 +1277,15 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, i, ip->virtualUnits, ip->firstUnit, ip->lastUnit, ip->flags, ip->spareUnits); -//#endif -/* +#if 0 if ((i == 0) && (ip->firstUnit > 0)) { parts[0].name = " DiskOnChip IPL / Media Header partition"; parts[0].offset = 0; parts[0].size = mtd->erasesize * ip->firstUnit; numparts = 1; } -*/ +#endif if (ip->flags & INFTL_BINARY) parts[numparts].name = " DiskOnChip BDK partition"; -- cgit v1.2.3 From f29a4b86f554a496beba8d339917399b9c44fbc9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 31 Jan 2005 22:22:24 +0000 Subject: [MTD] DiskOnChip: big endian fix for NFTL devices Make NFTL devices work on big endian machines. Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/diskonchip.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 39224012030..d5927674f28 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -16,7 +16,7 @@ * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.47 2005/01/31 22:21:15 gleixner Exp $ + * $Id: diskonchip.c,v 1.48 2005/01/31 22:22:21 gleixner Exp $ */ #include @@ -1122,6 +1122,10 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out; mh = (struct NFTLMediaHeader *) buf; + mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits); + mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN); + mh->FormattedSize = le32_to_cpu(mh->FormattedSize); + printk(KERN_INFO " DataOrgID = %s\n" " NumEraseUnits = %d\n" " FirstPhysicalEUN = %d\n" -- cgit v1.2.3 From 322b12eb57db8cc598ccedfb85fcf2faded08473 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Fri, 4 Feb 2005 07:43:13 +0000 Subject: [MTD] amd_flash: Fix chip ID clash * Removed table entry for AM29BDS643D, since device ID clashes with AM29DL640G and both chips support CFI. Signed-off-by: Jonas Holmberg Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/amd_flash.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c index 41e2e3e3160..2dafeba3f3d 100644 --- a/drivers/mtd/chips/amd_flash.c +++ b/drivers/mtd/chips/amd_flash.c @@ -3,7 +3,7 @@ * * Author: Jonas Holmberg * - * $Id: amd_flash.c,v 1.26 2004/11/20 12:49:04 dwmw2 Exp $ + * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $ * * Copyright (c) 2001 Axis Communications AB * @@ -67,7 +67,6 @@ #define AM29LV160DT 0x22C4 #define AM29LV160DB 0x2249 #define AM29BDS323D 0x22D1 -#define AM29BDS643D 0x227E /* Atmel */ #define AT49xV16x 0x00C0 @@ -617,17 +616,6 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 }, { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 }, } - }, { - .mfr_id = MANUFACTURER_AMD, - .dev_id = AM29BDS643D, - .name = "AMD AM29BDS643D", - .size = 0x00800000, - .numeraseregions = 3, - .regions = { - { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 }, - { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 }, - { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 }, - } }, { .mfr_id = MANUFACTURER_ATMEL, .dev_id = AT49xV16x, -- cgit v1.2.3 From 72b56a2d7dccd9ea90f34f6ddb653086a3f3bd2e Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 5 Feb 2005 02:06:19 +0000 Subject: [MTD] Add OTP basisc add structure definition for OTP region info Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index c268bcd7172..c630d7532f7 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.164 2004/11/16 18:29:00 dwmw2 Exp $ + * $Id: cfi_cmdset_0001.c,v 1.165 2005/02/05 02:06:15 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -252,7 +252,8 @@ read_pri_intelext(struct map_info *map, __u16 adr) int nb_parts, i; /* Protection Register info */ - extra_size += (extp->NumProtectionFields - 1) * (4 + 6); + extra_size += (extp->NumProtectionFields - 1) * + sizeof(struct cfi_intelext_otpinfo); /* Burst Read info */ extra_size += 6; @@ -471,7 +472,8 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, int offs, numregions, numparts, partshift, numvirtchips, i, j; /* Protection Register info */ - offs = (extp->NumProtectionFields - 1) * (4 + 6); + offs = (extp->NumProtectionFields - 1) * + sizeof(struct cfi_intelext_otpinfo); /* Burst Read info */ offs += 6; -- cgit v1.2.3 From f77814dd5728edaf1239d19755d2aa0d8c33d861 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 8 Feb 2005 17:11:19 +0000 Subject: [MTD] Support for protection register support on Intel FLASH chips This enables support for reading, writing and locking so called "Protection Registers" present on some flash chips. A subset of them are pre-programmed at the factory with a unique set of values. The rest is user-programmable. Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/Kconfig | 27 ++- drivers/mtd/chips/cfi_cmdset_0001.c | 401 +++++++++++++++++++++++++----------- drivers/mtd/mtdpart.c | 28 ++- 3 files changed, 339 insertions(+), 117 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index d682dbc8157..f4eda1e40d5 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/chips/Kconfig -# $Id: Kconfig,v 1.13 2004/12/01 15:49:10 nico Exp $ +# $Id: Kconfig,v 1.14 2005/02/08 17:11:15 nico Exp $ menu "RAM/ROM/Flash chip drivers" depends on MTD!=n @@ -155,6 +155,31 @@ config MTD_CFI_I8 If your flash chips are interleaved in eights - i.e. you have eight flash chips addressed by each bus cycle, then say 'Y'. +config MTD_OTP + bool "Protection Registers aka one-time programmable (OTP) bits" + depends on MTD_CFI_ADV_OPTIONS + default n + help + This enables support for reading, writing and locking so called + "Protection Registers" present on some flash chips. + A subset of them are pre-programmed at the factory with a + unique set of values. The rest is user-programmable. + + The user-programmable Protection Registers contain one-time + programmable (OTP) bits; when programmed, register bits cannot be + erased. Each Protection Register can be accessed multiple times to + program individual bits, as long as the register remains unlocked. + + Each Protection Register has an associated Lock Register bit. When a + Lock Register bit is programmed, the associated Protection Register + can only be read; it can no longer be programmed. Additionally, + because the Lock Register bits themselves are OTP, when programmed, + Lock Register bits cannot be erased. Therefore, when a Protection + Register is locked, it cannot be unlocked. + + This feature should therefore be used with extreme care. Any mistake + in the programming of OTP bits will waste them. + config MTD_CFI_INTELEXT tristate "Support for Intel/Sharp flash chips" depends on MTD_GEN_PROBE diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index c630d7532f7..b3f5acf0760 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.165 2005/02/05 02:06:15 nico Exp $ + * $Id: cfi_cmdset_0001.c,v 1.167 2005/02/08 17:11:15 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -48,14 +48,20 @@ #define M50LPW080 0x002F static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); -//static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); -//static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); static void cfi_intelext_sync (struct mtd_info *); static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t); +static int cfi_intelext_get_fact_prot_info (struct mtd_info *, + struct otp_info *, size_t); +static int cfi_intelext_get_user_prot_info (struct mtd_info *, + struct otp_info *, size_t); static int cfi_intelext_suspend (struct mtd_info *); static void cfi_intelext_resume (struct mtd_info *); @@ -423,9 +429,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) mtd->eraseregions[i].numblocks); } -#if 0 - mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg; +#ifdef CONFIG_MTD_OTP mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg; + mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg; + mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg; + mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg; + mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info; + mtd->get_user_prot_info = cfi_intelext_get_user_prot_info; #endif /* This function has the potential to distort the reality @@ -565,7 +575,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr resettime: timeo = jiffies + HZ; retry: - if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)) { + if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) { /* * OK. We have possibility for contension on the write/erase * operations which are global to the real chip and not per @@ -1178,111 +1188,11 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz return ret; } -#if 0 -static int __xipram cfi_intelext_read_prot_reg (struct mtd_info *mtd, - loff_t from, size_t len, - size_t *retlen, - u_char *buf, - int base_offst, int reg_sz) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp = cfi->cmdset_priv; - struct flchip *chip; - int ofs_factor = cfi->interleave * cfi->device_type; - int count = len; - int chip_num, offst; - int ret; - - chip_num = ((unsigned int)from/reg_sz); - offst = from - (reg_sz*chip_num)+base_offst; - - while (count) { - /* Calculate which chip & protection register offset we need */ - - if (chip_num >= cfi->numchips) - goto out; - - chip = &cfi->chips[chip_num]; - - spin_lock(chip->mutex); - ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY); - if (ret) { - spin_unlock(chip->mutex); - return (len-count)?:ret; - } - - xip_disable(map, chip, chip->start); - - if (chip->state != FL_JEDEC_QUERY) { - map_write(map, CMD(0x90), chip->start); - chip->state = FL_JEDEC_QUERY; - } - - while (count && ((offst-base_offst) < reg_sz)) { - *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst)); - buf++; - offst++; - count--; - } - - xip_enable(map, chip, chip->start); - put_chip(map, chip, chip->start); - spin_unlock(chip->mutex); - - /* Move on to the next chip */ - chip_num++; - offst = base_offst; - } - - out: - return len-count; -} - -static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp=cfi->cmdset_priv; - int base_offst,reg_sz; - - /* Check that we actually have some protection registers */ - if(!extp || !(extp->FeatureSupport&64)){ - printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); - return 0; - } - - base_offst=(1<FactProtRegSize); - reg_sz=(1<UserProtRegSize); - - return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz); -} - -static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp=cfi->cmdset_priv; - int base_offst,reg_sz; - - /* Check that we actually have some protection registers */ - if(!extp || !(extp->FeatureSupport&64)){ - printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); - return 0; - } - - base_offst=0; - reg_sz=(1<FactProtRegSize); - - return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz); -} -#endif - static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, - unsigned long adr, map_word datum) + unsigned long adr, map_word datum, int mode) { struct cfi_private *cfi = map->fldrv_priv; - map_word status, status_OK; + map_word status, status_OK, write_cmd; unsigned long timeo; int z, ret=0; @@ -1290,9 +1200,14 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); + switch (mode) { + case FL_WRITING: write_cmd = CMD(0x40); break; + case FL_OTP_WRITE: write_cmd = CMD(0xc0); break; + default: return -EINVAL; + } spin_lock(chip->mutex); - ret = get_chip(map, chip, adr, FL_WRITING); + ret = get_chip(map, chip, adr, mode); if (ret) { spin_unlock(chip->mutex); return ret; @@ -1301,9 +1216,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map)); ENABLE_VPP(map); xip_disable(map, chip, adr); - map_write(map, CMD(0x40), adr); + map_write(map, write_cmd, adr); map_write(map, datum, adr); - chip->state = FL_WRITING; + chip->state = mode; spin_unlock(chip->mutex); INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map)); @@ -1313,7 +1228,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, timeo = jiffies + (HZ/2); z = 0; for (;;) { - if (chip->state != FL_WRITING) { + if (chip->state != mode) { /* Someone's suspended the write. Sleep */ DECLARE_WAITQUEUE(wait, current); @@ -1401,7 +1316,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le datum = map_word_load_partial(map, datum, buf, gap, n); ret = do_write_oneword(map, &cfi->chips[chipnum], - bus_ofs, datum); + bus_ofs, datum, FL_WRITING); if (ret) return ret; @@ -1422,7 +1337,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le map_word datum = map_word_load(map, buf); ret = do_write_oneword(map, &cfi->chips[chipnum], - ofs, datum); + ofs, datum, FL_WRITING); if (ret) return ret; @@ -1446,7 +1361,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le datum = map_word_load_partial(map, datum, buf, 0, len); ret = do_write_oneword(map, &cfi->chips[chipnum], - ofs, datum); + ofs, datum, FL_WRITING); if (ret) return ret; @@ -2036,6 +1951,262 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) return ret; } +#ifdef CONFIG_MTD_OTP + +typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, + u_long data_offset, u_char *buf, u_int size, + u_long prot_offset, u_int groupno, u_int groupsize); + +static int __xipram +do_otp_read(struct map_info *map, struct flchip *chip, u_long offset, + u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz) +{ + struct cfi_private *cfi = map->fldrv_priv; + int ret; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + + /* let's ensure we're not reading back cached data from array mode */ + if (map->inval_cache) + map->inval_cache(map, chip->start + offset, size); + + xip_disable(map, chip, chip->start); + if (chip->state != FL_JEDEC_QUERY) { + map_write(map, CMD(0x90), chip->start); + chip->state = FL_JEDEC_QUERY; + } + map_copy_from(map, buf, chip->start + offset, size); + xip_enable(map, chip, chip->start); + + /* then ensure we don't keep OTP data in the cache */ + if (map->inval_cache) + map->inval_cache(map, chip->start + offset, size); + + put_chip(map, chip, chip->start); + spin_unlock(chip->mutex); + return 0; +} + +static int +do_otp_write(struct map_info *map, struct flchip *chip, u_long offset, + u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz) +{ + int ret; + + while (size) { + unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1); + int gap = offset - bus_ofs; + int n = min_t(int, size, map_bankwidth(map)-gap); + map_word datum = map_word_ff(map); + + datum = map_word_load_partial(map, datum, buf, gap, n); + ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE); + if (ret) + return ret; + + offset += n; + buf += n; + size -= n; + } + + return 0; +} + +static int +do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset, + u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz) +{ + struct cfi_private *cfi = map->fldrv_priv; + map_word datum; + + /* make sure area matches group boundaries */ + if (offset != 0 || size != grpsz) + return -EXDEV; + + datum = map_word_ff(map); + datum = map_word_clr(map, datum, CMD(1 << grpno)); + return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE); +} + +static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, + otp_op_t action, int user_regs) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + struct cfi_pri_intelext *extp = cfi->cmdset_priv; + struct flchip *chip; + struct cfi_intelext_otpinfo *otp; + u_long devsize, reg_prot_offset, data_offset; + u_int chip_num, chip_step, field, reg_fact_size, reg_user_size; + u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups; + int ret; + + *retlen = 0; + + /* Check that we actually have some OTP registers */ + if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields) + return -ENODATA; + + /* we need real chips here not virtual ones */ + devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave; + chip_step = devsize >> cfi->chipshift; + + for (chip_num = 0; chip_num < cfi->numchips; chip_num += chip_step) { + chip = &cfi->chips[chip_num]; + otp = (struct cfi_intelext_otpinfo *)&extp->extra[0]; + + /* first OTP region */ + field = 0; + reg_prot_offset = extp->ProtRegAddr; + reg_fact_groups = 1; + reg_fact_size = 1 << extp->FactProtRegSize; + reg_user_groups = 1; + reg_user_size = 1 << extp->UserProtRegSize; + + while (len > 0) { + /* flash geometry fixup */ + data_offset = reg_prot_offset + 1; + data_offset *= cfi->interleave * cfi->device_type; + reg_prot_offset *= cfi->interleave * cfi->device_type; + reg_fact_size *= cfi->interleave; + reg_user_size *= cfi->interleave; + + if (user_regs) { + groups = reg_user_groups; + groupsize = reg_user_size; + /* skip over factory reg area */ + groupno = reg_fact_groups; + data_offset += reg_fact_groups * reg_fact_size; + } else { + groups = reg_fact_groups; + groupsize = reg_fact_size; + groupno = 0; + } + + while (groups > 0) { + if (!action) { + /* + * Special case: if action is NULL + * we fill buf with otp_info records. + */ + struct otp_info *otpinfo; + map_word lockword; + len -= sizeof(struct otp_info); + if (len <= 0) + return -ENOSPC; + ret = do_otp_read(map, chip, + reg_prot_offset, + (u_char *)&lockword, + map_bankwidth(map), + 0, 0, 0); + if (ret) + return ret; + otpinfo = (struct otp_info *)buf; + otpinfo->start = from; + otpinfo->length = groupsize; + otpinfo->locked = + !map_word_bitsset(map, lockword, + CMD(1 << groupno)); + from += groupsize; + buf += sizeof(*otpinfo); + *retlen += sizeof(*otpinfo); + } else if (from >= groupsize) { + from -= groupsize; + } else { + int size = groupsize; + data_offset += from; + size -= from; + from = 0; + if (size > len) + size = len; + ret = action(map, chip, data_offset, + buf, size, reg_prot_offset, + groupno, groupsize); + if (ret < 0) + return ret; + buf += size; + len -= size; + *retlen += size; + } + groupno++; + groups--; + } + + /* next OTP region */ + if (++field == extp->NumProtectionFields) + break; + reg_prot_offset = otp->ProtRegAddr; + reg_fact_groups = otp->FactGroups; + reg_fact_size = 1 << otp->FactProtRegSize; + reg_user_groups = otp->UserGroups; + reg_user_size = 1 << otp->UserProtRegSize; + otp++; + } + } + + return 0; +} + +static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, + u_char *buf) +{ + return cfi_intelext_otp_walk(mtd, from, len, retlen, + buf, do_otp_read, 0); +} + +static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, + u_char *buf) +{ + return cfi_intelext_otp_walk(mtd, from, len, retlen, + buf, do_otp_read, 1); +} + +static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, + u_char *buf) +{ + return cfi_intelext_otp_walk(mtd, from, len, retlen, + buf, do_otp_write, 1); +} + +static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd, + loff_t from, size_t len) +{ + size_t retlen; + return cfi_intelext_otp_walk(mtd, from, len, &retlen, + NULL, do_otp_lock, 1); +} + +static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + size_t retlen; + int ret; + + ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0); + return ret ? : retlen; +} + +static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + size_t retlen; + int ret; + + ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1); + return ret ? : retlen; +} + +#endif + static int cfi_intelext_suspend(struct mtd_info *mtd) { struct map_info *map = mtd->priv; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 96ebb52f24b..b92e6bfffaf 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: mtdpart.c,v 1.51 2004/11/16 18:28:59 dwmw2 Exp $ + * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $ * * 02-21-2002 Thomas Gleixner * added support for read_oob, write_oob @@ -116,6 +116,13 @@ static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t le len, retlen, buf); } +static int part_get_user_prot_info (struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->get_user_prot_info (part->master, buf, len); +} + static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -124,6 +131,13 @@ static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t le len, retlen, buf); } +static int part_get_fact_prot_info (struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->get_fact_prot_info (part->master, buf, len); +} + static int part_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { @@ -182,6 +196,12 @@ static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t l len, retlen, buf); } +static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->lock_user_prot_reg (part->master, from, len); +} + static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen) { @@ -409,6 +429,12 @@ int add_mtd_partitions(struct mtd_info *master, slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; if(master->write_user_prot_reg) slave->mtd.write_user_prot_reg = part_write_user_prot_reg; + if(master->lock_user_prot_reg) + slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; + if(master->get_user_prot_info) + slave->mtd.get_user_prot_info = part_get_user_prot_info; + if(master->get_fact_prot_info) + slave->mtd.get_fact_prot_info = part_get_fact_prot_info; if (master->sync) slave->mtd.sync = part_sync; if (!i && master->suspend && master->resume) { -- cgit v1.2.3 From 31f4233baeaaeb7c563d2766781c6592ad259b6a Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 8 Feb 2005 17:45:55 +0000 Subject: [MTD] User interface to Protection Registers This is implemented using a ioctl to switch the MTD char device into one of the different OTP "modes", at which point read/write/seek can operate on the selected OTP area. Also some extra ioctls to query for size and lock protection segments or groups. Some example user space utilities are provided. Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/mtdchar.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 510ad78312c..6ea2d8058a4 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1,5 +1,5 @@ /* - * $Id: mtdchar.c,v 1.66 2005/01/05 18:05:11 dwmw2 Exp $ + * $Id: mtdchar.c,v 1.67 2005/02/08 17:45:51 nico Exp $ * * Character-device access to raw MTD devices. * @@ -59,6 +59,12 @@ static inline void mtdchar_devfs_exit(void) #define mtdchar_devfs_exit() do { } while(0) #endif + +/* Well... let's abuse the unused bits in file->f_mode for those */ +#define MTD_MODE_OTP_FACT 0x1000 +#define MTD_MODE_OTP_USER 0x2000 +#define MTD_MODE_MASK 0xf000 + static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) { struct mtd_info *mtd = file->private_data; @@ -105,6 +111,10 @@ static int mtd_open(struct inode *inode, struct file *file) if ((file->f_mode & 2) && (minor & 1)) return -EACCES; + /* make sure the locally abused bits are initialy clear */ + if (file->f_mode & MTD_MODE_MASK) + return -EWOULDBLOCK; + mtd = get_mtd_device(NULL, devnum); if (!mtd) @@ -178,7 +188,16 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t if (!kbuf) return -ENOMEM; - ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf); + switch (file->f_mode & MTD_MODE_MASK) { + case MTD_MODE_OTP_FACT: + ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); + break; + case MTD_MODE_OTP_USER: + ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); + break; + default: + ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf); + } /* Nand returns -EBADMSG on ecc errors, but it returns * the data. For our userspace tools it is important * to dump areas with ecc errors ! @@ -196,6 +215,8 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t count -= retlen; buf += retlen; + if (retlen == 0) + count = 0; } else { kfree(kbuf); @@ -245,7 +266,20 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count return -EFAULT; } - ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf); + switch (file->f_mode & MTD_MODE_MASK) { + case MTD_MODE_OTP_FACT: + ret = -EROFS; + break; + case MTD_MODE_OTP_USER: + if (!mtd->write_user_prot_reg) { + ret = -EOPNOTSUPP; + break; + } + ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); + break; + default: + ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf); + } if (!ret) { *ppos += retlen; total_retlen += retlen; @@ -518,6 +552,79 @@ static int mtd_ioctl(struct inode *inode, struct file *file, break; } +#ifdef CONFIG_MTD_OTP + case OTPSELECT: + { + int mode; + if (copy_from_user(&mode, argp, sizeof(int))) + return -EFAULT; + file->f_mode &= ~MTD_MODE_MASK; + switch (mode) { + case MTD_OTP_FACTORY: + if (!mtd->read_fact_prot_reg) + ret = -EOPNOTSUPP; + else + file->f_mode |= MTD_MODE_OTP_FACT; + break; + case MTD_OTP_USER: + if (!mtd->read_fact_prot_reg) + ret = -EOPNOTSUPP; + else + file->f_mode |= MTD_MODE_OTP_USER; + break; + default: + ret = -EINVAL; + case MTD_OTP_OFF: + break; + } + break; + } + + case OTPGETREGIONCOUNT: + case OTPGETREGIONINFO: + { + struct otp_info *buf = kmalloc(4096, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = -EOPNOTSUPP; + switch (file->f_mode & MTD_MODE_MASK) { + case MTD_MODE_OTP_FACT: + if (mtd->get_fact_prot_info) + ret = mtd->get_fact_prot_info(mtd, buf, 4096); + break; + case MTD_MODE_OTP_USER: + if (mtd->get_user_prot_info) + ret = mtd->get_user_prot_info(mtd, buf, 4096); + break; + } + if (ret >= 0) { + if (cmd == OTPGETREGIONCOUNT) { + int nbr = ret / sizeof(struct otp_info); + ret = copy_to_user(argp, &nbr, sizeof(int)); + } else + ret = copy_to_user(argp, buf, ret); + if (ret) + ret = -EFAULT; + } + kfree(buf); + break; + } + + case OTPLOCK: + { + struct otp_info info; + + if ((file->f_mode & MTD_MODE_MASK) != MTD_MODE_OTP_USER) + return -EINVAL; + if (copy_from_user(&info, argp, sizeof(info))) + return -EFAULT; + if (!mtd->lock_user_prot_reg) + return -EOPNOTSUPP; + ret = mtd->lock_user_prot_reg(mtd, info.start, info.length); + break; + } +#endif + default: ret = -ENOTTY; } -- cgit v1.2.3 From 045e9a5d51ced27bfcbdb78071534ce6fd36b33d Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 8 Feb 2005 19:12:53 +0000 Subject: [MTD] Unabuse file-f_mode for OTP purpose Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/mtdchar.c | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 6ea2d8058a4..548b89204aa 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1,5 +1,5 @@ /* - * $Id: mtdchar.c,v 1.67 2005/02/08 17:45:51 nico Exp $ + * $Id: mtdchar.c,v 1.68 2005/02/08 19:12:50 nico Exp $ * * Character-device access to raw MTD devices. * @@ -59,15 +59,25 @@ static inline void mtdchar_devfs_exit(void) #define mtdchar_devfs_exit() do { } while(0) #endif +/* + * We use file->private_data to store a pointer to the MTDdevice. + * Since alighment is at least 32 bits, we have 2 bits free for OTP + * modes as well. + */ + +#define TO_MTD(file) (struct mtd_info *)((long)((file)->private_data) & ~3L) -/* Well... let's abuse the unused bits in file->f_mode for those */ -#define MTD_MODE_OTP_FACT 0x1000 -#define MTD_MODE_OTP_USER 0x2000 -#define MTD_MODE_MASK 0xf000 +#define MTD_MODE_OTP_FACT 1 +#define MTD_MODE_OTP_USER 2 +#define MTD_MODE(file) ((long)((file)->private_data) & 3) + +#define SET_MTD_MODE(file, mode) \ + do { long __p = (long)((file)->private_data); \ + (file)->private_data = (void *)((__p & ~3L) | mode); } while (0) static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) { - struct mtd_info *mtd = file->private_data; + struct mtd_info *mtd = TO_MTD(file); switch (orig) { case 0: @@ -111,10 +121,6 @@ static int mtd_open(struct inode *inode, struct file *file) if ((file->f_mode & 2) && (minor & 1)) return -EACCES; - /* make sure the locally abused bits are initialy clear */ - if (file->f_mode & MTD_MODE_MASK) - return -EWOULDBLOCK; - mtd = get_mtd_device(NULL, devnum); if (!mtd) @@ -144,7 +150,7 @@ static int mtd_close(struct inode *inode, struct file *file) DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); - mtd = file->private_data; + mtd = TO_MTD(file); if (mtd->sync) mtd->sync(mtd); @@ -161,7 +167,7 @@ static int mtd_close(struct inode *inode, struct file *file) static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos) { - struct mtd_info *mtd = file->private_data; + struct mtd_info *mtd = TO_MTD(file); size_t retlen=0; size_t total_retlen=0; int ret=0; @@ -188,7 +194,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t if (!kbuf) return -ENOMEM; - switch (file->f_mode & MTD_MODE_MASK) { + switch (MTD_MODE(file)) { case MTD_MODE_OTP_FACT: ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); break; @@ -231,7 +237,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos) { - struct mtd_info *mtd = file->private_data; + struct mtd_info *mtd = TO_MTD(file); char *kbuf; size_t retlen; size_t total_retlen=0; @@ -266,7 +272,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count return -EFAULT; } - switch (file->f_mode & MTD_MODE_MASK) { + switch (MTD_MODE(file)) { case MTD_MODE_OTP_FACT: ret = -EROFS; break; @@ -310,7 +316,7 @@ static void mtdchar_erase_callback (struct erase_info *instr) static int mtd_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) { - struct mtd_info *mtd = file->private_data; + struct mtd_info *mtd = TO_MTD(file); void __user *argp = (void __user *)arg; int ret = 0; u_long size; @@ -558,19 +564,19 @@ static int mtd_ioctl(struct inode *inode, struct file *file, int mode; if (copy_from_user(&mode, argp, sizeof(int))) return -EFAULT; - file->f_mode &= ~MTD_MODE_MASK; + SET_MTD_MODE(file, 0); switch (mode) { case MTD_OTP_FACTORY: if (!mtd->read_fact_prot_reg) ret = -EOPNOTSUPP; else - file->f_mode |= MTD_MODE_OTP_FACT; + SET_MTD_MODE(file, MTD_MODE_OTP_FACT); break; case MTD_OTP_USER: if (!mtd->read_fact_prot_reg) ret = -EOPNOTSUPP; else - file->f_mode |= MTD_MODE_OTP_USER; + SET_MTD_MODE(file, MTD_MODE_OTP_USER); break; default: ret = -EINVAL; @@ -587,7 +593,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, if (!buf) return -ENOMEM; ret = -EOPNOTSUPP; - switch (file->f_mode & MTD_MODE_MASK) { + switch (MTD_MODE(file)) { case MTD_MODE_OTP_FACT: if (mtd->get_fact_prot_info) ret = mtd->get_fact_prot_info(mtd, buf, 4096); @@ -614,7 +620,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, { struct otp_info info; - if ((file->f_mode & MTD_MODE_MASK) != MTD_MODE_OTP_USER) + if (MTD_MODE(file) != MTD_MODE_OTP_USER) return -EINVAL; if (copy_from_user(&info, argp, sizeof(info))) return -EFAULT; -- cgit v1.2.3 From 0040bf382c77414739c933e4d2ee35ff817d0b99 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 9 Feb 2005 12:20:00 +0000 Subject: [MTD] NAND: Skip bad block table scan on request Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 7094dd5716d..99abd615a46 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.130 2005/01/24 03:07:43 dmarlin Exp $ + * $Id: nand_base.c,v 1.131 2005/02/09 12:19:56 gleixner Exp $ * * 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 @@ -2631,6 +2631,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips) memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); mtd->owner = THIS_MODULE; + + /* Check, if we should skip the bad block table scan */ + if (this->options & NAND_SKIP_BBTSCAN) + return 0; /* Build bad block table */ return this->scan_bbt (mtd); -- cgit v1.2.3 From 41ce921440bd14d9b69b19fbf47d9278582739fe Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Wed, 9 Feb 2005 14:50:00 +0000 Subject: [MTD] NAND: Allow operation without bad block table Small bugfix. Sometimes it may be handy not to have bbt. So, this->bbt might be NULL. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 99abd615a46..1806ffae245 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.131 2005/02/09 12:19:56 gleixner Exp $ + * $Id: nand_base.c,v 1.132 2005/02/09 14:49:56 dedekind Exp $ * * 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 @@ -461,7 +461,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /* Get block number */ block = ((int) ofs) >> this->bbt_erase_shift; - this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); + if (this->bbt) + this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); /* Do we have a flash based bad block table ? */ if (this->options & NAND_USE_FLASH_BBT) -- cgit v1.2.3 From eeada24da8bd23fcf6acd2729be054ea99b301bb Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Fri, 11 Feb 2005 10:14:15 +0000 Subject: [MTD] NAND: Read only OOB bytes during bad block scan When scanning NAND for bad blocks, don't read the whole page, read only needed OOB bytes instead. Also check the return code of the nand_read_raw() function. Correctly free the this->bbt array in case of failure. Tested with Large page NAND. Fix debugging message. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_bbt.c | 52 +++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 9a1949751c1..5ff6eba8bec 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -6,7 +6,7 @@ * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $ + * $Id: nand_bbt.c,v 1.30 2005/02/11 10:14:12 dedekind Exp $ * * 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 @@ -252,10 +252,10 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de * Create a bad block table by scanning the device * for the given good/bad block identify pattern */ -static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) +static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) { struct nand_chip *this = mtd->priv; - int i, j, numblocks, len, scanlen; + int i, j, numblocks, len, scanlen, pagelen; int startblock; loff_t from; size_t readlen, ooblen; @@ -270,9 +270,18 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc else len = 1; } - scanlen = mtd->oobblock + mtd->oobsize; - readlen = len * mtd->oobblock; - ooblen = len * mtd->oobsize; + + if (bd->options == 0) { + /* Memory-based BBT. We may read only needed bytes from the OOB area to + * test if block is bad, no need to read the whole page content. */ + scanlen = ooblen = pagelen = 0; + readlen = bd->len; + } else { + scanlen = mtd->oobblock + mtd->oobsize; + readlen = len * mtd->oobblock; + ooblen = len * mtd->oobsize; + pagelen = mtd->oobblock; + } if (chip == -1) { /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it @@ -284,7 +293,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc if (chip >= this->numchips) { printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", chip + 1, this->numchips); - return; + return -EINVAL; } numblocks = this->chipsize >> (this->bbt_erase_shift - 1); startblock = chip * numblocks; @@ -293,9 +302,18 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } for (i = startblock; i < numblocks;) { - nand_read_raw (mtd, buf, from, readlen, ooblen); + int ret; + + if (bd->options == 0) { + size_t retlen; + if ((ret = mtd->read_oob(mtd, from + bd->offs, bd->len, &retlen, &buf[bd->offs]))) + return ret; + } else { + if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) + return ret; + } for (j = 0; j < len; j++) { - if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { + if (check_pattern (&buf[j * scanlen], scanlen, pagelen, bd)) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", i >> 1, (unsigned int) from); @@ -305,6 +323,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc i += 2; from += (1 << this->bbt_erase_shift); } + return 0; } /** @@ -595,8 +614,7 @@ static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) /* Ensure that we only scan for the pattern and nothing else */ bd->options = 0; - create_bbt (mtd, this->data_buf, bd, -1); - return 0; + return create_bbt (mtd, this->data_buf, bd, -1); } /** @@ -808,8 +826,14 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) /* If no primary table decriptor is given, scan the device * to build a memory based bad block table */ - if (!td) - return nand_memory_bbt(mtd, bd); + if (!td) { + if ((res = nand_memory_bbt(mtd, bd))) { + printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); + kfree (this->bbt); + this->bbt = NULL; + } + return res; + } /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); @@ -1042,7 +1066,7 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", - (unsigned int)offs, res, block >> 1); + (unsigned int)offs, block >> 1, res); switch ((int)res) { case 0x00: return 0; -- cgit v1.2.3 From 011b2a36278cca110c70506ad85b042c2faabac2 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 14 Feb 2005 16:27:38 +0000 Subject: [MTD] Fixup probing logic for single 16bit devices The change to the generic probe to look for the smallest width of chip first is causing some problems on boards with a single 16bit device. The problem seems to be the jedec_match() is truncating the device-id read from the table to match against the one read from the hardware, causing a match against the partial id of some chips with 16bit IDs (such as the SST39LF160) This fixes things for my own board, but something may need to be done if the same problem is exhibited for chips with an 8bit ID Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/jedec_probe.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 30325a25ab9..c2ef821b7af 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1,7 +1,7 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $ + $Id: jedec_probe.c,v 1.62 2005/02/14 16:27:34 bjd Exp $ See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) for the standard this probe goes back to. @@ -1856,6 +1856,16 @@ static inline int jedec_match( __u32 base, case CFI_DEVICETYPE_X8: mfr = (__u8)finfo->mfr_id; id = (__u8)finfo->dev_id; + + /* bjd: it seems that if we do this, we can end up + * detecting 16bit flashes as an 8bit device, even though + * there aren't. + */ + if (finfo->dev_id > 0xff) { + DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n", + __func__); + goto match_done; + } break; case CFI_DEVICETYPE_X16: mfr = (__u16)finfo->mfr_id; -- cgit v1.2.3 From 88ec7c50bfeb5447d96fba55021bec2a274ea021 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 14 Feb 2005 16:30:35 +0000 Subject: [MTD] Add SST 39VF1601 (MPF+) ID Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/jedec_probe.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index c2ef821b7af..30da428eb7b 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1,7 +1,7 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: jedec_probe.c,v 1.62 2005/02/14 16:27:34 bjd Exp $ + $Id: jedec_probe.c,v 1.63 2005/02/14 16:30:32 bjd Exp $ See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) for the standard this probe goes back to. @@ -142,6 +142,7 @@ #define SST29LE512 0x003d #define SST39LF800 0x2781 #define SST39LF160 0x2782 +#define SST39VF1601 0x234b #define SST39LF512 0x00D4 #define SST39LF010 0x00D5 #define SST39LF020 0x00D6 @@ -1448,6 +1449,21 @@ static const struct amd_flash_info jedec_table[] = { ERASEINFO(0x1000,256), ERASEINFO(0x1000,256) } + }, { + .mfr_id = MANUFACTURER_SST, /* should be CFI */ + .dev_id = SST39VF1601, + .name = "SST 39VF1601", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ + [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x1000,256), + ERASEINFO(0x1000,256) + } }, { .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ -- cgit v1.2.3 From 0ea4a7558f3c5b894e46da4b2be120edf002a86d Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Wed, 16 Feb 2005 09:39:39 +0000 Subject: [MTD] NAND: Early Manufacturer ID lookup Move manufacturer ID search to display correct ID in case of buswidth mismatch. Signed-off-by: Kyungmin Park Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 19 ++++++++++--------- drivers/mtd/nand/nand_ids.c | 4 +--- 2 files changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1806ffae245..acd5ec193ff 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.132 2005/02/09 14:49:56 dedekind Exp $ + * $Id: nand_base.c,v 1.133 2005/02/16 09:39:35 gleixner Exp $ * * 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 @@ -2276,7 +2276,7 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) */ int nand_scan (struct mtd_info *mtd, int maxchips) { - int i, j, nand_maf_id, nand_dev_id, busw; + int i, j, nand_maf_id, nand_dev_id, busw, maf_id; struct nand_chip *this = mtd->priv; /* Get buswidth to select the correct functions*/ @@ -2364,12 +2364,18 @@ int nand_scan (struct mtd_info *mtd, int maxchips) busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; } + /* Try to identify manufacturer */ + for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) { + if (nand_manuf_ids[maf_id].id == nand_maf_id) + break; + } + /* Check, if buswidth is correct. Hardware drivers should set * this correct ! */ if (busw != (this->options & NAND_BUSWIDTH_16)) { printk (KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, - nand_manuf_ids[i].name , mtd->name); + nand_manuf_ids[maf_id].name , mtd->name); printk (KERN_WARNING "NAND bus width %d instead %d bit\n", (this->options & NAND_BUSWIDTH_16) ? 16 : 8, @@ -2408,14 +2414,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (mtd->oobblock > 512 && this->cmdfunc == nand_command) this->cmdfunc = nand_command_lp; - /* Try to identify manufacturer */ - for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { - if (nand_manuf_ids[j].id == nand_maf_id) - break; - } printk (KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, - nand_manuf_ids[j].name , nand_flash_ids[i].name); + nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); break; } diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 9756797c92f..79945e6ce2b 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -3,7 +3,7 @@ * * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_ids.c,v 1.11 2005/01/17 18:26:27 dmarlin Exp $ + * $Id: nand_ids.c,v 1.12 2005/02/16 09:33:27 gleixner Exp $ * * 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 @@ -62,8 +62,6 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, - {"NAND 512MiB 3,3V 8-bit", 0xDC, 512, 512, 0x4000, 0}, - /* These are the new chips with large page size. The pagesize * and the erasesize is determined from the extended id bytes */ -- cgit v1.2.3 From 171650af9cd847964cf69b6bab9009631283293f Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Wed, 16 Feb 2005 17:09:39 +0000 Subject: [MTD] NAND: Fix bad block table scan for small page devices Scan 1st and 2nd pages of SP devices for BB marker by default. Fix more then one page scanning in create_bbt.c. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_bbt.c | 59 +++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 5ff6eba8bec..c85c69dec54 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -6,7 +6,7 @@ * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_bbt.c,v 1.30 2005/02/11 10:14:12 dedekind Exp $ + * $Id: nand_bbt.c,v 1.31 2005/02/16 17:09:36 dedekind Exp $ * * 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 @@ -77,17 +77,17 @@ */ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) { - int i, end; + int i, end = 0; uint8_t *p = buf; - end = paglen + td->offs; if (td->options & NAND_BBT_SCANEMPTY) { + end = paglen + td->offs; for (i = 0; i < end; i++) { if (p[i] != 0xff) return -1; } + p += end; } - p += end; /* Compare the pattern */ for (i = 0; i < td->len; i++) { @@ -95,9 +95,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des return -1; } - p += td->len; - end += td->len; if (td->options & NAND_BBT_SCANEMPTY) { + p += td->len; + end += td->len; for (i = end; i < len; i++) { if (*p++ != 0xff) return -1; @@ -255,7 +255,7 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) { struct nand_chip *this = mtd->priv; - int i, j, numblocks, len, scanlen, pagelen; + int i, j, numblocks, len, scanlen; int startblock; loff_t from; size_t readlen, ooblen; @@ -270,17 +270,16 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr else len = 1; } - - if (bd->options == 0) { - /* Memory-based BBT. We may read only needed bytes from the OOB area to - * test if block is bad, no need to read the whole page content. */ - scanlen = ooblen = pagelen = 0; + + if (!(bd->options & NAND_BBT_SCANEMPTY)) { + /* We need only read few bytes from the OOB area */ + scanlen = ooblen = 0; readlen = bd->len; } else { + /* Full page content should be read */ scanlen = mtd->oobblock + mtd->oobsize; readlen = len * mtd->oobblock; ooblen = len * mtd->oobsize; - pagelen = mtd->oobblock; } if (chip == -1) { @@ -293,7 +292,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr if (chip >= this->numchips) { printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", chip + 1, this->numchips); - return -EINVAL; + return -EINVAL; } numblocks = this->chipsize >> (this->bbt_erase_shift - 1); startblock = chip * numblocks; @@ -304,16 +303,21 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr for (i = startblock; i < numblocks;) { int ret; - if (bd->options == 0) { - size_t retlen; - if ((ret = mtd->read_oob(mtd, from + bd->offs, bd->len, &retlen, &buf[bd->offs]))) - return ret; - } else { + if (bd->options & NAND_BBT_SCANEMPTY) if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) return ret; - } + for (j = 0; j < len; j++) { - if (check_pattern (&buf[j * scanlen], scanlen, pagelen, bd)) { + if (!(bd->options & NAND_BBT_SCANEMPTY)) { + size_t retlen; + + /* No need to read pages fully, just read required OOB bytes */ + ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs, + readlen, &retlen, &buf[0]); + if (ret) + return ret; + } + if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", i >> 1, (unsigned int) from); @@ -323,6 +327,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr i += 2; from += (1 << this->bbt_erase_shift); } + return 0; } @@ -608,12 +613,11 @@ write: * The function creates a memory based bbt by scanning the device * for manufacturer / software marked good / bad blocks */ -static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) +static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; - /* Ensure that we only scan for the pattern and nothing else */ - bd->options = 0; + bd->options &= ~NAND_BBT_SCANEMPTY; return create_bbt (mtd, this->data_buf, bd, -1); } @@ -928,14 +932,11 @@ out: } /* Define some generic bad / good block scan pattern which are used - * while scanning a device for factory marked good / bad blocks - * - * The memory based patterns just - */ + * while scanning a device for factory marked good / bad blocks. */ static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; static struct nand_bbt_descr smallpage_memorybased = { - .options = 0, + .options = NAND_BBT_SCAN2NDPAGE, .offs = 5, .len = 1, .pattern = scan_ff_pattern -- cgit v1.2.3 From 332d71f7682d860b4439e197bc0ae85867458e1b Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 17 Feb 2005 20:35:04 +0000 Subject: [MTD] Make OTP actually work. The OTP code is rather broken without this. Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index b3f5acf0760..f018ea16217 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.167 2005/02/08 17:11:15 nico Exp $ + * $Id: cfi_cmdset_0001.c,v 1.168 2005/02/17 20:34:59 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -2025,7 +2025,7 @@ do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset, map_word datum; /* make sure area matches group boundaries */ - if (offset != 0 || size != grpsz) + if (size != grpsz) return -EXDEV; datum = map_word_ff(map); @@ -2089,7 +2089,7 @@ static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, groupno = 0; } - while (groups > 0) { + while (len > 0 && groups > 0) { if (!action) { /* * Special case: if action is NULL @@ -2118,6 +2118,7 @@ static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, *retlen += sizeof(*otpinfo); } else if (from >= groupsize) { from -= groupsize; + data_offset += groupsize; } else { int size = groupsize; data_offset += from; @@ -2133,6 +2134,7 @@ static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, buf += size; len -= size; *retlen += size; + data_offset += size; } groupno++; groups--; -- cgit v1.2.3 From 7685359656774e0348835f72a68e201fe0285fa9 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 18 Feb 2005 11:03:48 +0000 Subject: [MTD] Update BAST driver configuration update the BAST driver config (which already supports the vr1000) to be selected only if the vr1000 has been configured Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/Kconfig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 7d21d432f38..d29dc121c1f 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.43 2005/01/24 00:35:21 bjd Exp $ +# $Id: Kconfig,v 1.44 2005/02/18 11:03:45 bjd Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -637,13 +637,14 @@ config MTD_DMV182 Map driver for Dy-4 SVME/DMV-182 board. config MTD_BAST - tristate "Map driver for Simtec BAST (EB2410ITX)" - depends on ARCH_BAST + tristate "Map driver for Simtec BAST (EB2410ITX) or Thorcom VR1000" + depends on ARCH_BAST || MACH_VR1000 select MTD_PARTITIONS select MTD_MAP_BANK_WIDTH_16 select MTD_JEDECPROBE help - Map driver for NOR flash on the Simtec BAST (EB2410ITX). + Map driver for NOR flash on the Simtec BAST (EB2410ITX), or the + Thorcom VR1000 Note, this driver *cannot* over-ride the WP link on the board, or currently detect the state of the link. -- cgit v1.2.3 From 49450795844daba7867cc215f17532cac2c2b284 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Fri, 18 Feb 2005 14:34:54 +0000 Subject: [MTD] Fix unregister_mtd_user() public function documentation. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- drivers/mtd/mtdcore.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 9c0315d1b1c..dc86df18e94 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1,5 +1,5 @@ /* - * $Id: mtdcore.c,v 1.44 2004/11/16 18:28:59 dwmw2 Exp $ + * $Id: mtdcore.c,v 1.45 2005/02/18 14:34:50 dedekind Exp $ * * Core registration and callback routines for MTD * drivers and users. @@ -149,8 +149,8 @@ void register_mtd_user (struct mtd_notifier *new) } /** - * register_mtd_user - unregister a 'user' of MTD devices. - * @new: pointer to notifier info structure + * unregister_mtd_user - unregister a 'user' of MTD devices. + * @old: pointer to notifier info structure * * Removes a callback function pair from the list of 'users' to be * notified upon addition or removal of MTD devices. Causes the -- cgit v1.2.3 From fdf2fd52746bbffeffa19e24cb0608abc5429bc2 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 18 Feb 2005 14:46:15 +0000 Subject: [MTD] Sparse fixes Fix sparse errors due to lack of address-space markers Updated header comments Small re-format of initialiser Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/s3c2410.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index d05e9b97947..cb04b3c771e 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -1,7 +1,8 @@ /* linux/drivers/mtd/nand/s3c2410.c * * Copyright (c) 2004 Simtec Electronics - * Ben Dooks + * http://www.simtec.co.uk/products/SWLINUX/ + * Ben Dooks * * Samsung S3C2410 NAND driver * @@ -10,8 +11,9 @@ * 23-Sep-2004 BJD Mulitple device support * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode * 12-Oct-2004 BJD Fixed errors in use of platform data + * 18-Feb-2004 BJD Fix sparse errors * - * $Id: s3c2410.c,v 1.7 2005/01/05 18:05:14 dwmw2 Exp $ + * $Id: s3c2410.c,v 1.8 2005/02/18 14:46:12 bjd Exp $ * * 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 @@ -69,10 +71,10 @@ static int hardware_ecc = 0; */ static struct nand_oobinfo nand_hw_eccoob = { - .useecc = MTD_NANDECC_AUTOPLACE, - .eccbytes = 3, - .eccpos = {0, 1, 2 }, - .oobfree = { {8, 8} } + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 3, + .eccpos = {0, 1, 2 }, + .oobfree = { {8, 8} } }; /* controller and mtd information */ @@ -99,7 +101,7 @@ struct s3c2410_nand_info { struct device *device; struct resource *area; struct clk *clk; - void *regs; + void __iomem *regs; int mtd_count; }; @@ -523,8 +525,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, { struct nand_chip *chip = &nmtd->chip; - chip->IO_ADDR_R = (char *)info->regs + S3C2410_NFDATA; - chip->IO_ADDR_W = (char *)info->regs + S3C2410_NFDATA; + chip->IO_ADDR_R = info->regs + S3C2410_NFDATA; + chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; chip->hwcontrol = s3c2410_nand_hwcontrol; chip->dev_ready = s3c2410_nand_devready; chip->cmdfunc = s3c2410_nand_command; -- cgit v1.2.3 From dfd61294403cce7ca2263674f420c3417093cb56 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 22 Feb 2005 21:48:25 +0000 Subject: [MTD] DiskOnChip: Wait for the command to finish. Do not use the ready function here, as it might hang for ever. The result will show, whether the chip is there or not Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/diskonchip.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index d5927674f28..a9b1da40ad3 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -16,7 +16,7 @@ * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.48 2005/01/31 22:22:21 gleixner Exp $ + * $Id: diskonchip.c,v 1.49 2005/02/22 21:48:21 gleixner Exp $ */ #include @@ -410,7 +410,12 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) doc200x_hwcontrol(mtd, NAND_CTL_SETALE); this->write_byte(mtd, 0); doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); - + + /* We cant' use dev_ready here, but at least we wait for the + * command to complete + */ + udelay(50); + ret = this->read_byte(mtd) << 8; ret |= this->read_byte(mtd); @@ -429,6 +434,8 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) doc2000_write_byte(mtd, 0); doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); + udelay(50); + ident.dword = readl(docptr + DoC_2k_CDSN_IO); if (((ident.byte[0] << 8) | ident.byte[1]) == ret) { printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n"); -- cgit v1.2.3 From 3b88775c7504dfdedd5f267cb8f02999e380222a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 22 Feb 2005 21:56:49 +0000 Subject: [MTD] NAND: Check command timeout Check timeout while we wait for the command to finish. No worry about a false result. This prevents deadlocking when detecting an unknown number of chips and is useful for removable media too. Signed-off-by: Thomas Gleixner Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index acd5ec193ff..4d7c916c74f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.133 2005/02/16 09:39:35 gleixner Exp $ + * $Id: nand_base.c,v 1.134 2005/02/22 21:56:46 gleixner Exp $ * * 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 @@ -509,6 +509,22 @@ static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, i return nand_isbad_bbt (mtd, ofs, allowbbt); } +/* + * Wait for the ready pin, after a command + * The timeout is catched later. + */ +static void nand_wait_ready(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + unsigned long timeo = jiffies + 2; + + /* wait until command is processed or timeout occures */ + do { + if (this->dev_ready(mtd)) + return; + } while (time_before(jiffies, timeo)); +} + /** * nand_command - [DEFAULT] Send command to NAND device * @mtd: MTD device structure @@ -604,12 +620,11 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in return; } } - /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); - /* wait until command is processed */ - while (!this->dev_ready(mtd)); + + nand_wait_ready(mtd); } /** @@ -720,12 +735,12 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, return; } } - + /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); - /* wait until command is processed */ - while (!this->dev_ready(mtd)); + + nand_wait_ready(mtd); } /** @@ -1011,7 +1026,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + nand_wait_ready(mtd); /* All done, return happy */ if (!numpages) @@ -1302,7 +1317,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + nand_wait_ready(mtd); if (read == len) break; @@ -1401,7 +1416,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + nand_wait_ready(mtd); /* Read more ? */ if (i < len) { @@ -1481,7 +1496,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + nand_wait_ready(mtd); /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) -- cgit v1.2.3 From d30f11d22549c54e9b05d153e37d166f88a2aa43 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Wed, 23 Feb 2005 19:37:11 +0000 Subject: [MTD] Use after free, found by the Coverity tool Signed-off-by: Alexander Nyberg Signed-off-by: Joern Engel Signed-off-by: Thomas Gleixner --- drivers/mtd/devices/phram.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 5f8e164ddb7..57454df639f 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -1,5 +1,5 @@ /** - * $Id: phram.c,v 1.11 2005/01/05 18:05:13 dwmw2 Exp $ + * $Id: phram.c,v 1.12 2005/02/23 19:37:07 joern Exp $ * * Copyright (c) ???? Jochen Schäuble * Copyright (c) 2003-2004 Jörn Engel @@ -107,9 +107,9 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len, static void unregister_devices(void) { - struct phram_mtd_list *this; + struct phram_mtd_list *this, *safe; - list_for_each_entry(this, &phram_list, list) { + list_for_each_entry_safe(this, safe, &phram_list, list) { del_mtd_device(&this->mtd); iounmap(this->mtd.priv); kfree(this); -- cgit v1.2.3 From 002fa30170f9500ac31fa22931c689029af7f27b Mon Sep 17 00:00:00 2001 From: Pete Popov Date: Sun, 27 Feb 2005 21:50:25 +0000 Subject: [MTD] Replace all the Au1x mapping drivers with a simplified single driver This driver does not have as many options but it's easier to maintain. And, it turns out AMD never shipped boards with different flash densities. Signed-off-by: Pete Popov Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/Kconfig | 73 +------------ drivers/mtd/maps/Makefile | 7 +- drivers/mtd/maps/alchemy-flash.c | 192 +++++++++++++++++++++++++++++++++ drivers/mtd/maps/db1550-flash.c | 187 -------------------------------- drivers/mtd/maps/db1x00-flash.c | 226 --------------------------------------- drivers/mtd/maps/pb1550-flash.c | 203 ----------------------------------- drivers/mtd/maps/pb1xxx-flash.c | 178 ------------------------------ 7 files changed, 199 insertions(+), 867 deletions(-) create mode 100644 drivers/mtd/maps/alchemy-flash.c delete mode 100644 drivers/mtd/maps/db1550-flash.c delete mode 100644 drivers/mtd/maps/db1x00-flash.c delete mode 100644 drivers/mtd/maps/pb1550-flash.c delete mode 100644 drivers/mtd/maps/pb1xxx-flash.c (limited to 'drivers') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index d29dc121c1f..f036de8080b 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.44 2005/02/18 11:03:45 bjd Exp $ +# $Id: Kconfig,v 1.45 2005/02/27 21:50:21 ppopov Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -213,74 +213,11 @@ config MTD_NETtel help Support for flash chips on NETtel/SecureEdge/SnapGear boards. -config MTD_PB1XXX - tristate "Flash devices on Alchemy PB1xxx boards" - depends on MIPS && ( MIPS_PB1000 || MIPS_PB1100 || MIPS_PB1500 ) +config MTD_ALCHEMY + tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' + depends on MIPS && SOC_AU1X00 help - Flash memory access on Alchemy Pb1000/Pb1100/Pb1500 boards - -config MTD_PB1XXX_BOOT - bool "PB1x00 boot flash device" - depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 ) - help - Use the first of the two 32MiB flash banks on Pb1100/Pb1500 board. - You can say 'Y' to both this and 'MTD_PB1XXX_USER' below, to use - both banks. - -config MTD_PB1XXX_USER - bool "PB1x00 user flash device" - depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 ) - default y if MTD_PB1XX_BOOT = n - help - Use the second of the two 32MiB flash banks on Pb1100/Pb1500 board. - You can say 'Y' to both this and 'MTD_PB1XXX_BOOT' above, to use - both banks. - -config MTD_PB1550 - tristate "Flash devices on Alchemy PB1550 board" - depends on MIPS && MIPS_PB1550 - help - Flash memory access on Alchemy Pb1550 board - -config MTD_PB1550_BOOT - bool "PB1550 boot flash device" - depends on MTD_PB1550 - help - Use the first of the two 64MiB flash banks on Pb1550 board. - You can say 'Y' to both this and 'MTD_PB1550_USER' below, to use - both banks. - -config MTD_PB1550_USER - bool "PB1550 user flash device" - depends on MTD_PB1550 - default y if MTD_PB1550_BOOT = n - help - Use the second of the two 64MiB flash banks on Pb1550 board. - You can say 'Y' to both this and 'MTD_PB1550_BOOT' above, to use - both banks. - -config MTD_DB1550 - tristate "Flash devices on Alchemy DB1550 board" - depends on MIPS && MIPS_DB1550 - help - Flash memory access on Alchemy Db1550 board - -config MTD_DB1550_BOOT - bool "DB1550 boot flash device" - depends on MTD_DB1550 - help - Use the first of the two 64MiB flash banks on Db1550 board. - You can say 'Y' to both this and 'MTD_DB1550_USER' below, to use - both banks. - -config MTD_DB1550_USER - bool "DB1550 user flash device" - depends on MTD_DB1550 - default y if MTD_DB1550_BOOT = n - help - Use the second of the two 64MiB flash banks on Db1550 board. - You can say 'Y' to both this and 'MTD_DB1550_BOOT' above, to use - both banks. + Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards config MTD_DILNETPC tristate "CFI Flash device mapped on DIL/Net PC" diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index d2e6dcc8705..d0639a85cb1 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile.common,v 1.24 2005/01/24 00:35:21 bjd Exp $ +# $Id: Makefile.common,v 1.25 2005/02/27 21:50:21 ppopov Exp $ ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) obj-$(CONFIG_MTD) += map_funcs.o @@ -44,10 +44,7 @@ obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_OCELOT) += ocelot.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o -obj-$(CONFIG_MTD_PB1XXX) += pb1xxx-flash.o -obj-$(CONFIG_MTD_DB1X00) += db1x00-flash.o -obj-$(CONFIG_MTD_PB1550) += pb1550-flash.o -obj-$(CONFIG_MTD_DB1550) += db1550-flash.o +obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o obj-$(CONFIG_MTD_LASAT) += lasat.o obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o obj-$(CONFIG_MTD_EDB7312) += edb7312.o diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c new file mode 100644 index 00000000000..27fd2a3c3b6 --- /dev/null +++ b/drivers/mtd/maps/alchemy-flash.c @@ -0,0 +1,192 @@ +/* + * Flash memory access on AMD Alchemy evaluation boards + * + * $Id: alchemy-flash.c,v 1.1 2005/02/27 21:50:21 ppopov Exp $ + * + * (C) 2003, 2004 Pete Popov + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#ifdef DEBUG_RW +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#ifdef CONFIG_MIPS_PB1000 +#define BOARD_MAP_NAME "Pb1000 Flash" +#define BOARD_FLASH_SIZE 0x00800000 /* 8MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_PB1500 +#define BOARD_MAP_NAME "Pb1500 Flash" +#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_PB1100 +#define BOARD_MAP_NAME "Pb1100 Flash" +#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_PB1550 +#define BOARD_MAP_NAME "Pb1550 Flash" +#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_PB1200 +#define BOARD_MAP_NAME "Pb1200 Flash" +#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */ +#define BOARD_FLASH_WIDTH 2 /* 16-bits */ +#endif + +#ifdef CONFIG_MIPS_DB1000 +#define BOARD_MAP_NAME "Db1000 Flash" +#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_DB1500 +#define BOARD_MAP_NAME "Db1500 Flash" +#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_DB1100 +#define BOARD_MAP_NAME "Db1100 Flash" +#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_DB1550 +#define BOARD_MAP_NAME "Db1550 Flash" +#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_DB1200 +#define BOARD_MAP_NAME "Db1200 Flash" +#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */ +#define BOARD_FLASH_WIDTH 2 /* 16-bits */ +#endif + +#ifdef CONFIG_MIPS_HYDROGEN3 +#define BOARD_MAP_NAME "Hydrogen3 Flash" +#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#define USE_LOCAL_ACCESSORS /* why? */ +#endif + +#ifdef CONFIG_MIPS_BOSPORUS +#define BOARD_MAP_NAME "Bosporus Flash" +#define BOARD_FLASH_SIZE 0x01000000 /* 16MB */ +#define BOARD_FLASH_WIDTH 2 /* 16-bits */ +#endif + +#ifdef CONFIG_MIPS_MIRAGE +#define BOARD_MAP_NAME "Mirage Flash" +#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#define USE_LOCAL_ACCESSORS /* why? */ +#endif + +static struct map_info alchemy_map = { + .name = BOARD_MAP_NAME, +}; + +static struct mtd_partition alchemy_partitions[] = { + { + .name = "User FS", + .size = BOARD_FLASH_SIZE - 0x00400000, + .offset = 0x0000000 + },{ + .name = "YAMON", + .size = 0x0100000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE + },{ + .name = "raw kernel", + .size = (0x300000 - 0x40000), /* last 256KB is yamon env */ + .offset = MTDPART_OFS_APPEND, + } +}; + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_info *mymtd; + +int __init alchemy_mtd_init(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + unsigned long window_addr; + unsigned long window_size; + + /* Default flash buswidth */ + alchemy_map.bankwidth = BOARD_FLASH_WIDTH; + + window_addr = 0x20000000 - BOARD_FLASH_SIZE; + window_size = BOARD_FLASH_SIZE; +#ifdef CONFIG_MIPS_MIRAGE_WHY + /* Boot ROM flash bank only; no user bank */ + window_addr = 0x1C000000; + window_size = 0x04000000; + /* USERFS from 0x1C00 0000 to 0x1FC00000 */ + alchemy_partitions[0].size = 0x03C00000; +#endif + + /* + * Static partition definition selection + */ + parts = alchemy_partitions; + nb_parts = NB_OF(alchemy_partitions); + alchemy_map.size = window_size; + + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n", + alchemy_map.bankwidth*8); + alchemy_map.virt = ioremap(window_addr, window_size); + mymtd = do_map_probe("cfi_probe", &alchemy_map); + if (!mymtd) { + iounmap(alchemy_map.virt); + return -ENXIO; + } + mymtd->owner = THIS_MODULE; + + add_mtd_partitions(mymtd, parts, nb_parts); + return 0; +} + +static void __exit alchemy_mtd_cleanup(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + iounmap(alchemy_map.virt); + } +} + +module_init(alchemy_mtd_init); +module_exit(alchemy_mtd_cleanup); + +MODULE_AUTHOR("Embedded Alley Solutions, Inc"); +MODULE_DESCRIPTION(BOARD_MAP_NAME " MTD driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/maps/db1550-flash.c b/drivers/mtd/maps/db1550-flash.c deleted file mode 100644 index d213888462a..00000000000 --- a/drivers/mtd/maps/db1550-flash.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Flash memory access on Alchemy Db1550 board - * - * $Id: db1550-flash.c,v 1.7 2004/11/04 13:24:14 gleixner Exp $ - * - * (C) 2004 Embedded Edge, LLC, based on db1550-flash.c: - * (C) 2003, 2004 Pete Popov - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#ifdef DEBUG_RW -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -static unsigned long window_addr; -static unsigned long window_size; - - -static struct map_info db1550_map = { - .name = "Db1550 flash", -}; - -static unsigned char flash_bankwidth = 4; - -/* - * Support only 64MB NOR Flash parts - */ - -#if defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER) -#define DB1550_BOTH_BANKS -#elif defined(CONFIG_MTD_DB1550_BOOT) && !defined(CONFIG_MTD_DB1550_USER) -#define DB1550_BOOT_ONLY -#elif !defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER) -#define DB1550_USER_ONLY -#endif - -#ifdef DB1550_BOTH_BANKS -/* both banks will be used. Combine the first bank and the first - * part of the second bank together into a single jffs/jffs2 - * partition. - */ -static struct mtd_partition db1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash - * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash - */ - { - .name = "User FS", - .size = (0x1FC00000 - 0x18000000), - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000 - 0x40000), /* last 256KB is yamon env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(DB1550_BOOT_ONLY) -static struct mtd_partition db1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash - */ - { - .name = "User FS", - .size = 0x03c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000-0x40000), /* last 256KB is yamon env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(DB1550_USER_ONLY) -static struct mtd_partition db1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash - */ - { - .name = "User FS", - .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */ - .offset = 0x0000000 - },{ - .name = "raw kernel", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, - } -}; -#else -#error MTD_DB1550 define combo error /* should never happen */ -#endif - -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - -static struct mtd_info *mymtd; - -/* - * Probe the flash density and setup window address and size - * based on user CONFIG options. There are times when we don't - * want the MTD driver to be probing the boot or user flash, - * so having the option to enable only one bank is important. - */ -int setup_flash_params(void) -{ -#if defined(DB1550_BOTH_BANKS) - window_addr = 0x18000000; - window_size = 0x8000000; -#elif defined(DB1550_BOOT_ONLY) - window_addr = 0x1C000000; - window_size = 0x4000000; -#else /* USER ONLY */ - window_addr = 0x18000000; - window_size = 0x4000000; -#endif - return 0; -} - -int __init db1550_mtd_init(void) -{ - struct mtd_partition *parts; - int nb_parts = 0; - - /* Default flash bankwidth */ - db1550_map.bankwidth = flash_bankwidth; - - if (setup_flash_params()) - return -ENXIO; - - /* - * Static partition definition selection - */ - parts = db1550_partitions; - nb_parts = NB_OF(db1550_partitions); - db1550_map.size = window_size; - - /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. - */ - printk(KERN_NOTICE "Db1550 flash: probing %d-bit flash bus\n", - db1550_map.bankwidth*8); - db1550_map.virt = ioremap(window_addr, window_size); - mymtd = do_map_probe("cfi_probe", &db1550_map); - if (!mymtd) return -ENXIO; - mymtd->owner = THIS_MODULE; - - add_mtd_partitions(mymtd, parts, nb_parts); - return 0; -} - -static void __exit db1550_mtd_cleanup(void) -{ - if (mymtd) { - del_mtd_partitions(mymtd); - map_destroy(mymtd); - iounmap((void *) db1550_map.virt); - } -} - -module_init(db1550_mtd_init); -module_exit(db1550_mtd_cleanup); - -MODULE_AUTHOR("Embedded Edge, LLC"); -MODULE_DESCRIPTION("Db1550 mtd map driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/maps/db1x00-flash.c b/drivers/mtd/maps/db1x00-flash.c deleted file mode 100644 index faa68ec5690..00000000000 --- a/drivers/mtd/maps/db1x00-flash.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Flash memory access on Alchemy Db1xxx boards - * - * $Id: db1x00-flash.c,v 1.6 2004/11/04 13:24:14 gleixner Exp $ - * - * (C) 2003 Pete Popov - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#ifdef DEBUG_RW -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* MTD CONFIG OPTIONS */ -#if defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER) -#define DB1X00_BOTH_BANKS -#elif defined(CONFIG_MTD_DB1X00_BOOT) && !defined(CONFIG_MTD_DB1X00_USER) -#define DB1X00_BOOT_ONLY -#elif !defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER) -#define DB1X00_USER_ONLY -#endif - -static unsigned long window_addr; -static unsigned long window_size; -static unsigned long flash_size; - -static unsigned short *bcsr = (unsigned short *)0xAE000000; -static unsigned char flash_bankwidth = 4; - -/* - * The Db1x boards support different flash densities. We setup - * the mtd_partition structures below for default of 64Mbit - * flash densities, and override the partitions sizes, if - * necessary, after we check the board status register. - */ - -#ifdef DB1X00_BOTH_BANKS -/* both banks will be used. Combine the first bank and the first - * part of the second bank together into a single jffs/jffs2 - * partition. - */ -static struct mtd_partition db1x00_partitions[] = { - { - .name = "User FS", - .size = 0x1c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000-0x40000), /* last 256KB is env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(DB1X00_BOOT_ONLY) -static struct mtd_partition db1x00_partitions[] = { - { - .name = "User FS", - .size = 0x00c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000-0x40000), /* last 256KB is env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(DB1X00_USER_ONLY) -static struct mtd_partition db1x00_partitions[] = { - { - .name = "User FS", - .size = 0x0e00000, - .offset = 0x0000000 - },{ - .name = "raw kernel", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, - } -}; -#else -#error MTD_DB1X00 define combo error /* should never happen */ -#endif -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - -#define NAME "Db1x00 Linux Flash" - -static struct map_info db1xxx_mtd_map = { - .name = NAME, -}; - -static struct mtd_partition *parsed_parts; -static struct mtd_info *db1xxx_mtd; - -/* - * Probe the flash density and setup window address and size - * based on user CONFIG options. There are times when we don't - * want the MTD driver to be probing the boot or user flash, - * so having the option to enable only one bank is important. - */ -int setup_flash_params(void) -{ - switch ((bcsr[2] >> 14) & 0x3) { - case 0: /* 64Mbit devices */ - flash_size = 0x800000; /* 8MB per part */ -#if defined(DB1X00_BOTH_BANKS) - window_addr = 0x1E000000; - window_size = 0x2000000; -#elif defined(DB1X00_BOOT_ONLY) - window_addr = 0x1F000000; - window_size = 0x1000000; -#else /* USER ONLY */ - window_addr = 0x1E000000; - window_size = 0x1000000; -#endif - break; - case 1: - /* 128 Mbit devices */ - flash_size = 0x1000000; /* 16MB per part */ -#if defined(DB1X00_BOTH_BANKS) - window_addr = 0x1C000000; - window_size = 0x4000000; - /* USERFS from 0x1C00 0000 to 0x1FC0 0000 */ - db1x00_partitions[0].size = 0x3C00000; -#elif defined(DB1X00_BOOT_ONLY) - window_addr = 0x1E000000; - window_size = 0x2000000; - /* USERFS from 0x1E00 0000 to 0x1FC0 0000 */ - db1x00_partitions[0].size = 0x1C00000; -#else /* USER ONLY */ - window_addr = 0x1C000000; - window_size = 0x2000000; - /* USERFS from 0x1C00 0000 to 0x1DE00000 */ - db1x00_partitions[0].size = 0x1DE0000; -#endif - break; - case 2: - /* 256 Mbit devices */ - flash_size = 0x4000000; /* 64MB per part */ -#if defined(DB1X00_BOTH_BANKS) - return 1; -#elif defined(DB1X00_BOOT_ONLY) - /* Boot ROM flash bank only; no user bank */ - window_addr = 0x1C000000; - window_size = 0x4000000; - /* USERFS from 0x1C00 0000 to 0x1FC00000 */ - db1x00_partitions[0].size = 0x3C00000; -#else /* USER ONLY */ - return 1; -#endif - break; - default: - return 1; - } - db1xxx_mtd_map.size = window_size; - db1xxx_mtd_map.bankwidth = flash_bankwidth; - db1xxx_mtd_map.phys = window_addr; - db1xxx_mtd_map.bankwidth = flash_bankwidth; - return 0; -} - -int __init db1x00_mtd_init(void) -{ - struct mtd_partition *parts; - int nb_parts = 0; - - if (setup_flash_params()) - return -ENXIO; - - /* - * Static partition definition selection - */ - parts = db1x00_partitions; - nb_parts = NB_OF(db1x00_partitions); - - /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. - */ - printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n", - db1xxx_mtd_map.bankwidth*8); - db1xxx_mtd_map.virt = ioremap(window_addr, window_size); - db1xxx_mtd = do_map_probe("cfi_probe", &db1xxx_mtd_map); - if (!db1xxx_mtd) return -ENXIO; - db1xxx_mtd->owner = THIS_MODULE; - - add_mtd_partitions(db1xxx_mtd, parts, nb_parts); - return 0; -} - -static void __exit db1x00_mtd_cleanup(void) -{ - if (db1xxx_mtd) { - del_mtd_partitions(db1xxx_mtd); - map_destroy(db1xxx_mtd); - if (parsed_parts) - kfree(parsed_parts); - } -} - -module_init(db1x00_mtd_init); -module_exit(db1x00_mtd_cleanup); - -MODULE_AUTHOR("Pete Popov"); -MODULE_DESCRIPTION("Db1x00 mtd map driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/maps/pb1550-flash.c b/drivers/mtd/maps/pb1550-flash.c deleted file mode 100644 index 1424726a219..00000000000 --- a/drivers/mtd/maps/pb1550-flash.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Flash memory access on Alchemy Pb1550 board - * - * $Id: pb1550-flash.c,v 1.6 2004/11/04 13:24:15 gleixner Exp $ - * - * (C) 2004 Embedded Edge, LLC, based on pb1550-flash.c: - * (C) 2003 Pete Popov - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#ifdef DEBUG_RW -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -static unsigned long window_addr; -static unsigned long window_size; - - -static struct map_info pb1550_map = { - .name = "Pb1550 flash", -}; - -static unsigned char flash_bankwidth = 4; - -/* - * Support only 64MB NOR Flash parts - */ - -#ifdef PB1550_BOTH_BANKS -/* both banks will be used. Combine the first bank and the first - * part of the second bank together into a single jffs/jffs2 - * partition. - */ -static struct mtd_partition pb1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash - * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash - */ - { - .name = "User FS", - .size = (0x1FC00000 - 0x18000000), - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000 - 0x40000), /* last 256KB is yamon env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(PB1550_BOOT_ONLY) -static struct mtd_partition pb1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash - */ - { - .name = "User FS", - .size = 0x03c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000-0x40000), /* last 256KB is yamon env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(PB1550_USER_ONLY) -static struct mtd_partition pb1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash - */ - { - .name = "User FS", - .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */ - .offset = 0x0000000 - },{ - .name = "raw kernel", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, - } -}; -#else -#error MTD_PB1550 define combo error /* should never happen */ -#endif - -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - -static struct mtd_info *mymtd; - -/* - * Probe the flash density and setup window address and size - * based on user CONFIG options. There are times when we don't - * want the MTD driver to be probing the boot or user flash, - * so having the option to enable only one bank is important. - */ -int setup_flash_params(void) -{ - u16 boot_swapboot; - boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | - ((bcsr->status >> 6) & 0x1); - printk("Pb1550 MTD: boot:swap %d\n", boot_swapboot); - - switch (boot_swapboot) { - case 0: /* 512Mbit devices, both enabled */ - case 1: - case 8: - case 9: -#if defined(PB1550_BOTH_BANKS) - window_addr = 0x18000000; - window_size = 0x8000000; -#elif defined(PB1550_BOOT_ONLY) - window_addr = 0x1C000000; - window_size = 0x4000000; -#else /* USER ONLY */ - window_addr = 0x1E000000; - window_size = 0x4000000; -#endif - break; - case 0xC: - case 0xD: - case 0xE: - case 0xF: - /* 64 MB Boot NOR Flash is disabled */ - /* and the start address is moved to 0x0C00000 */ - window_addr = 0x0C000000; - window_size = 0x4000000; - default: - printk("Pb1550 MTD: unsupported boot:swap setting\n"); - return 1; - } - return 0; -} - -int __init pb1550_mtd_init(void) -{ - struct mtd_partition *parts; - int nb_parts = 0; - - /* Default flash bankwidth */ - pb1550_map.bankwidth = flash_bankwidth; - - if (setup_flash_params()) - return -ENXIO; - - /* - * Static partition definition selection - */ - parts = pb1550_partitions; - nb_parts = NB_OF(pb1550_partitions); - pb1550_map.size = window_size; - - /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. - */ - printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n", - pb1550_map.bankwidth*8); - pb1550_map.virt = ioremap(window_addr, window_size); - mymtd = do_map_probe("cfi_probe", &pb1550_map); - if (!mymtd) return -ENXIO; - mymtd->owner = THIS_MODULE; - - add_mtd_partitions(mymtd, parts, nb_parts); - return 0; -} - -static void __exit pb1550_mtd_cleanup(void) -{ - if (mymtd) { - del_mtd_partitions(mymtd); - map_destroy(mymtd); - } -} - -module_init(pb1550_mtd_init); -module_exit(pb1550_mtd_cleanup); - -MODULE_AUTHOR("Embedded Edge, LLC"); -MODULE_DESCRIPTION("Pb1550 mtd map driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/maps/pb1xxx-flash.c b/drivers/mtd/maps/pb1xxx-flash.c deleted file mode 100644 index 06e73154055..00000000000 --- a/drivers/mtd/maps/pb1xxx-flash.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Flash memory access on Alchemy Pb1xxx boards - * - * (C) 2001 Pete Popov - * - * $Id: pb1xxx-flash.c,v 1.14 2004/11/04 13:24:15 gleixner Exp $ - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#ifdef DEBUG_RW -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -#ifdef CONFIG_MIPS_PB1000 - -#define WINDOW_ADDR 0x1F800000 -#define WINDOW_SIZE 0x800000 - -static struct mtd_partition pb1xxx_partitions[] = { - { - .name = "yamon env", - .size = 0x00020000, - .offset = 0, - .mask_flags = MTD_WRITEABLE}, - { - .name = "User FS", - .size = 0x003e0000, - .offset = 0x20000,}, - { - .name = "boot code", - .size = 0x100000, - .offset = 0x400000, - .mask_flags = MTD_WRITEABLE}, - { - .name = "raw/kernel", - .size = 0x300000, - .offset = 0x500000} -}; - -#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) - -#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) -/* both 32MB banks will be used. Combine the first 32MB bank and the - * first 28MB of the second bank together into a single jffs/jffs2 - * partition. - */ -#define WINDOW_ADDR 0x1C000000 -#define WINDOW_SIZE 0x4000000 -static struct mtd_partition pb1xxx_partitions[] = { - { - .name = "User FS", - .size = 0x3c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = 0x3c00000, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = 0x02c0000, - .offset = 0x3d00000 - } -}; -#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER) -#define WINDOW_ADDR 0x1E000000 -#define WINDOW_SIZE 0x2000000 -static struct mtd_partition pb1xxx_partitions[] = { - { - .name = "User FS", - .size = 0x1c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = 0x1c00000, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = 0x02c0000, - .offset = 0x1d00000 - } -}; -#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) -#define WINDOW_ADDR 0x1C000000 -#define WINDOW_SIZE 0x2000000 -static struct mtd_partition pb1xxx_partitions[] = { - { - .name = "User FS", - .size = 0x1e00000, - .offset = 0x0000000 - },{ - .name = "raw kernel", - .size = 0x0200000, - .offset = 0x1e00000, - } -}; -#else -#error MTD_PB1500 define combo error /* should never happen */ -#endif -#else -#error Unsupported board -#endif - -#define NAME "Pb1x00 Linux Flash" -#define PADDR WINDOW_ADDR -#define BUSWIDTH 4 -#define SIZE WINDOW_SIZE -#define PARTITIONS 4 - -static struct map_info pb1xxx_mtd_map = { - .name = NAME, - .size = SIZE, - .bankwidth = BUSWIDTH, - .phys = PADDR, -}; - -static struct mtd_info *pb1xxx_mtd; - -int __init pb1xxx_mtd_init(void) -{ - struct mtd_partition *parts; - int nb_parts = 0; - char *part_type; - - /* - * Static partition definition selection - */ - part_type = "static"; - parts = pb1xxx_partitions; - nb_parts = ARRAY_SIZE(pb1xxx_partitions); - - /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. - */ - printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", - BUSWIDTH*8); - pb1xxx_mtd_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); - - simple_map_init(&pb1xxx_mtd_map); - - pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map); - if (!pb1xxx_mtd) return -ENXIO; - pb1xxx_mtd->owner = THIS_MODULE; - - add_mtd_partitions(pb1xxx_mtd, parts, nb_parts); - return 0; -} - -static void __exit pb1xxx_mtd_cleanup(void) -{ - if (pb1xxx_mtd) { - del_mtd_partitions(pb1xxx_mtd); - map_destroy(pb1xxx_mtd); - iounmap((void *) pb1xxx_mtd_map.virt); - } -} - -module_init(pb1xxx_mtd_init); -module_exit(pb1xxx_mtd_cleanup); - -MODULE_AUTHOR("Pete Popov"); -MODULE_DESCRIPTION("Pb1xxx CFI map driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 20a6c211903dce92a0db7f19c221cfa3f2cb4c32 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 1 Mar 2005 09:32:48 +0000 Subject: [MTD] NAND: Use cond_resched instead of msleep Replace msleep by cond_resched. On machines with HZ=100 (e.g. ARM) msleep slows down the operation by factor 10 Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 4d7c916c74f..4c94ec632ae 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.134 2005/02/22 21:56:46 gleixner Exp $ + * $Id: nand_base.c,v 1.135 2005/03/01 09:32:45 gleixner Exp $ * * 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 @@ -830,7 +830,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) if (this->read_byte(mtd) & NAND_STATUS_READY) break; } - msleep(1); + cond_resched(); } status = (int) this->read_byte(mtd); return status; -- cgit v1.2.3 From b4eab4b8d633ff1d65dac5cfb07949489f68ae26 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Wed, 2 Mar 2005 14:51:08 +0000 Subject: [MTD] Remove Elan-104NC Remove support for the Arcom Elan-104NC since it's no longer being maintained. Signed-off-by: David Vrabel Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/Kconfig | 12 +-- drivers/mtd/maps/Makefile | 3 +- drivers/mtd/maps/elan-104nc.c | 228 ------------------------------------------ 3 files changed, 2 insertions(+), 241 deletions(-) delete mode 100644 drivers/mtd/maps/elan-104nc.c (limited to 'drivers') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index f036de8080b..d3699e9f394 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.45 2005/02/27 21:50:21 ppopov Exp $ +# $Id: Kconfig,v 1.46 2005/03/02 14:51:04 dvrabel Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -122,16 +122,6 @@ config MTD_SBC_GXX More info at . -config MTD_ELAN_104NC - tristate "CFI Flash device mapped on Arcom ELAN-104NC" - depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS - help - This provides a driver for the on-board flash of the Arcom Control - System's ELAN-104NC development board. By default the flash - is split into 3 partitions which are accessed as separate MTD - devices. This board utilizes Intel StrataFlash. More info at - . - config MTD_LUBBOCK tristate "CFI Flash device mapped on Intel Lubbock XScale eval board" depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index d0639a85cb1..164cafc101c 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile.common,v 1.25 2005/02/27 21:50:21 ppopov Exp $ +# $Id: Makefile.common,v 1.26 2005/03/02 14:51:04 dvrabel Exp $ ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) obj-$(CONFIG_MTD) += map_funcs.o @@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o obj-$(CONFIG_MTD_DC21285) += dc21285.o obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o -obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o obj-$(CONFIG_MTD_IQ80310) += iq80310.o obj-$(CONFIG_MTD_L440GX) += l440gx.o diff --git a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c deleted file mode 100644 index e9465f5c069..00000000000 --- a/drivers/mtd/maps/elan-104nc.c +++ /dev/null @@ -1,228 +0,0 @@ -/* elan-104nc.c -- MTD map driver for Arcom Control Systems ELAN-104NC - - Copyright (C) 2000 Arcom Control System Ltd - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 - - $Id: elan-104nc.c,v 1.25 2004/11/28 09:40:39 dwmw2 Exp $ - -The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16 -mode. This drivers uses the CFI probe and Intel Extended Command Set drivers. - -The flash is accessed as follows: - - 32 kbyte memory window at 0xb0000-0xb7fff - - 16 bit I/O port (0x22) for some sort of paging. - -The single flash device is divided into 3 partition which appear as separate -MTD devices. - -Linux thinks that the I/O port is used by the PIC and hence check_region() will -always fail. So we don't do it. I just hope it doesn't break anything. -*/ -#include -#include -#include -#include -#include - -#include -#include -#include - -#define WINDOW_START 0xb0000 -/* Number of bits in offset. */ -#define WINDOW_SHIFT 15 -#define WINDOW_LENGTH (1 << WINDOW_SHIFT) -/* The bits for the offset into the window. */ -#define WINDOW_MASK (WINDOW_LENGTH-1) -#define PAGE_IO 0x22 -#define PAGE_IO_SIZE 2 - -static volatile int page_in_window = -1; // Current page in window. -static void __iomem *iomapadr; -static DEFINE_SPINLOCK(elan_104nc_spin); - -/* partition_info gives details on the logical partitions that the split the - * single flash device into. If the size if zero we use up to the end of the - * device. */ -static struct mtd_partition partition_info[]={ - { .name = "ELAN-104NC flash boot partition", - .offset = 0, - .size = 640*1024 }, - { .name = "ELAN-104NC flash partition 1", - .offset = 640*1024, - .size = 896*1024 }, - { .name = "ELAN-104NC flash partition 2", - .offset = (640+896)*1024 } -}; -#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) - -/* - * If no idea what is going on here. This is taken from the FlashFX stuff. - */ -#define ROMCS 1 - -static inline void elan_104nc_setup(void) -{ - u16 t; - - outw( 0x0023 + ROMCS*2, PAGE_IO ); - t=inb( PAGE_IO+1 ); - - t=(t & 0xf9) | 0x04; - - outw( ((0x0023 + ROMCS*2) | (t << 8)), PAGE_IO ); -} - -static inline void elan_104nc_page(struct map_info *map, unsigned long ofs) -{ - unsigned long page = ofs >> WINDOW_SHIFT; - - if( page!=page_in_window ) { - int cmd1; - int cmd2; - - cmd1=(page & 0x700) + 0x0833 + ROMCS*0x4000; - cmd2=((page & 0xff) << 8) + 0x0032; - - outw( cmd1, PAGE_IO ); - outw( cmd2, PAGE_IO ); - - page_in_window = page; - } -} - - -static map_word elan_104nc_read16(struct map_info *map, unsigned long ofs) -{ - map_word ret; - spin_lock(&elan_104nc_spin); - elan_104nc_page(map, ofs); - ret.x[0] = readw(iomapadr + (ofs & WINDOW_MASK)); - spin_unlock(&elan_104nc_spin); - return ret; -} - -static void elan_104nc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - while (len) { - unsigned long thislen = len; - if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) - thislen = WINDOW_LENGTH-(from & WINDOW_MASK); - - spin_lock(&elan_104nc_spin); - elan_104nc_page(map, from); - memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen); - spin_unlock(&elan_104nc_spin); - to += thislen; - from += thislen; - len -= thislen; - } -} - -static void elan_104nc_write16(struct map_info *map, map_word d, unsigned long adr) -{ - spin_lock(&elan_104nc_spin); - elan_104nc_page(map, adr); - writew(d.x[0], iomapadr + (adr & WINDOW_MASK)); - spin_unlock(&elan_104nc_spin); -} - -static void elan_104nc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - while(len) { - unsigned long thislen = len; - if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) - thislen = WINDOW_LENGTH-(to & WINDOW_MASK); - - spin_lock(&elan_104nc_spin); - elan_104nc_page(map, to); - memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen); - spin_unlock(&elan_104nc_spin); - to += thislen; - from += thislen; - len -= thislen; - } -} - -static struct map_info elan_104nc_map = { - .name = "ELAN-104NC flash", - .phys = NO_XIP, - .size = 8*1024*1024, /* this must be set to a maximum possible amount - of flash so the cfi probe routines find all - the chips */ - .bankwidth = 2, - .read = elan_104nc_read16, - .copy_from = elan_104nc_copy_from, - .write = elan_104nc_write16, - .copy_to = elan_104nc_copy_to -}; - -/* MTD device for all of the flash. */ -static struct mtd_info *all_mtd; - -static void cleanup_elan_104nc(void) -{ - if( all_mtd ) { - del_mtd_partitions( all_mtd ); - map_destroy( all_mtd ); - } - - iounmap(iomapadr); -} - -static int __init init_elan_104nc(void) -{ - /* Urg! We use I/O port 0x22 without request_region()ing it, - because it's already allocated to the PIC. */ - - iomapadr = ioremap(WINDOW_START, WINDOW_LENGTH); - if (!iomapadr) { - printk( KERN_ERR"%s: failed to ioremap memory region\n", - elan_104nc_map.name ); - return -EIO; - } - - printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", - elan_104nc_map.name, - PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1, - WINDOW_START, WINDOW_START+WINDOW_LENGTH-1 ); - - elan_104nc_setup(); - - /* Probe for chip. */ - all_mtd = do_map_probe("cfi_probe", &elan_104nc_map ); - if( !all_mtd ) { - cleanup_elan_104nc(); - return -ENXIO; - } - - all_mtd->owner = THIS_MODULE; - - /* Create MTD devices for each partition. */ - add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS ); - - return 0; -} - -module_init(init_elan_104nc); -module_exit(cleanup_elan_104nc); - - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Arcom Control Systems Ltd."); -MODULE_DESCRIPTION("MTD map driver for Arcom Control Systems ELAN-104NC"); -- cgit v1.2.3 From 711c11b78d00c0652d38893c558a2bcca55d96d4 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Mon, 7 Mar 2005 20:29:09 +0000 Subject: [MTD] block2mtd: Remove copyright. Fix offset calculation - Remove Gareth from the Copyrights (at his own request) - Fix the "fscking embarrassment" Signed-off-by: Joern Engel Signed-off-by: Thomas Gleixner --- drivers/mtd/devices/block2mtd.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index cfe6ccf0797..e5da82a0dd6 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -1,10 +1,9 @@ /* - * $Id: block2mtd.c,v 1.23 2005/01/05 17:05:46 dwmw2 Exp $ + * $Id: block2mtd.c,v 1.25 2005/03/07 20:29:05 joern Exp $ * * block2mtd.c - create an mtd from a block device * * Copyright (C) 2001,2002 Simon Evans - * Copyright (C) 2004 Gareth Bult * Copyright (C) 2004,2005 Jörn Engel * * Licence: GPL @@ -20,7 +19,7 @@ #include #include -#define VERSION "$Revision: 1.23 $" +#define VERSION "$Revision: 1.24 $" #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) @@ -157,7 +156,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, struct block2mtd_dev *dev = mtd->priv; struct page *page; int index = from >> PAGE_SHIFT; - int offset = from & (PAGE_SHIFT-1); + int offset = from & (PAGE_SIZE-1); int cpylen; if (from > mtd->size) -- cgit v1.2.3 From 663259a44f440249cab1b0f3f4b82cfab8e4758d Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Mon, 7 Mar 2005 21:43:42 +0000 Subject: [MTD] phram: Allow short reads. Jffs2 apparently needs this. Accept newline at the end of input. Signed-off-by: Joern Engel Signed-off-by: Thomas Gleixner --- drivers/mtd/devices/phram.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 57454df639f..a423a382095 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -1,5 +1,5 @@ /** - * $Id: phram.c,v 1.12 2005/02/23 19:37:07 joern Exp $ + * $Id: phram.c,v 1.14 2005/03/07 21:43:38 joern Exp $ * * Copyright (c) ???? Jochen Schäuble * Copyright (c) 2003-2004 Jörn Engel @@ -15,9 +15,7 @@ * * Example: * phram=swap,64Mi,128Mi phram=test,900Mi,1Mi - * */ - #include #include #include @@ -36,7 +34,6 @@ struct phram_mtd_list { static LIST_HEAD(phram_list); - static int phram_erase(struct mtd_info *mtd, struct erase_info *instr) { u_char *start = mtd->priv; @@ -71,7 +68,8 @@ static int phram_point(struct mtd_info *mtd, loff_t from, size_t len, return 0; } -static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) +static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, + size_t len) { } @@ -80,8 +78,11 @@ static int phram_read(struct mtd_info *mtd, loff_t from, size_t len, { u_char *start = mtd->priv; - if (from + len > mtd->size) + if (from >= mtd->size) return -EINVAL; + + if (len > mtd->size - from) + len = mtd->size - from; memcpy(buf, start + from, len); @@ -94,8 +95,11 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len, { u_char *start = mtd->priv; - if (to + len > mtd->size) + if (to >= mtd->size) return -EINVAL; + + if (len > mtd->size - to) + len = mtd->size - to; memcpy(start + to, buf, len); @@ -145,7 +149,7 @@ static int register_device(char *name, unsigned long start, unsigned long len) new->mtd.write = phram_write; new->mtd.owner = THIS_MODULE; new->mtd.type = MTD_RAM; - new->mtd.erasesize = 0; + new->mtd.erasesize = PAGE_SIZE; ret = -EAGAIN; if (add_mtd_device(&new->mtd)) { @@ -214,6 +218,15 @@ static int parse_name(char **pname, const char *token) return 0; } + +static inline void kill_final_newline(char *str) +{ + char *newline = strrchr(str, '\n'); + if (newline && !newline[1]) + *newline = 0; +} + + #define parse_err(fmt, args...) do { \ ERROR(fmt , ## args); \ return 0; \ @@ -232,6 +245,7 @@ static int phram_setup(const char *val, struct kernel_param *kp) parse_err("parameter too long\n"); strcpy(str, val); + kill_final_newline(str); for (i=0; i<3; i++) token[i] = strsep(&str, ","); -- cgit v1.2.3 From 3b946e3f3dc0de473a88b4106f01731a5c016689 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 14 Mar 2005 18:30:48 +0000 Subject: [MTD] NAND: Fixed unused loop variable Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 4c94ec632ae..cc3cd277064 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.135 2005/03/01 09:32:45 gleixner Exp $ + * $Id: nand_base.c,v 1.136 2005/03/14 18:30:44 bjd Exp $ * * 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 @@ -2291,7 +2291,7 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) */ int nand_scan (struct mtd_info *mtd, int maxchips) { - int i, j, nand_maf_id, nand_dev_id, busw, maf_id; + int i, nand_maf_id, nand_dev_id, busw, maf_id; struct nand_chip *this = mtd->priv; /* Get buswidth to select the correct functions*/ -- cgit v1.2.3 From fb6bb52ddde0429b654ab6d4cb20fa016a1d5b0d Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 14 Mar 2005 20:33:22 +0000 Subject: [MTD] plat-ram: removed extraneous debugging code removed define of DEBUG removed extraneous debugging code Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/plat-ram.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 808f94346ad..f7e6dad50ca 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -6,7 +6,7 @@ * * Generic platfrom device based RAM map * - * $Id: plat-ram.c,v 1.1 2005/01/24 00:37:02 bjd Exp $ + * $Id: plat-ram.c,v 1.2 2005/03/14 20:33:19 bjd Exp $ * * 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 @@ -23,8 +23,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define DEBUG - #include #include #include @@ -192,7 +190,7 @@ static int platram_probe(struct device *dev) /* remap the memory area */ info->map.virt = ioremap(res->start, info->map.size); - dev_dbg(dev, "virt %p, %d bytes\n", info->map.virt, info->map.size); + dev_dbg(dev, "virt %p, %lu bytes\n", info->map.virt, info->map.size); if (info->map.virt == NULL) { dev_err(dev, "failed to ioremap() region\n"); @@ -200,12 +198,6 @@ static int platram_probe(struct device *dev) goto exit_free; } - { - unsigned int *p = (unsigned int *)info->map.virt; - printk("%08x %08x %08x %08x\n", - readl(p), readl(p+1), readl(p+2), readl(p+3)); - } - simple_map_init(&info->map); dev_dbg(dev, "initialised map, probing for mtd\n"); -- cgit v1.2.3 From 3a70025047f90de2133744a8918e90fcf5a93366 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 15 Mar 2005 19:07:21 +0000 Subject: [MTD] cfi_cmdset_0001: Fix the buggy status check. The change makes the code endianess aware and replaces the bogus nested loop to or the status flags together. Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index f018ea16217..92074ff9dac 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.168 2005/02/17 20:34:59 nico Exp $ + * $Id: cfi_cmdset_0001.c,v 1.169 2005/03/15 19:07:18 gleixner Exp $ * * * 10/10/2000 Nicolas Pitre @@ -1697,24 +1697,14 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, /* check for lock bit */ if (map_word_bitsset(map, status, CMD(0x3a))) { - unsigned char chipstatus; + unsigned long chipstatus; /* Reset the error bits */ map_write(map, CMD(0x50), adr); map_write(map, CMD(0x70), adr); xip_enable(map, chip, adr); - chipstatus = status.x[0]; - if (!map_word_equal(map, status, CMD(chipstatus))) { - int i, w; - for (w=0; w> (cfi->device_type * 8); - } - } - printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n", - status.x[0], chipstatus); - } + chipstatus = MERGESTATUS(status); if ((chipstatus & 0x30) == 0x30) { printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus); -- cgit v1.2.3 From 09c7933547e383ab89ee1b08ec86899bef3035cf Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 16 Mar 2005 22:41:09 +0000 Subject: [MTD] cfi_cmdset_0001: Fix state after sync oldstate has to be reset to FL_READY after sync completion. Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 92074ff9dac..87554aae01e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.169 2005/03/15 19:07:18 gleixner Exp $ + * $Id: cfi_cmdset_0001.c,v 1.170 2005/03/16 22:41:05 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -1789,6 +1789,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd) if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; + chip->oldstate = FL_READY; wake_up(&chip->wq); } spin_unlock(chip->mutex); -- cgit v1.2.3 From 3e4ef3bb77f7b87c631ba188d4a4b4eb30b2f16f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 17 Mar 2005 11:31:30 +0000 Subject: [MTD] NAND s3c2410: Simplify command handling Updated with tglx's suggestion to simply the command invocation by simply changing the address of the IO write area Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/s3c2410.c | 118 +++++---------------------------------------- 1 file changed, 12 insertions(+), 106 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index cb04b3c771e..64b1d95e3e3 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -11,9 +11,10 @@ * 23-Sep-2004 BJD Mulitple device support * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode * 12-Oct-2004 BJD Fixed errors in use of platform data - * 18-Feb-2004 BJD Fix sparse errors + * 18-Feb-2005 BJD Fix sparse errors + * 14-Mar-2005 BJD Applied tglx's code reduction patch * - * $Id: s3c2410.c,v 1.8 2005/02/18 14:46:12 bjd Exp $ + * $Id: s3c2410.c,v 1.12 2005/03/17 11:31:26 bjd Exp $ * * 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 @@ -236,6 +237,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + struct nand_chip *chip = mtd->priv; unsigned long cur; switch (cmd) { @@ -251,117 +253,22 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) writel(cur, info->regs + S3C2410_NFCONF); break; - /* we don't need to implement these */ case NAND_CTL_SETCLE: - case NAND_CTL_CLRCLE: - case NAND_CTL_SETALE: - case NAND_CTL_CLRALE: - pr_debug(PFX "s3c2410_nand_hwcontrol(%d) unusedn", cmd); + chip->IO_ADDR_W = info->regs + S3C2410_NFCMD; break; - } -} - -/* s3c2410_nand_command - * - * This function implements sending commands and the relevant address - * information to the chip, via the hardware controller. Since the - * S3C2410 generates the correct ALE/CLE signaling automatically, we - * do not need to use hwcontrol. -*/ - -static void s3c2410_nand_command (struct mtd_info *mtd, unsigned command, - int column, int page_addr) -{ - register struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - register struct nand_chip *this = mtd->priv; - - /* - * Write out the command to the device. - */ - if (command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->oobblock) { - /* OOB area */ - column -= mtd->oobblock; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - - writeb(readcmd, info->regs + S3C2410_NFCMD); - } - writeb(command, info->regs + S3C2410_NFCMD); - - /* Set ALE and clear CLE to start address cycle */ - if (column != -1 || page_addr != -1) { + case NAND_CTL_SETALE: + chip->IO_ADDR_W = info->regs + S3C2410_NFADDR; + break; - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (this->options & NAND_BUSWIDTH_16) - column >>= 1; - writeb(column, info->regs + S3C2410_NFADDR); - } - if (page_addr != -1) { - writeb((unsigned char) (page_addr), info->regs + S3C2410_NFADDR); - writeb((unsigned char) (page_addr >> 8), info->regs + S3C2410_NFADDR); - /* One more address cycle for higher density devices */ - if (this->chipsize & 0x0c000000) - writeb((unsigned char) ((page_addr >> 16) & 0x0f), - info->regs + S3C2410_NFADDR); - } - /* Latch in address */ - } - - /* - * program and erase have their own busy handlers - * status and sequential in needs no delay - */ - switch (command) { - - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_STATUS: - return; - - case NAND_CMD_RESET: - if (this->dev_ready) - break; - - udelay(this->chip_delay); - writeb(NAND_CMD_STATUS, info->regs + S3C2410_NFCMD); - - while ( !(this->read_byte(mtd) & 0x40)); - return; - - /* This applies to read commands */ + /* NAND_CTL_CLRCLE: */ + /* NAND_CTL_CLRALE: */ default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay - */ - if (!this->dev_ready) { - udelay (this->chip_delay); - return; - } + chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; + break; } - - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ - ndelay (100); - /* wait until command is processed */ - while (!this->dev_ready(mtd)); } - /* s3c2410_nand_devready() * * returns 0 if the nand is busy, 1 if it is ready @@ -529,7 +436,6 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; chip->hwcontrol = s3c2410_nand_hwcontrol; chip->dev_ready = s3c2410_nand_devready; - chip->cmdfunc = s3c2410_nand_command; chip->write_buf = s3c2410_nand_write_buf; chip->read_buf = s3c2410_nand_read_buf; chip->select_chip = s3c2410_nand_select_chip; -- cgit v1.2.3 From 3c45e00afcaa22c65cfb7f77649591db9e0bec03 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 18 Mar 2005 02:07:24 +0000 Subject: [MTD] Fix typo in Kconfig Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index d3699e9f394..8d27dbf3fa8 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.46 2005/03/02 14:51:04 dvrabel Exp $ +# $Id: Kconfig,v 1.51 2005/03/18 02:07:22 gleixner Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -588,7 +588,7 @@ config MTD_SHARP_SL This enables access to the flash chip on the Sharp SL Series of PDAs. config MTD_PLATRAM - tristate "Map driver for platfrom device RAM (mtd-ram)" + tristate "Map driver for platform device RAM (mtd-ram)" depends on MTD select MTD_RAM help -- cgit v1.2.3 From ff3bc4eb94ec3d2ce6e8f615d38c94151ccb6553 Mon Sep 17 00:00:00 2001 From: Domen Puncer Date: Fri, 18 Mar 2005 14:04:38 +0000 Subject: [MTD] Kernel Janitor fixes. Signed-off-by: Domen Puncer Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/amd76xrom.c | 4 ++-- drivers/mtd/maps/ichxrom.c | 4 ++-- drivers/mtd/maps/pci.c | 4 ++-- drivers/mtd/maps/scb2_flash.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 51e97b05304..e8a900a7768 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -2,7 +2,7 @@ * amd76xrom.c * * Normal mappings of chips in physical memory - * $Id: amd76xrom.c,v 1.19 2004/11/28 09:40:39 dwmw2 Exp $ + * $Id: amd76xrom.c,v 1.20 2005/03/18 14:04:35 gleixner Exp $ */ #include @@ -314,7 +314,7 @@ static int __init init_amd76xrom(void) } return -ENXIO; #if 0 - return pci_module_init(&amd76xrom_driver); + return pci_register_driver(&amd76xrom_driver); #endif } diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index 29d1cc1bb42..1800ceedf38 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -2,7 +2,7 @@ * ichxrom.c * * Normal mappings of chips in physical memory - * $Id: ichxrom.c,v 1.16 2004/11/28 09:40:39 dwmw2 Exp $ + * $Id: ichxrom.c,v 1.17 2005/03/18 14:04:35 gleixner Exp $ */ #include @@ -366,7 +366,7 @@ static int __init init_ichxrom(void) } return -ENXIO; #if 0 - return pci_module_init(&ichxrom_driver); + return pci_register_driver(&ichxrom_driver); #endif } diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index 08b60bdc538..18dbd3af1ea 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * $Id: pci.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $ + * $Id: pci.c,v 1.10 2005/03/18 14:04:35 gleixner Exp $ * * Generic PCI memory map driver. We support the following boards: * - Intel IQ80310 ATU. @@ -370,7 +370,7 @@ static struct pci_driver mtd_pci_driver = { static int __init mtd_pci_maps_init(void) { - return pci_module_init(&mtd_pci_driver); + return pci_register_driver(&mtd_pci_driver); } static void __exit mtd_pci_maps_exit(void) diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index 5bb3b600e5d..97a8dfd6925 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c @@ -1,6 +1,6 @@ /* * MTD map driver for BIOS Flash on Intel SCB2 boards - * $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 Exp $ + * $Id: scb2_flash.c,v 1.12 2005/03/18 14:04:35 gleixner Exp $ * Copyright (C) 2002 Sun Microsystems, Inc. * Tim Hockin * @@ -238,7 +238,7 @@ static struct pci_driver scb2_flash_driver = { static int __init scb2_flash_init(void) { - return pci_module_init(&scb2_flash_driver); + return pci_register_driver(&scb2_flash_driver); } static void __exit -- cgit v1.2.3 From 167e1770e526c6c6cdff5014e32f5a3363c017f3 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 18 Mar 2005 14:07:49 +0000 Subject: [MTD] ixp2000: Remove port setting code Setting the slowport to 8-bit mode is something that ought to be done in the IXP2000 generic code, not in the MTD map driver. See the description for ARM patch 2493/1 for an explanation. http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=2493/1 Now that 2493/1 has been accepted and will be upstream soon, this doesn't need to be done in the map driver anymore. Signed-off-by: Lennert Buytenhek Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/ixp2000.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index c5b5f447e34..3e94b616743 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c @@ -1,5 +1,5 @@ /* - * $Id: ixp2000.c,v 1.5 2004/11/16 17:15:48 dsaxena Exp $ + * $Id: ixp2000.c,v 1.6 2005/03/18 14:07:46 gleixner Exp $ * * drivers/mtd/maps/ixp2000.c * @@ -216,11 +216,6 @@ static int ixp2000_flash_probe(struct device *_dev) goto Error; } - /* - * Setup read mode for FLASH - */ - *IXP2000_SLOWPORT_FRM = 1; - #if defined(__ARMEB__) /* * Enable erratum 44 workaround for NPUs with broken slowport -- cgit v1.2.3 From 515022870f0f648b9c506a285b1c7e92901dd37f Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Sat, 19 Mar 2005 15:33:59 +0000 Subject: [MTD] NAND nandsim: Use NAND_SKIP_BBT option Use the new NAND_SKIP_BBT option instead of defining a fake scan_bbt handler. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nandsim.c | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 13feefd7d8c..754b6ed7ce1 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * - * $Id: nandsim.c,v 1.7 2004/12/06 11:53:06 dedekind Exp $ + * $Id: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $ */ #include @@ -1483,33 +1483,6 @@ ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) } } -/* - * Having only NAND chip IDs we call nand_scan which detects NAND flash - * parameters and then calls scan_bbt in order to scan/find/build the - * NAND flash bad block table. But since at that moment the NAND flash - * image isn't allocated in the simulator, errors arise. To avoid this - * we redefine the scan_bbt callback and initialize the nandsim structure - * before the flash media scanning. - */ -int ns_scan_bbt(struct mtd_info *mtd) -{ - struct nand_chip *chip = (struct nand_chip *)mtd->priv; - struct nandsim *ns = (struct nandsim *)(chip->priv); - int retval; - - if (!NS_IS_INITIALIZED(ns)) - if ((retval = init_nandsim(mtd)) != 0) { - NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); - return retval; - } - if ((retval = nand_default_bbt(mtd)) != 0) { - free_nandsim(ns); - return retval; - } - - return 0; -} - /* * Module initialization function */ @@ -1544,7 +1517,6 @@ int __init ns_init_module(void) chip->hwcontrol = ns_hwcontrol; chip->read_byte = ns_nand_read_byte; chip->dev_ready = ns_device_ready; - chip->scan_bbt = ns_scan_bbt; chip->write_byte = ns_nand_write_byte; chip->write_buf = ns_nand_write_buf; chip->read_buf = ns_nand_read_buf; @@ -1552,6 +1524,7 @@ int __init ns_init_module(void) chip->write_word = ns_nand_write_word; chip->read_word = ns_nand_read_word; chip->eccmode = NAND_ECC_SOFT; + chip->options |= NAND_SKIP_BBTSCAN; /* * Perform minimum nandsim structure initialization to handle @@ -1580,6 +1553,16 @@ int __init ns_init_module(void) goto error; } + if ((retval = init_nandsim(nsmtd)) != 0) { + NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); + goto error; + } + + if ((retval = nand_default_bbt(nsmtd)) != 0) { + free_nandsim(nand); + goto error; + } + /* Register NAND as one big partition */ add_mtd_partitions(nsmtd, &nand->part, 1); -- cgit v1.2.3 From 50da7f60960a2e39aa8784983c580a3ddfd9bd8d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 19 Mar 2005 22:39:52 +0000 Subject: [MTD] cfi_cmdset_0001: Fix compiler warnings Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 87554aae01e..100a00063f8 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.170 2005/03/16 22:41:05 nico Exp $ + * $Id: cfi_cmdset_0001.c,v 1.171 2005/03/19 22:39:49 gleixner Exp $ * * * 10/10/2000 Nicolas Pitre @@ -1707,24 +1707,24 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chipstatus = MERGESTATUS(status); if ((chipstatus & 0x30) == 0x30) { - printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus); + printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%lx\n", chipstatus); ret = -EIO; } else if (chipstatus & 0x02) { /* Protection bit set */ ret = -EROFS; } else if (chipstatus & 0x8) { /* Voltage */ - printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", chipstatus); + printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%lx\n", chipstatus); ret = -EIO; } else if (chipstatus & 0x20) { if (retries--) { - printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus); + printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); timeo = jiffies + HZ; put_chip(map, chip, adr); spin_unlock(chip->mutex); goto retry; } - printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus); + printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx\n", adr, chipstatus); ret = -EIO; } } else { -- cgit v1.2.3 From cc71229ff345a32d1b3de370a257dac62986b187 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 19 Mar 2005 22:40:47 +0000 Subject: [MTD] block2mtd: Fix incompatible pointer type Signed-off-by: Thomas Gleixner --- drivers/mtd/devices/block2mtd.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index e5da82a0dd6..4a7a805e756 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -1,5 +1,5 @@ /* - * $Id: block2mtd.c,v 1.25 2005/03/07 20:29:05 joern Exp $ + * $Id: block2mtd.c,v 1.28 2005/03/19 22:40:44 gleixner Exp $ * * block2mtd.c - create an mtd from a block device * @@ -19,7 +19,7 @@ #include #include -#define VERSION "$Revision: 1.24 $" +#define VERSION "$Revision: 1.28 $" #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) @@ -88,7 +88,6 @@ void cache_readahead(struct address_space *mapping, int index) static struct page* page_readahead(struct address_space *mapping, int index) { filler_t *filler = (filler_t*)mapping->a_ops->readpage; - //do_page_cache_readahead(mapping, index, XXX, 64); cache_readahead(mapping, index); return read_cache_page(mapping, index, filler, NULL); } @@ -369,16 +368,16 @@ static int ustrtoul(const char *cp, char **endp, unsigned int base) } -static int parse_num32(u32 *num32, const char *token) +static int parse_num(size_t *num, const char *token) { char *endp; - unsigned long n; + size_t n; - n = ustrtoul(token, &endp, 0); + n = (size_t) ustrtoul(token, &endp, 0); if (*endp) return -EINVAL; - *num32 = n; + *num = n; return 0; } @@ -421,7 +420,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp) char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */ char *token[2]; char *name; - u32 erase_size = PAGE_SIZE; + size_t erase_size = PAGE_SIZE; int i, ret; if (strnlen(val, sizeof(buf)) >= sizeof(buf)) @@ -448,7 +447,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp) return 0; if (token[1]) { - ret = parse_num32(&erase_size, token[1]); + ret = parse_num(&erase_size, token[1]); if (ret) parse_err("illegal erase size"); } -- cgit v1.2.3 From a921e28b4bd35b091754a1814ff015fe268b9295 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 19 Mar 2005 22:41:30 +0000 Subject: [MTD] plat-ram: Make it usable on non ARM platforms Use memset instead of ARM only memzero function Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/plat-ram.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index f7e6dad50ca..118b04544ca 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -6,7 +6,7 @@ * * Generic platfrom device based RAM map * - * $Id: plat-ram.c,v 1.2 2005/03/14 20:33:19 bjd Exp $ + * $Id: plat-ram.c,v 1.3 2005/03/19 22:41:27 gleixner Exp $ * * 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 @@ -153,7 +153,7 @@ static int platram_probe(struct device *dev) goto exit_error; } - memzero(info, sizeof(*info)); + memset(info, 0, sizeof(*info)); dev_set_drvdata(dev, info); info->dev = dev; -- cgit v1.2.3 From ba38069875a365a33b9b56e42dfdb71b5ce7a3a4 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 21 Mar 2005 00:10:24 +0000 Subject: [MTD] Add support for more SharpSL machines and fix missing mapping init Signed-off-by: Richard Purdie Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/sharpsl-flash.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index b3b39cb7c60..c643d4c5124 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c @@ -4,7 +4,7 @@ * Copyright (C) 2001 Lineo Japan, Inc. * Copyright (C) 2002 SHARP * - * $Id: sharpsl-flash.c,v 1.2 2004/11/24 20:38:06 rpurdie Exp $ + * $Id: sharpsl-flash.c,v 1.3 2005/03/21 00:10:21 rpurdie Exp $ * * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp * Handle mapping of the flash on the RPX Lite and CLLF boards @@ -24,13 +24,14 @@ #include #include #include -#include #include #include #include +#include +#include #define WINDOW_ADDR 0x00000000 -#define WINDOW_SIZE 0x01000000 +#define WINDOW_SIZE 0x00800000 #define BANK_WIDTH 2 static struct mtd_info *mymtd; @@ -44,9 +45,7 @@ struct map_info sharpsl_map = { static struct mtd_partition sharpsl_partitions[1] = { { - name: "Filesystem", - size: 0x006d0000, - offset: 0x00120000 + name: "Boot PROM Filesystem", } }; @@ -64,6 +63,9 @@ int __init init_sharpsl(void) printk("Failed to ioremap\n"); return -EIO; } + + simple_map_init(&sharpsl_map); + mymtd = do_map_probe("map_rom", &sharpsl_map); if (!mymtd) { iounmap(sharpsl_map.virt); @@ -72,6 +74,18 @@ int __init init_sharpsl(void) mymtd->owner = THIS_MODULE; + if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() || machine_is_poodle()) { + sharpsl_partitions[0].size=0x006d0000; + sharpsl_partitions[0].offset=0x00120000; + } else if (machine_is_tosa()) { + sharpsl_partitions[0].size=0x006a0000; + sharpsl_partitions[0].offset=0x00160000; + } else if (machine_is_spitz()) { + sharpsl_partitions[0].size=0x006b0000; + sharpsl_partitions[0].offset=0x00140000; + } else + return -ENODEV; + parts = sharpsl_partitions; nb_parts = NB_OF(sharpsl_partitions); -- cgit v1.2.3 From 8f5a4486c05275a5f3d53c80c86a44adb7fb8823 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Mon, 21 Mar 2005 08:42:14 +0000 Subject: [MTD] sharpsl-flash: Correct error paths Signed-off-by: Richard Purdie Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/sharpsl-flash.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index c643d4c5124..d15da6fd84c 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c @@ -4,7 +4,7 @@ * Copyright (C) 2001 Lineo Japan, Inc. * Copyright (C) 2002 SHARP * - * $Id: sharpsl-flash.c,v 1.3 2005/03/21 00:10:21 rpurdie Exp $ + * $Id: sharpsl-flash.c,v 1.5 2005/03/21 08:42:11 rpurdie Exp $ * * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp * Handle mapping of the flash on the RPX Lite and CLLF boards @@ -57,7 +57,8 @@ int __init init_sharpsl(void) int nb_parts = 0; char *part_type = "static"; - printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); + printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", + WINDOW_SIZE, WINDOW_ADDR); sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); if (!sharpsl_map.virt) { printk("Failed to ioremap\n"); @@ -74,7 +75,8 @@ int __init init_sharpsl(void) mymtd->owner = THIS_MODULE; - if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() || machine_is_poodle()) { + if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() + || machine_is_poodle()) { sharpsl_partitions[0].size=0x006d0000; sharpsl_partitions[0].offset=0x00120000; } else if (machine_is_tosa()) { @@ -83,8 +85,11 @@ int __init init_sharpsl(void) } else if (machine_is_spitz()) { sharpsl_partitions[0].size=0x006b0000; sharpsl_partitions[0].offset=0x00140000; - } else - return -ENODEV; + } else { + map_destroy(mymtd); + iounmap(sharpsl_map.virt); + return -ENODEV; + } parts = sharpsl_partitions; nb_parts = NB_OF(sharpsl_partitions); -- cgit v1.2.3 From 15fc108606a499df44549274a95d1e3455823347 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Thu, 24 Mar 2005 14:33:26 +0000 Subject: [MTD] NAND: Use arrays of needed size instead of constant-sized. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index cc3cd277064..422c465f311 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.136 2005/03/14 18:30:44 bjd Exp $ + * $Id: nand_base.c,v 1.137 2005/03/24 14:33:22 dedekind Exp $ * * 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 @@ -855,7 +855,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) { int i, status; - u_char ecc_code[32]; + u_char ecc_code[oobsel->eccbytes]; int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; int *oob_config = oobsel->eccpos; int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; @@ -961,7 +961,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int int i, j, datidx = 0, oobofs = 0, res = -EIO; int eccsteps = this->eccsteps; int hweccbytes; - u_char oobdata[64]; + u_char oobdata[mtd->oobsize]; hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; @@ -1107,8 +1107,8 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; struct nand_chip *this = mtd->priv; u_char *data_poi, *oob_data = oob_buf; - u_char ecc_calc[32]; - u_char ecc_code[32]; + u_char ecc_calc[oobsel->eccbytes]; + u_char ecc_code[oobsel->eccbytes]; int eccmode, eccsteps; int *oob_config, datidx; int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; -- cgit v1.2.3 From 1a78ff6b4114cfb0f734b7df217759315d692683 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 29 Mar 2005 21:57:48 +0100 Subject: [MTD] DiskOnChip: Scan the entire device for Media Headers. Add a new module param, show_firmware_partition. Signed-off-by: Dan Brown Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/diskonchip.c | 50 ++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index a9b1da40ad3..a96c43b4ea1 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -16,7 +16,7 @@ * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.49 2005/02/22 21:48:21 gleixner Exp $ + * $Id: diskonchip.c,v 1.50 2005/03/29 20:57:45 dbrown Exp $ */ #include @@ -81,11 +81,6 @@ struct doc_priv { struct mtd_info *nextdoc; }; -/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL - MediaHeader. The spec says to just keep going, I think, but that's just - silly. */ -#define MAX_MEDIAHEADER_SCAN 8 - /* This is the syndrome computed by the HW ecc generator upon reading an empty page, one with all 0xff for data and stored ecc code. */ static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a }; @@ -114,6 +109,9 @@ module_param(no_ecc_failures, int, 0); #ifdef CONFIG_MTD_PARTITIONS static int no_autopart=0; module_param(no_autopart, int, 0); + +static int show_firmware_partition=0; +module_param(show_firmware_partition, int, 0); #endif #ifdef MTD_NAND_DISKONCHIP_BBTWRITE @@ -1071,12 +1069,11 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift); + unsigned offs; int ret; size_t retlen; - end = min(end, mtd->size); // paranoia - for (offs = 0; offs < end; offs += mtd->erasesize) { + for (offs = 0; offs < mtd->size; offs += mtd->erasesize) { ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); if (retlen != mtd->oobblock) continue; if (ret) { @@ -1118,6 +1115,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, u_char *buf; struct NFTLMediaHeader *mh; const unsigned psize = 1 << this->page_shift; + int numparts = 0; unsigned blocks, maxblocks; int offs, numheaders; @@ -1183,19 +1181,28 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, offs <<= this->page_shift; offs += mtd->erasesize; - parts[0].name = " DiskOnChip BDTL partition"; - parts[0].offset = offs; - parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift; + if (show_firmware_partition == 1) { + parts[0].name = " DiskOnChip Firmware / Media Header partition"; + parts[0].offset = 0; + parts[0].size = offs; + numparts = 1; + } + + parts[numparts].name = " DiskOnChip BDTL partition"; + parts[numparts].offset = offs; + parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift; + + offs += parts[numparts].size; + numparts++; - offs += parts[0].size; if (offs < mtd->size) { - parts[1].name = " DiskOnChip Remainder partition"; - parts[1].offset = offs; - parts[1].size = mtd->size - offs; - ret = 2; - goto out; + parts[numparts].name = " DiskOnChip Remainder partition"; + parts[numparts].offset = offs; + parts[numparts].size = mtd->size - offs; + numparts++; } - ret = 1; + + ret = numparts; out: kfree(buf); return ret; @@ -1289,14 +1296,13 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, ip->lastUnit, ip->flags, ip->spareUnits); -#if 0 - if ((i == 0) && (ip->firstUnit > 0)) { + if ((show_firmware_partition == 1) && + (i == 0) && (ip->firstUnit > 0)) { parts[0].name = " DiskOnChip IPL / Media Header partition"; parts[0].offset = 0; parts[0].size = mtd->erasesize * ip->firstUnit; numparts = 1; } -#endif if (ip->flags & INFTL_BINARY) parts[numparts].name = " DiskOnChip BDK partition"; -- cgit v1.2.3 From 9a6e73ec4906bdf44ccfaaf8db56693b146595c0 Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Tue, 29 Mar 2005 23:06:40 +0100 Subject: [MTD] cfi_cmdset_0001: Skip delay if Instant Block Locking is set Skip jiffy delay after each block lock/unlock for Intel CFI flash with the "Instant Individual Block Locking" feature bit set. Signed-off-by: Todd Poynor Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 100a00063f8..51675bb2f83 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.171 2005/03/19 22:39:49 gleixner Exp $ + * $Id: cfi_cmdset_0001.c,v 1.172 2005/03/29 22:06:37 tpoynor Exp $ * * * 10/10/2000 Nicolas Pitre @@ -1823,6 +1823,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip unsigned long adr, int len, void *thunk) { struct cfi_private *cfi = map->fldrv_priv; + struct cfi_pri_intelext *extp = cfi->cmdset_priv; map_word status, status_OK; unsigned long timeo = jiffies + HZ; int ret; @@ -1852,9 +1853,16 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip } else BUG(); - spin_unlock(chip->mutex); - UDELAY(map, chip, adr, 1000000/HZ); - spin_lock(chip->mutex); + /* + * If Instant Individual Block Locking supported then no need + * to delay. + */ + + if (!extp || !(extp->FeatureSupport & (1 << 5))) { + spin_unlock(chip->mutex); + UDELAY(map, chip, adr, 1000000/HZ); + spin_lock(chip->mutex); + } /* FIXME. Use a timer to check this, and return immediately. */ /* Once the state machine's known to be working I'll do that */ -- cgit v1.2.3 From 8048d2fc38c9559ce37b46c21fa734c5cb9bcdb2 Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Thu, 31 Mar 2005 00:57:33 +0100 Subject: [MTD] Avoid compile warnings for Intel CFI flash without OTP support. Signed-off-by: Todd Poynor Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 51675bb2f83..b482a4e48e4 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.172 2005/03/29 22:06:37 tpoynor Exp $ + * $Id: cfi_cmdset_0001.c,v 1.173 2005/03/30 23:57:30 tpoynor Exp $ * * * 10/10/2000 Nicolas Pitre @@ -54,6 +54,7 @@ static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); static void cfi_intelext_sync (struct mtd_info *); static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); +#ifdef CONFIG_MTD_OTP static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); @@ -62,6 +63,7 @@ static int cfi_intelext_get_fact_prot_info (struct mtd_info *, struct otp_info *, size_t); static int cfi_intelext_get_user_prot_info (struct mtd_info *, struct otp_info *, size_t); +#endif static int cfi_intelext_suspend (struct mtd_info *); static void cfi_intelext_resume (struct mtd_info *); -- cgit v1.2.3 From 963a6fb0a0d336d0513083b7e4b5c3ff9d6d2061 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 1 Apr 2005 02:59:56 +0100 Subject: [MTD] Add reboot notifier to Intel NOR flash driver to make sure the flash is in array mode whenever we're about to reboot. This is especially useful to allow "soft" reboot to work which consists of branching back into the bootloader. Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 45 +++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index b482a4e48e4..dc257eb6932 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.173 2005/03/30 23:57:30 tpoynor Exp $ + * $Id: cfi_cmdset_0001.c,v 1.174 2005/04/01 01:59:52 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ static int cfi_intelext_get_user_prot_info (struct mtd_info *, #endif static int cfi_intelext_suspend (struct mtd_info *); static void cfi_intelext_resume (struct mtd_info *); +static int cfi_intelext_reboot (struct notifier_block *, unsigned long, void *); static void cfi_intelext_destroy(struct mtd_info *); @@ -333,7 +335,9 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) mtd->resume = cfi_intelext_resume; mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; - + + mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; + if (cfi->cfi_mode == CFI_MODE_CFI) { /* * It's a real CFI chip, not one for which the probe @@ -446,6 +450,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) goto setup_err; __module_get(THIS_MODULE); + register_reboot_notifier(&mtd->reboot_notifier); return mtd; setup_err: @@ -2301,10 +2306,46 @@ static void cfi_intelext_resume(struct mtd_info *mtd) } } +static int cfi_intelext_reset(struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + int i, ret; + + for (i=0; i < cfi->numchips; i++) { + struct flchip *chip = &cfi->chips[i]; + + /* force the completion of any ongoing operation + and switch to array mode so any bootloader in + flash is accessible for soft reboot. */ + spin_lock(chip->mutex); + ret = get_chip(map, chip, chip->start, FL_SYNCING); + if (!ret) { + map_write(map, CMD(0xff), chip->start); + chip->state = FL_READY; + } + spin_unlock(chip->mutex); + } + + return 0; +} + +static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val, + void *v) +{ + struct mtd_info *mtd; + + mtd = container_of(nb, struct mtd_info, reboot_notifier); + cfi_intelext_reset(mtd); + return NOTIFY_DONE; +} + static void cfi_intelext_destroy(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; + cfi_intelext_reset(mtd); + unregister_reboot_notifier(&mtd->reboot_notifier); kfree(cfi->cmdset_priv); kfree(cfi->cfiq); kfree(cfi->chips[0].priv); -- cgit v1.2.3 From 998cf6403cdaac74211c619772bea027274ffc42 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 1 Apr 2005 08:21:48 +0100 Subject: [MTD] NAND: Fix oob available calculation Use oobfree to calculate the number of oob bytes available for fs usage Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 422c465f311..aea87f05389 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.137 2005/03/24 14:33:22 dedekind Exp $ + * $Id: nand_base.c,v 1.138 2005/04/01 07:21:44 gleixner Exp $ * * 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 @@ -2512,12 +2512,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* The number of bytes available for the filesystem to place fs dependend * oob data */ - if (this->options & NAND_BUSWIDTH_16) { - mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2); - if (this->autooob->eccbytes & 0x01) - mtd->oobavail--; - } else - mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1); + mtd->oobavail = 0; + for (i = 0; this->autooob->oobfree[i][1]; i++) + mtd->oobavail += this->autooob->oobfree[i][1]; /* * check ECC mode, default to software -- cgit v1.2.3 From 81dba488792b29cc8cb2b3d49407be05303dde16 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 1 Apr 2005 16:36:15 +0100 Subject: [MTD] Reset file position when switching OTP mode Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/mtdchar.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 548b89204aa..da3f1a8f756 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1,5 +1,5 @@ /* - * $Id: mtdchar.c,v 1.68 2005/02/08 19:12:50 nico Exp $ + * $Id: mtdchar.c,v 1.70 2005/04/01 15:36:11 nico Exp $ * * Character-device access to raw MTD devices. * @@ -583,6 +583,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, case MTD_OTP_OFF: break; } + file->f_pos = 0; break; } -- cgit v1.2.3 From dce2b4da69a83635150a6535ebc23f680e200a8d Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 1 Apr 2005 17:36:29 +0100 Subject: [MTD] Fix OTP for top-parameter devices Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index dc257eb6932..b99400f6e48 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.174 2005/04/01 01:59:52 nico Exp $ + * $Id: cfi_cmdset_0001.c,v 1.175 2005/04/01 16:36:25 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -2062,8 +2062,20 @@ static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, /* we need real chips here not virtual ones */ devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave; chip_step = devsize >> cfi->chipshift; + chip_num = 0; + + /* Some chips have OTP located in the _top_ partition only. + For example: Intel 28F256L18T (T means top-parameter device) */ + if (cfi->mfr == MANUFACTURER_INTEL) { + switch (cfi->id) { + case 0x880b: + case 0x880c: + case 0x880d: + chip_num = chip_step - 1; + } + } - for (chip_num = 0; chip_num < cfi->numchips; chip_num += chip_step) { + for ( ; chip_num < cfi->numchips; chip_num += chip_step) { chip = &cfi->chips[chip_num]; otp = (struct cfi_intelext_otpinfo *)&extp->extra[0]; -- cgit v1.2.3 From bb75ba4c442c6aa73797c35651a697b0a8006bd6 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 4 Apr 2005 19:02:26 +0100 Subject: [MTD] NAND: Fix missing NULL pointer check Version 1.137 broke nand_read_ecc clients who pass NULL oobsel. Fixed. Signed-off-by: Dan Brown Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index aea87f05389..0da1daa5164 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.138 2005/04/01 07:21:44 gleixner Exp $ + * $Id: nand_base.c,v 1.139 2005/04/04 18:02:23 dbrown Exp $ * * 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 @@ -1090,8 +1090,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * @len: number of bytes to read * @retlen: pointer to variable to store the number of read bytes * @buf: the databuffer to put data - * @oob_buf: filesystem supplied oob data buffer - * @oobsel: oob selection structure + * @oob_buf: filesystem supplied oob data buffer (can be NULL) + * @oobsel: oob selection structure (can be NULL) * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed * and how many corrected error bits are acceptable: * bits 0..7 - number of tolerable errors @@ -1103,6 +1103,10 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel, int flags) { + /* use userspace supplied oobinfo, if zero */ + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; struct nand_chip *this = mtd->priv; @@ -1130,10 +1134,6 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, if (flags & NAND_GET_DEVICE) nand_get_device (this, mtd, FL_READING); - /* use userspace supplied oobinfo, if zero */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; - /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) oobsel = this->autooob; -- cgit v1.2.3 From 22c60f5fb7b8184a2d00a607f965b54c586fb40e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 4 Apr 2005 19:56:32 +0100 Subject: [MTD] NAND: Move the NULL check into the calling function Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 0da1daa5164..02e58f5ac72 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.139 2005/04/04 18:02:23 dbrown Exp $ + * $Id: nand_base.c,v 1.140 2005/04/04 18:56:29 gleixner Exp $ * * 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 @@ -1060,8 +1060,8 @@ out: */ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) { - return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff); -} + return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff); +} /** @@ -1079,6 +1079,9 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) { + /* use userspace supplied oobinfo, if zero */ + if (oobsel == NULL) + oobsel = &mtd->oobinfo; return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff); } @@ -1091,7 +1094,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * @retlen: pointer to variable to store the number of read bytes * @buf: the databuffer to put data * @oob_buf: filesystem supplied oob data buffer (can be NULL) - * @oobsel: oob selection structure (can be NULL) + * @oobsel: oob selection structure * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed * and how many corrected error bits are acceptable: * bits 0..7 - number of tolerable errors @@ -1103,10 +1106,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel, int flags) { - /* use userspace supplied oobinfo, if zero */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; - + int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; struct nand_chip *this = mtd->priv; -- cgit v1.2.3 From e5a3e8ca948e8ac0dad751dbd75e4dc96b4277e9 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 6 Apr 2005 19:10:24 +0100 Subject: [MTD] DiskOnChip: Fix (?) free OOB array info. I really hope this doesn't break something. Signed-off-by: Dan Brown Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/diskonchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index a96c43b4ea1..ee579dd3278 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -16,7 +16,7 @@ * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.50 2005/03/29 20:57:45 dbrown Exp $ + * $Id: diskonchip.c,v 1.51 2005/04/06 18:10:20 dbrown Exp $ */ #include @@ -1055,7 +1055,7 @@ static struct nand_oobinfo doc200x_oobinfo = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 6, .eccpos = {0, 1, 2, 3, 4, 5}, - .oobfree = { {8, 8} } + .oobfree = { {6, 10} } }; /* Find the (I)NFTL Media Header, and optionally also the mirror media header. -- cgit v1.2.3 From 82e1d19fc3e6bd20b65937352a015a412b751d47 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 6 Apr 2005 21:13:09 +0100 Subject: [MTD] NAND: Fix reading of autoplaced OOB when there are multiple free sections. Signed-off-by: Dan Brown Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 02e58f5ac72..b73f3c4e892 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.140 2005/04/04 18:56:29 gleixner Exp $ + * $Id: nand_base.c,v 1.141 2005/04/06 20:13:05 dbrown Exp $ * * 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 @@ -1285,13 +1285,12 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, switch(oobsel->useecc) { case MTD_NANDECC_AUTOPLACE: /* Walk through the autoplace chunks */ - for (i = 0, j = 0; j < mtd->oobavail; i++) { + for (i = 0; oobsel->oobfree[i][1]; i++) { int from = oobsel->oobfree[i][0]; int num = oobsel->oobfree[i][1]; memcpy(&oob_buf[oob], &oob_data[from], num); - j+= num; + oob += num; } - oob += mtd->oobavail; break; case MTD_NANDECC_PLACE: /* YAFFS1 legacy mode */ -- cgit v1.2.3 From dff59421983b235d5b8f713d01213fcc7f57c970 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 6 Apr 2005 21:14:22 +0100 Subject: [MTD] DiskOnChip: Prevent problems with existing filesystems Try not to break existing jffs2 installs, instead break oobfree into two out-of-order pieces. Signed-off-by: Dan Brown Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/diskonchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index ee579dd3278..fdc495c2f3e 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -16,7 +16,7 @@ * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.51 2005/04/06 18:10:20 dbrown Exp $ + * $Id: diskonchip.c,v 1.52 2005/04/06 20:14:19 dbrown Exp $ */ #include @@ -1055,7 +1055,7 @@ static struct nand_oobinfo doc200x_oobinfo = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 6, .eccpos = {0, 1, 2, 3, 4, 5}, - .oobfree = { {6, 10} } + .oobfree = { {8, 8}, {6, 2} } }; /* Find the (I)NFTL Media Header, and optionally also the mirror media header. -- cgit v1.2.3 From 7e4a1d3e6abec5464169a29a3d34473a59e2e8b7 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 7 Apr 2005 14:39:17 +0100 Subject: [MTD] DiskOnChip: Fix compile w/o CONFIG_MTD_PARTITIONS. Signed-off-by: Dan Brown Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/diskonchip.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index fdc495c2f3e..9f33f335a39 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -16,7 +16,7 @@ * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.52 2005/04/06 20:14:19 dbrown Exp $ + * $Id: diskonchip.c,v 1.53 2005/04/07 13:39:13 dbrown Exp $ */ #include @@ -106,13 +106,11 @@ module_param(try_dword, int, 0); static int no_ecc_failures=0; module_param(no_ecc_failures, int, 0); -#ifdef CONFIG_MTD_PARTITIONS static int no_autopart=0; module_param(no_autopart, int, 0); static int show_firmware_partition=0; module_param(show_firmware_partition, int, 0); -#endif #ifdef MTD_NAND_DISKONCHIP_BBTWRITE static int inftl_bbt_write=1; -- cgit v1.2.3 From abc37e6771ec92bb4c531d218ad572afbef6aa21 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 7 Apr 2005 15:22:58 +0100 Subject: [MTD] DiskOnChip: Add some comments Add helpful comment about oobfree so I can't claim two years from now that I don't remember what I was thinking. Signed-off-by: Dan Brown Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/diskonchip.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 9f33f335a39..fdb5d4ad3d5 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -16,7 +16,7 @@ * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.53 2005/04/07 13:39:13 dbrown Exp $ + * $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $ */ #include @@ -1049,6 +1049,16 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ //u_char mydatabuf[528]; +/* The strange out-of-order .oobfree list below is a (possibly unneeded) + * attempt to retain compatibility. It used to read: + * .oobfree = { {8, 8} } + * Since that leaves two bytes unusable, it was changed. But the following + * scheme might affect existing jffs2 installs by moving the cleanmarker: + * .oobfree = { {6, 10} } + * jffs2 seems to handle the above gracefully, but the current scheme seems + * safer. The only problem with it is that any code that parses oobfree must + * be able to handle out-of-order segments. + */ static struct nand_oobinfo doc200x_oobinfo = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 6, -- cgit v1.2.3 From 0a18cde60f384d1f7aa012aba004766fb633a31d Mon Sep 17 00:00:00 2001 From: Jarkko Lavinen Date: Mon, 11 Apr 2005 15:16:11 +0100 Subject: [MTD] NAND: Fix the broken dynamic array allocations Reverting the change from 1.136 to 1.137 (back to static allocation of ecc arrays) due to stack corruption and ecc errors. Signed-off-by: Jarkko Lavinen Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index b73f3c4e892..c1a971ca57e 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.141 2005/04/06 20:13:05 dbrown Exp $ + * $Id: nand_base.c,v 1.142 2005/04/11 14:16:07 lavinen Exp $ * * 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 @@ -855,7 +855,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) { int i, status; - u_char ecc_code[oobsel->eccbytes]; + u_char ecc_code[32]; int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; int *oob_config = oobsel->eccpos; int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; @@ -961,7 +961,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int int i, j, datidx = 0, oobofs = 0, res = -EIO; int eccsteps = this->eccsteps; int hweccbytes; - u_char oobdata[mtd->oobsize]; + u_char oobdata[64]; hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; @@ -1111,8 +1111,8 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; struct nand_chip *this = mtd->priv; u_char *data_poi, *oob_data = oob_buf; - u_char ecc_calc[oobsel->eccbytes]; - u_char ecc_code[oobsel->eccbytes]; + u_char ecc_calc[32]; + u_char ecc_code[32]; int eccmode, eccsteps; int *oob_config, datidx; int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; -- cgit v1.2.3 From c13cbf3b5086d4ed51360b86b6b0ef8b82b179dc Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Thu, 21 Apr 2005 04:42:15 +0100 Subject: [MTD] mtdram: Quick cleanup of the driver: - Lindent - Removal of slram/phram functionality - Removal of most #ifdefs Signed-off-by: Joern Engel Signed-off-by: Thomas Gleixner --- drivers/mtd/devices/mtdram.c | 265 ++++++++++++++++--------------------------- 1 file changed, 96 insertions(+), 169 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index edac4156d69..bb713fed2f3 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -1,9 +1,10 @@ /* * mtdram - a test mtd device - * $Id: mtdram.c,v 1.35 2005/01/05 18:05:12 dwmw2 Exp $ + * $Id: mtdram.c,v 1.37 2005/04/21 03:42:11 joern Exp $ * Author: Alexander Larsson * * Copyright (c) 1999 Alexander Larsson + * Copyright (c) 2005 Joern Engel * * This code is GPL * @@ -18,213 +19,140 @@ #include #include -#ifndef CONFIG_MTDRAM_ABS_POS - #define CONFIG_MTDRAM_ABS_POS 0 -#endif - -#if CONFIG_MTDRAM_ABS_POS > 0 - #include -#endif - -#ifdef MODULE static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE; static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE; -module_param(total_size,ulong,0); -MODULE_PARM_DESC(total_size, "Total device size in KiB"); -module_param(erase_size,ulong,0); -MODULE_PARM_DESC(erase_size, "Device erase block size in KiB"); #define MTDRAM_TOTAL_SIZE (total_size * 1024) #define MTDRAM_ERASE_SIZE (erase_size * 1024) -#else -#define MTDRAM_TOTAL_SIZE (CONFIG_MTDRAM_TOTAL_SIZE * 1024) -#define MTDRAM_ERASE_SIZE (CONFIG_MTDRAM_ERASE_SIZE * 1024) -#endif +#ifdef MODULE +module_param(total_size, ulong, 0); +MODULE_PARM_DESC(total_size, "Total device size in KiB"); +module_param(erase_size, ulong, 0); +MODULE_PARM_DESC(erase_size, "Device erase block size in KiB"); +#endif // We could store these in the mtd structure, but we only support 1 device.. static struct mtd_info *mtd_info; - -static int -ram_erase(struct mtd_info *mtd, struct erase_info *instr) +static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) { - DEBUG(MTD_DEBUG_LEVEL2, "ram_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len); - if (instr->addr + instr->len > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL1, "ram_erase() out of bounds (%ld > %ld)\n", (long)(instr->addr + instr->len), (long)mtd->size); - return -EINVAL; - } - - memset((char *)mtd->priv + instr->addr, 0xff, instr->len); - - instr->state = MTD_ERASE_DONE; - mtd_erase_callback(instr); - - return 0; + if (instr->addr + instr->len > mtd->size) + return -EINVAL; + + memset((char *)mtd->priv + instr->addr, 0xff, instr->len); + + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + + return 0; } -static int ram_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf) +static int ram_point(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char **mtdbuf) { - if (from + len > mtd->size) - return -EINVAL; - - *mtdbuf = mtd->priv + from; - *retlen = len; - return 0; + if (from + len > mtd->size) + return -EINVAL; + + *mtdbuf = mtd->priv + from; + *retlen = len; + return 0; } -static void ram_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, - size_t len) +static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from, + size_t len) { - DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n"); } static int ram_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) + size_t *retlen, u_char *buf) { - DEBUG(MTD_DEBUG_LEVEL2, "ram_read(pos:%ld, len:%ld)\n", (long)from, (long)len); - if (from + len > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL1, "ram_read() out of bounds (%ld > %ld)\n", (long)(from + len), (long)mtd->size); - return -EINVAL; - } + if (from + len > mtd->size) + return -EINVAL; - memcpy(buf, mtd->priv + from, len); + memcpy(buf, mtd->priv + from, len); - *retlen=len; - return 0; + *retlen = len; + return 0; } static int ram_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) + size_t *retlen, const u_char *buf) { - DEBUG(MTD_DEBUG_LEVEL2, "ram_write(pos:%ld, len:%ld)\n", (long)to, (long)len); - if (to + len > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL1, "ram_write() out of bounds (%ld > %ld)\n", (long)(to + len), (long)mtd->size); - return -EINVAL; - } + if (to + len > mtd->size) + return -EINVAL; - memcpy ((char *)mtd->priv + to, buf, len); + memcpy((char *)mtd->priv + to, buf, len); - *retlen=len; - return 0; + *retlen = len; + return 0; } static void __exit cleanup_mtdram(void) { - if (mtd_info) { - del_mtd_device(mtd_info); -#if CONFIG_MTDRAM_TOTAL_SIZE > 0 - if (mtd_info->priv) -#if CONFIG_MTDRAM_ABS_POS > 0 - iounmap(mtd_info->priv); -#else - vfree(mtd_info->priv); -#endif -#endif - kfree(mtd_info); - } -} - -int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, - unsigned long size, char *name) -{ - memset(mtd, 0, sizeof(*mtd)); - - /* Setup the MTD structure */ - mtd->name = name; - mtd->type = MTD_RAM; - mtd->flags = MTD_CAP_RAM; - mtd->size = size; - mtd->erasesize = MTDRAM_ERASE_SIZE; - mtd->priv = mapped_address; - - mtd->owner = THIS_MODULE; - mtd->erase = ram_erase; - mtd->point = ram_point; - mtd->unpoint = ram_unpoint; - mtd->read = ram_read; - mtd->write = ram_write; - - if (add_mtd_device(mtd)) { - return -EIO; - } - - return 0; -} - -#if CONFIG_MTDRAM_TOTAL_SIZE > 0 -#if CONFIG_MTDRAM_ABS_POS > 0 -static int __init init_mtdram(void) -{ - void *addr; - int err; - /* Allocate some memory */ - mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); - if (!mtd_info) - return -ENOMEM; - - addr = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE); - if (!addr) { - DEBUG(MTD_DEBUG_LEVEL1, - "Failed to ioremap) memory region of size %ld at ABS_POS:%ld\n", - (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS); - kfree(mtd_info); - mtd_info = NULL; - return -ENOMEM; - } - err = mtdram_init_device(mtd_info, addr, - MTDRAM_TOTAL_SIZE, "mtdram test device"); - if (err) - { - iounmap(addr); - kfree(mtd_info); - mtd_info = NULL; - return err; - } - memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); - return err; + if (mtd_info) { + del_mtd_device(mtd_info); + if (mtd_info->priv) + vfree(mtd_info->priv); + kfree(mtd_info); + } } -#else /* CONFIG_MTDRAM_ABS_POS > 0 */ - -static int __init init_mtdram(void) +int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, + unsigned long size, char *name) { - void *addr; - int err; - /* Allocate some memory */ - mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); - if (!mtd_info) - return -ENOMEM; - - addr = vmalloc(MTDRAM_TOTAL_SIZE); - if (!addr) { - DEBUG(MTD_DEBUG_LEVEL1, - "Failed to vmalloc memory region of size %ld\n", - (long)MTDRAM_TOTAL_SIZE); - kfree(mtd_info); - mtd_info = NULL; - return -ENOMEM; - } - err = mtdram_init_device(mtd_info, addr, - MTDRAM_TOTAL_SIZE, "mtdram test device"); - if (err) - { - vfree(addr); - kfree(mtd_info); - mtd_info = NULL; - return err; - } - memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); - return err; + memset(mtd, 0, sizeof(*mtd)); + + /* Setup the MTD structure */ + mtd->name = name; + mtd->type = MTD_RAM; + mtd->flags = MTD_CAP_RAM; + mtd->size = size; + mtd->erasesize = MTDRAM_ERASE_SIZE; + mtd->priv = mapped_address; + + mtd->owner = THIS_MODULE; + mtd->erase = ram_erase; + mtd->point = ram_point; + mtd->unpoint = ram_unpoint; + mtd->read = ram_read; + mtd->write = ram_write; + + if (add_mtd_device(mtd)) { + return -EIO; + } + + return 0; } -#endif /* !(CONFIG_MTDRAM_ABS_POS > 0) */ - -#else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */ static int __init init_mtdram(void) { - return 0; + void *addr; + int err; + + if (!total_size) + return -EINVAL; + + /* Allocate some memory */ + mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); + if (!mtd_info) + return -ENOMEM; + + addr = vmalloc(MTDRAM_TOTAL_SIZE); + if (!addr) { + kfree(mtd_info); + mtd_info = NULL; + return -ENOMEM; + } + err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device"); + if (err) { + vfree(addr); + kfree(mtd_info); + mtd_info = NULL; + return err; + } + memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); + return err; } -#endif /* !(CONFIG_MTDRAM_TOTAL_SIZE > 0) */ module_init(init_mtdram); module_exit(cleanup_mtdram); @@ -232,4 +160,3 @@ module_exit(cleanup_mtdram); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexander Larsson "); MODULE_DESCRIPTION("Simulated MTD driver for testing"); - -- cgit v1.2.3 From c25bb1f59ca6ebbee2649d82533537d4bf123609 Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Wed, 27 Apr 2005 21:01:52 +0100 Subject: [MTD] CFI DEBUG_LOCK_BITS fixes for Intel NOR flash: adjust chip-relative offsets to block address, write to block address + 2 per recent datasheets. Signed-off-by: Todd Poynor Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index b99400f6e48..71fad160144 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.175 2005/04/01 16:36:25 nico Exp $ + * $Id: cfi_cmdset_0001.c,v 1.176 2005/04/27 20:01:49 tpoynor Exp $ * * * 10/10/2000 Nicolas Pitre @@ -1812,8 +1812,9 @@ static int __xipram do_printlockstatus_oneblock(struct map_info *map, struct cfi_private *cfi = map->fldrv_priv; int status, ofs_factor = cfi->interleave * cfi->device_type; + adr += chip->start; xip_disable(map, chip, adr+(2*ofs_factor)); - cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); + map_write(map, CMD(0x90), adr+(2*ofs_factor)); chip->state = FL_JEDEC_QUERY; status = cfi_read_query(map, adr+(2*ofs_factor)); xip_enable(map, chip, 0); -- cgit v1.2.3 From 90e260c84f563a4ac6b47886e8188af06f4a4a46 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 19 May 2005 17:10:26 +0100 Subject: [MTD] NAND: Honour autoplacement schemes supplied by the caller Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index c1a971ca57e..f1db0bf9306 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.142 2005/04/11 14:16:07 lavinen Exp $ + * $Id: nand_base.c,v 1.143 2005/05/19 16:10:22 gleixner Exp $ * * 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 @@ -1195,7 +1195,8 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } /* get oob area, if we have no oob buffer from fs-driver */ - if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE) + if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || + oobsel->useecc == MTD_NANDECC_AUTOPL_USR) oob_data = &this->data_buf[end]; eccsteps = this->eccsteps; @@ -1284,6 +1285,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* without autoplace. Legacy mode used by YAFFS1 */ switch(oobsel->useecc) { case MTD_NANDECC_AUTOPLACE: + case MTD_NANDECC_AUTOPL_USR: /* Walk through the autoplace chunks */ for (i = 0; oobsel->oobfree[i][1]; i++) { int from = oobsel->oobfree[i][0]; @@ -1645,6 +1647,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, oobsel = this->autooob; autoplace = 1; } + if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) + autoplace = 1; /* Setup variables and oob buffer */ totalpages = len >> this->page_shift; @@ -1919,6 +1923,8 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig oobsel = this->autooob; autoplace = 1; } + if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) + autoplace = 1; /* Setup start page */ page = (int) (to >> this->page_shift); -- cgit v1.2.3 From 6da70124a1cc05bdbd7c847901964edc6f634a91 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 19 May 2005 18:05:47 +0100 Subject: [MTD] CFI flash locking reorg for XIP This reworks the XIP locking to make sure no lock primitive is ever called from XIP disabled paths even if in theory they should not cause any reschedule. Relying on the current spinlock implementation is rather fragile and not especially clean from an abstraction pov. The recent RT work makes it even more obvious. Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 90 +++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 71fad160144..8b1304531d8 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.176 2005/04/27 20:01:49 tpoynor Exp $ + * $Id: cfi_cmdset_0001.c,v 1.178 2005/05/19 17:05:43 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -826,10 +826,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad * assembly to make sure inline functions were actually inlined and that gcc * didn't emit calls to its own support functions). Also configuring MTD CFI * support to a single buswidth and a single interleave is also recommended. - * Note that not only IRQs are disabled but the preemption count is also - * increased to prevent other locking primitives (namely spin_unlock) from - * decrementing the preempt count to zero and scheduling the CPU away while - * not in array mode. */ static void xip_disable(struct map_info *map, struct flchip *chip, @@ -837,7 +833,6 @@ static void xip_disable(struct map_info *map, struct flchip *chip, { /* TODO: chips with no XIP use should ignore and return */ (void) map_read(map, adr); /* ensure mmu mapping is up to date */ - preempt_disable(); local_irq_disable(); } @@ -852,7 +847,6 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, (void) map_read(map, adr); asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */ local_irq_enable(); - preempt_enable(); } /* @@ -928,7 +922,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, (void) map_read(map, adr); asm volatile (".rep 8; nop; .endr"); local_irq_enable(); - preempt_enable(); + spin_unlock(chip->mutex); asm volatile (".rep 8; nop; .endr"); cond_resched(); @@ -938,15 +932,15 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, * a suspended erase state. If so let's wait * until it's done. */ - preempt_disable(); + spin_lock(chip->mutex); while (chip->state != newstate) { DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - preempt_enable(); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - preempt_disable(); + spin_lock(chip->mutex); } /* Disallow XIP again */ local_irq_disable(); @@ -975,12 +969,14 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while * the flash is actively programming or erasing since we have to poll for * the operation to complete anyway. We can't do that in a generic way with - * a XIP setup so do it before the actual flash operation in this case. + * a XIP setup so do it before the actual flash operation in this case + * and stub it out from INVALIDATE_CACHE_UDELAY. */ -#undef INVALIDATE_CACHED_RANGE -#define INVALIDATE_CACHED_RANGE(x...) -#define XIP_INVAL_CACHED_RANGE(map, from, size) \ - do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0) +#define XIP_INVAL_CACHED_RANGE(map, from, size) \ + INVALIDATE_CACHED_RANGE(map, from, size) + +#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \ + UDELAY(map, chip, adr, usec) /* * Extra notes: @@ -1003,11 +999,23 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, #define xip_disable(map, chip, adr) #define xip_enable(map, chip, adr) - -#define UDELAY(map, chip, adr, usec) cfi_udelay(usec) - #define XIP_INVAL_CACHED_RANGE(x...) +#define UDELAY(map, chip, adr, usec) \ +do { \ + spin_unlock(chip->mutex); \ + cfi_udelay(usec); \ + spin_lock(chip->mutex); \ +} while (0) + +#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \ +do { \ + spin_unlock(chip->mutex); \ + INVALIDATE_CACHED_RANGE(map, adr, len); \ + cfi_udelay(usec); \ + spin_lock(chip->mutex); \ +} while (0) + #endif static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) @@ -1227,10 +1235,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, map_write(map, datum, adr); chip->state = mode; - spin_unlock(chip->mutex); - INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map)); - UDELAY(map, chip, adr, chip->word_write_time); - spin_lock(chip->mutex); + INVALIDATE_CACHE_UDELAY(map, chip, + adr, map_bankwidth(map), + chip->word_write_time); timeo = jiffies + (HZ/2); z = 0; @@ -1263,10 +1270,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, } /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock(chip->mutex); z++; UDELAY(map, chip, adr, 1); - spin_lock(chip->mutex); } if (!z) { chip->word_write_time--; @@ -1430,9 +1435,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, if (map_word_andequal(map, status, status_OK, status_OK)) break; - spin_unlock(chip->mutex); UDELAY(map, chip, cmd_adr, 1); - spin_lock(chip->mutex); if (++z > 20) { /* Argh. Not ready for write to buffer */ @@ -1478,10 +1481,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, map_write(map, CMD(0xd0), cmd_adr); chip->state = FL_WRITING; - spin_unlock(chip->mutex); - INVALIDATE_CACHED_RANGE(map, adr, len); - UDELAY(map, chip, cmd_adr, chip->buffer_write_time); - spin_lock(chip->mutex); + INVALIDATE_CACHE_UDELAY(map, chip, + cmd_adr, len, + chip->buffer_write_time); timeo = jiffies + (HZ/2); z = 0; @@ -1513,10 +1515,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, } /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock(chip->mutex); - UDELAY(map, chip, cmd_adr, 1); z++; - spin_lock(chip->mutex); + UDELAY(map, chip, cmd_adr, 1); } if (!z) { chip->buffer_write_time--; @@ -1644,10 +1644,9 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->state = FL_ERASING; chip->erase_suspended = 0; - spin_unlock(chip->mutex); - INVALIDATE_CACHED_RANGE(map, adr, len); - UDELAY(map, chip, adr, chip->erase_time*1000/2); - spin_lock(chip->mutex); + INVALIDATE_CACHE_UDELAY(map, chip, + adr, len, + chip->erase_time*1000/2); /* FIXME. Use a timer to check this, and return immediately. */ /* Once the state machine's known to be working I'll do that */ @@ -1692,9 +1691,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, } /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock(chip->mutex); UDELAY(map, chip, adr, 1000000/HZ); - spin_lock(chip->mutex); } /* We've broken this before. It doesn't hurt to be safe */ @@ -1866,11 +1863,8 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip * to delay. */ - if (!extp || !(extp->FeatureSupport & (1 << 5))) { - spin_unlock(chip->mutex); + if (!extp || !(extp->FeatureSupport & (1 << 5))) UDELAY(map, chip, adr, 1000000/HZ); - spin_lock(chip->mutex); - } /* FIXME. Use a timer to check this, and return immediately. */ /* Once the state machine's known to be working I'll do that */ @@ -1897,9 +1891,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip } /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock(chip->mutex); UDELAY(map, chip, adr, 1); - spin_lock(chip->mutex); } /* Done and happy. */ @@ -1979,8 +1971,7 @@ do_otp_read(struct map_info *map, struct flchip *chip, u_long offset, } /* let's ensure we're not reading back cached data from array mode */ - if (map->inval_cache) - map->inval_cache(map, chip->start + offset, size); + INVALIDATE_CACHED_RANGE(map, chip->start + offset, size); xip_disable(map, chip, chip->start); if (chip->state != FL_JEDEC_QUERY) { @@ -1991,8 +1982,7 @@ do_otp_read(struct map_info *map, struct flchip *chip, u_long offset, xip_enable(map, chip, chip->start); /* then ensure we don't keep OTP data in the cache */ - if (map->inval_cache) - map->inval_cache(map, chip->start + offset, size); + INVALIDATE_CACHED_RANGE(map, chip->start + offset, size); put_chip(map, chip, chip->start); spin_unlock(chip->mutex); -- cgit v1.2.3 From fb4a90bfcd6d86e8531073c42fae7fde40974f5d Mon Sep 17 00:00:00 2001 From: "Eric W. Biedermann" Date: Fri, 20 May 2005 04:28:26 +0100 Subject: [MTD] CFI-0002 - Improve error checking Check for errors besides infinite loops when writing and erasing. Signed-off-by: Eric W. Biederman Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0002.c | 99 +++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index fca8ff6f7e1..59849236f52 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -13,7 +13,7 @@ * * This code is GPL * - * $Id: cfi_cmdset_0002.c,v 1.114 2004/12/11 15:43:53 dedekind Exp $ + * $Id: cfi_cmdset_0002.c,v 1.115 2005/05/20 03:28:23 eric Exp $ * */ @@ -43,6 +43,7 @@ #define MANUFACTURER_AMD 0x0001 #define MANUFACTURER_SST 0x00BF #define SST49LF004B 0x0060 +#define SST49LF008A 0x005a static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -191,6 +192,7 @@ static struct cfi_fixup cfi_fixup_table[] = { }; static struct cfi_fixup jedec_fixup_table[] = { { MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, }, + { MANUFACTURER_SST, SST49LF008A, fixup_use_fwh_lock, NULL, }, { 0, 0, NULL, NULL } }; @@ -401,6 +403,32 @@ static int chip_ready(struct map_info *map, unsigned long addr) return map_word_equal(map, d, t); } +/* + * Return true if the chip is ready and has the correct value. + * + * Ready is one of: read mode, query mode, erase-suspend-read mode (in any + * non-suspended sector) and it is indicated by no bits toggling. + * + * Error are indicated by toggling bits or bits held with the wrong value, + * or with bits toggling. + * + * Note that anything more complicated than checking if no bits are toggling + * (including checking DQ5 for an error status) is tricky to get working + * correctly and is therefore not done (particulary with interleaved chips + * as each chip must be checked independantly of the others). + * + */ +static int chip_good(struct map_info *map, unsigned long addr, map_word expected) +{ + map_word oldd, curd; + + oldd = map_read(map, addr); + curd = map_read(map, addr); + + return map_word_equal(map, oldd, curd) && + map_word_equal(map, curd, expected); +} + static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) { DECLARE_WAITQUEUE(wait, current); @@ -765,26 +793,29 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned } if (chip_ready(map, adr)) - goto op_done; + break; - if (time_after(jiffies, timeo)) + if (time_after(jiffies, timeo)) { + printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); break; + } /* Latency issues. Drop the lock, wait a while and retry */ cfi_spin_unlock(chip->mutex); cfi_udelay(1); cfi_spin_lock(chip->mutex); } + /* Did we succeed? */ + if (!chip_good(map, adr, datum)) { + /* reset on all failures. */ + map_write( map, CMD(0xF0), chip->start ); + /* FIXME - should have reset delay before continuing */ - printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); - - /* reset on all failures. */ - map_write( map, CMD(0xF0), chip->start ); - /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_WORD_RETRIES) - goto retry; + if (++retry_cnt <= MAX_WORD_RETRIES) + goto retry; - ret = -EIO; + ret = -EIO; + } op_done: chip->state = FL_READY; put_chip(map, chip, adr); @@ -1187,10 +1218,13 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) } if (chip_ready(map, adr)) - goto op_done; + break; - if (time_after(jiffies, timeo)) + if (time_after(jiffies, timeo)) { + printk(KERN_WARNING "MTD %s(): software timeout\n", + __func__ ); break; + } /* Latency issues. Drop the lock, wait a while and retry */ cfi_spin_unlock(chip->mutex); @@ -1198,16 +1232,15 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) schedule_timeout(1); cfi_spin_lock(chip->mutex); } + /* Did we succeed? */ + if (!chip_good(map, adr, map_word_ff(map))) { + /* reset on all failures. */ + map_write( map, CMD(0xF0), chip->start ); + /* FIXME - should have reset delay before continuing */ - printk(KERN_WARNING "MTD %s(): software timeout\n", - __func__ ); - - /* reset on all failures. */ - map_write( map, CMD(0xF0), chip->start ); - /* FIXME - should have reset delay before continuing */ + ret = -EIO; + } - ret = -EIO; - op_done: chip->state = FL_READY; put_chip(map, chip, adr); cfi_spin_unlock(chip->mutex); @@ -1272,10 +1305,13 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u } if (chip_ready(map, adr)) - goto op_done; + break; - if (time_after(jiffies, timeo)) + if (time_after(jiffies, timeo)) { + printk(KERN_WARNING "MTD %s(): software timeout\n", + __func__ ); break; + } /* Latency issues. Drop the lock, wait a while and retry */ cfi_spin_unlock(chip->mutex); @@ -1283,16 +1319,15 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u schedule_timeout(1); cfi_spin_lock(chip->mutex); } - - printk(KERN_WARNING "MTD %s(): software timeout\n", - __func__ ); - - /* reset on all failures. */ - map_write( map, CMD(0xF0), chip->start ); - /* FIXME - should have reset delay before continuing */ + /* Did we succeed? */ + if (chip_good(map, adr, map_word_ff(map))) { + /* reset on all failures. */ + map_write( map, CMD(0xF0), chip->start ); + /* FIXME - should have reset delay before continuing */ + + ret = -EIO; + } - ret = -EIO; - op_done: chip->state = FL_READY; put_chip(map, chip, adr); cfi_spin_unlock(chip->mutex); -- cgit v1.2.3 From 22fd9a8750bcad4999768aafc8fbd8a4bd6f5aa1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 24 May 2005 15:33:49 +0200 Subject: [MTD] cfi_cmdset_0002: Fix broken status check Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0002.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 59849236f52..49cd8120713 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -13,7 +13,7 @@ * * This code is GPL * - * $Id: cfi_cmdset_0002.c,v 1.115 2005/05/20 03:28:23 eric Exp $ + * $Id: cfi_cmdset_0002.c,v 1.116 2005/05/24 13:29:42 gleixner Exp $ * */ @@ -1320,7 +1320,7 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u cfi_spin_lock(chip->mutex); } /* Did we succeed? */ - if (chip_good(map, adr, map_word_ff(map))) { + if (!chip_good(map, adr, map_word_ff(map))) { /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ -- cgit v1.2.3 From f1f67a9874f1a4bba1adff6d694aa52e5f52ff1a Mon Sep 17 00:00:00 2001 From: "Nicolas S. Dade" Date: Tue, 24 May 2005 01:46:34 -0700 Subject: [MTD] NAND: Add Hynix to manufacturer list Signed-off-by: Nicolas S. Dade Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_ids.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 79945e6ce2b..4b2bfae6f50 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -116,6 +116,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_NATIONAL, "National"}, {NAND_MFR_RENESAS, "Renesas"}, {NAND_MFR_STMICRO, "ST Micro"}, + {NAND_MFR_HYNIX, "Hynix"}, {0x0, "Unknown"} }; -- cgit v1.2.3 From 22f579c621e2f264e6d093b07d75f99bc97d5df2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 28 Jun 2005 22:48:56 +1000 Subject: drm: Add via unichrome support Add DRM device driver for VIA Unichrome chipsets From: Unichrome Project http://unichrome.sf.net, Erdi Chen, Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/char/drm/Kconfig | 7 + drivers/char/drm/Makefile | 2 + drivers/char/drm/drm_pciids.h | 7 + drivers/char/drm/via_3d_reg.h | 1651 +++++++++++++++++++++++++++++++++++++++ drivers/char/drm/via_dma.c | 741 ++++++++++++++++++ drivers/char/drm/via_drm.h | 243 ++++++ drivers/char/drm/via_drv.c | 126 +++ drivers/char/drm/via_drv.h | 118 +++ drivers/char/drm/via_ds.c | 280 +++++++ drivers/char/drm/via_ds.h | 104 +++ drivers/char/drm/via_irq.c | 339 ++++++++ drivers/char/drm/via_map.c | 110 +++ drivers/char/drm/via_mm.c | 358 +++++++++ drivers/char/drm/via_mm.h | 40 + drivers/char/drm/via_verifier.c | 1061 +++++++++++++++++++++++++ drivers/char/drm/via_verifier.h | 61 ++ drivers/char/drm/via_video.c | 97 +++ 17 files changed, 5345 insertions(+) create mode 100644 drivers/char/drm/via_3d_reg.h create mode 100644 drivers/char/drm/via_dma.c create mode 100644 drivers/char/drm/via_drm.h create mode 100644 drivers/char/drm/via_drv.c create mode 100644 drivers/char/drm/via_drv.h create mode 100644 drivers/char/drm/via_ds.c create mode 100644 drivers/char/drm/via_ds.h create mode 100644 drivers/char/drm/via_irq.c create mode 100644 drivers/char/drm/via_map.c create mode 100644 drivers/char/drm/via_mm.c create mode 100644 drivers/char/drm/via_mm.h create mode 100644 drivers/char/drm/via_verifier.c create mode 100644 drivers/char/drm/via_verifier.h create mode 100644 drivers/char/drm/via_video.c (limited to 'drivers') diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig index c2b12eab67c..123417e4304 100644 --- a/drivers/char/drm/Kconfig +++ b/drivers/char/drm/Kconfig @@ -96,3 +96,10 @@ config DRM_SIS chipset. If M is selected the module will be called sis. AGP support is required for this driver to work. +config DRM_VIA + tristate "Via unichrome video cards" + depends on DRM + help + Choose this option if you have a Via unichrome or compatible video + chipset. If M is selected the module will be called via. + diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index 7444dec40b9..8c12254f7ee 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile @@ -18,6 +18,7 @@ i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o ffb-objs := ffb_drv.o ffb_context.o sis-objs := sis_drv.o sis_ds.o sis_mm.o +via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o ifeq ($(CONFIG_COMPAT),y) drm-objs += drm_ioc32.o @@ -35,4 +36,5 @@ obj-$(CONFIG_DRM_I830) += i830.o obj-$(CONFIG_DRM_I915) += i915.o obj-$(CONFIG_DRM_FFB) += ffb.o obj-$(CONFIG_DRM_SIS) += sis.o +obj-$(CONFIG_DRM_VIA) +=via.o diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index 11c6950158b..70ca4fa55c9 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -223,3 +223,10 @@ {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0, 0, 0} +#define viadrv_PCI_IDS \ + {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0, 0, 0} + diff --git a/drivers/char/drm/via_3d_reg.h b/drivers/char/drm/via_3d_reg.h new file mode 100644 index 00000000000..cf61bb514db --- /dev/null +++ b/drivers/char/drm/via_3d_reg.h @@ -0,0 +1,1651 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. 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 + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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. + */ + +#ifndef VIA_3D_REG_H +#define VIA_3D_REG_H +#define HC_REG_BASE 0x0400 + +#define HC_REG_TRANS_SPACE 0x0040 + +#define HC_ParaN_MASK 0xffffffff +#define HC_Para_MASK 0x00ffffff +#define HC_SubA_MASK 0xff000000 +#define HC_SubA_SHIFT 24 +/* Transmission Setting + */ +#define HC_REG_TRANS_SET 0x003c +#define HC_ParaSubType_MASK 0xff000000 +#define HC_ParaType_MASK 0x00ff0000 +#define HC_ParaOS_MASK 0x0000ff00 +#define HC_ParaAdr_MASK 0x000000ff +#define HC_ParaSubType_SHIFT 24 +#define HC_ParaType_SHIFT 16 +#define HC_ParaOS_SHIFT 8 +#define HC_ParaAdr_SHIFT 0 + +#define HC_ParaType_CmdVdata 0x0000 +#define HC_ParaType_NotTex 0x0001 +#define HC_ParaType_Tex 0x0002 +#define HC_ParaType_Palette 0x0003 +#define HC_ParaType_PreCR 0x0010 +#define HC_ParaType_Auto 0x00fe + +/* Transmission Space + */ +#define HC_REG_Hpara0 0x0040 +#define HC_REG_HpataAF 0x02fc + +/* Read + */ +#define HC_REG_HREngSt 0x0000 +#define HC_REG_HRFIFOempty 0x0004 +#define HC_REG_HRFIFOfull 0x0008 +#define HC_REG_HRErr 0x000c +#define HC_REG_FIFOstatus 0x0010 +/* HC_REG_HREngSt 0x0000 + */ +#define HC_HDASZC_MASK 0x00010000 +#define HC_HSGEMI_MASK 0x0000f000 +#define HC_HLGEMISt_MASK 0x00000f00 +#define HC_HCRSt_MASK 0x00000080 +#define HC_HSE0St_MASK 0x00000040 +#define HC_HSE1St_MASK 0x00000020 +#define HC_HPESt_MASK 0x00000010 +#define HC_HXESt_MASK 0x00000008 +#define HC_HBESt_MASK 0x00000004 +#define HC_HE2St_MASK 0x00000002 +#define HC_HE3St_MASK 0x00000001 +/* HC_REG_HRFIFOempty 0x0004 + */ +#define HC_HRZDempty_MASK 0x00000010 +#define HC_HRTXAempty_MASK 0x00000008 +#define HC_HRTXDempty_MASK 0x00000004 +#define HC_HWZDempty_MASK 0x00000002 +#define HC_HWCDempty_MASK 0x00000001 +/* HC_REG_HRFIFOfull 0x0008 + */ +#define HC_HRZDfull_MASK 0x00000010 +#define HC_HRTXAfull_MASK 0x00000008 +#define HC_HRTXDfull_MASK 0x00000004 +#define HC_HWZDfull_MASK 0x00000002 +#define HC_HWCDfull_MASK 0x00000001 +/* HC_REG_HRErr 0x000c + */ +#define HC_HAGPCMErr_MASK 0x80000000 +#define HC_HAGPCMErrC_MASK 0x70000000 +/* HC_REG_FIFOstatus 0x0010 + */ +#define HC_HRFIFOATall_MASK 0x80000000 +#define HC_HRFIFOATbusy_MASK 0x40000000 +#define HC_HRATFGMDo_MASK 0x00000100 +#define HC_HRATFGMDi_MASK 0x00000080 +#define HC_HRATFRZD_MASK 0x00000040 +#define HC_HRATFRTXA_MASK 0x00000020 +#define HC_HRATFRTXD_MASK 0x00000010 +#define HC_HRATFWZD_MASK 0x00000008 +#define HC_HRATFWCD_MASK 0x00000004 +#define HC_HRATTXTAG_MASK 0x00000002 +#define HC_HRATTXCH_MASK 0x00000001 + +/* AGP Command Setting + */ +#define HC_SubA_HAGPBstL 0x0060 +#define HC_SubA_HAGPBendL 0x0061 +#define HC_SubA_HAGPCMNT 0x0062 +#define HC_SubA_HAGPBpL 0x0063 +#define HC_SubA_HAGPBpH 0x0064 +/* HC_SubA_HAGPCMNT 0x0062 + */ +#define HC_HAGPCMNT_MASK 0x00800000 +#define HC_HCmdErrClr_MASK 0x00400000 +#define HC_HAGPBendH_MASK 0x0000ff00 +#define HC_HAGPBstH_MASK 0x000000ff +#define HC_HAGPBendH_SHIFT 8 +#define HC_HAGPBstH_SHIFT 0 +/* HC_SubA_HAGPBpL 0x0063 + */ +#define HC_HAGPBpL_MASK 0x00fffffc +#define HC_HAGPBpID_MASK 0x00000003 +#define HC_HAGPBpID_PAUSE 0x00000000 +#define HC_HAGPBpID_JUMP 0x00000001 +#define HC_HAGPBpID_STOP 0x00000002 +/* HC_SubA_HAGPBpH 0x0064 + */ +#define HC_HAGPBpH_MASK 0x00ffffff + +/* Miscellaneous Settings + */ +#define HC_SubA_HClipTB 0x0070 +#define HC_SubA_HClipLR 0x0071 +#define HC_SubA_HFPClipTL 0x0072 +#define HC_SubA_HFPClipBL 0x0073 +#define HC_SubA_HFPClipLL 0x0074 +#define HC_SubA_HFPClipRL 0x0075 +#define HC_SubA_HFPClipTBH 0x0076 +#define HC_SubA_HFPClipLRH 0x0077 +#define HC_SubA_HLP 0x0078 +#define HC_SubA_HLPRF 0x0079 +#define HC_SubA_HSolidCL 0x007a +#define HC_SubA_HPixGC 0x007b +#define HC_SubA_HSPXYOS 0x007c +#define HC_SubA_HVertexCNT 0x007d + +#define HC_HClipT_MASK 0x00fff000 +#define HC_HClipT_SHIFT 12 +#define HC_HClipB_MASK 0x00000fff +#define HC_HClipB_SHIFT 0 +#define HC_HClipL_MASK 0x00fff000 +#define HC_HClipL_SHIFT 12 +#define HC_HClipR_MASK 0x00000fff +#define HC_HClipR_SHIFT 0 +#define HC_HFPClipBH_MASK 0x0000ff00 +#define HC_HFPClipBH_SHIFT 8 +#define HC_HFPClipTH_MASK 0x000000ff +#define HC_HFPClipTH_SHIFT 0 +#define HC_HFPClipRH_MASK 0x0000ff00 +#define HC_HFPClipRH_SHIFT 8 +#define HC_HFPClipLH_MASK 0x000000ff +#define HC_HFPClipLH_SHIFT 0 +#define HC_HSolidCH_MASK 0x000000ff +#define HC_HPixGC_MASK 0x00800000 +#define HC_HSPXOS_MASK 0x00fff000 +#define HC_HSPXOS_SHIFT 12 +#define HC_HSPYOS_MASK 0x00000fff + +/* Command + * Command A + */ +#define HC_HCmdHeader_MASK 0xfe000000 /*0xffe00000 */ +#define HC_HE3Fire_MASK 0x00100000 +#define HC_HPMType_MASK 0x000f0000 +#define HC_HEFlag_MASK 0x0000e000 +#define HC_HShading_MASK 0x00001c00 +#define HC_HPMValidN_MASK 0x00000200 +#define HC_HPLEND_MASK 0x00000100 +#define HC_HVCycle_MASK 0x000000ff +#define HC_HVCycle_Style_MASK 0x000000c0 +#define HC_HVCycle_ChgA_MASK 0x00000030 +#define HC_HVCycle_ChgB_MASK 0x0000000c +#define HC_HVCycle_ChgC_MASK 0x00000003 +#define HC_HPMType_Point 0x00000000 +#define HC_HPMType_Line 0x00010000 +#define HC_HPMType_Tri 0x00020000 +#define HC_HPMType_TriWF 0x00040000 +#define HC_HEFlag_NoAA 0x00000000 +#define HC_HEFlag_ab 0x00008000 +#define HC_HEFlag_bc 0x00004000 +#define HC_HEFlag_ca 0x00002000 +#define HC_HShading_Solid 0x00000000 +#define HC_HShading_FlatA 0x00000400 +#define HC_HShading_FlatB 0x00000800 +#define HC_HShading_FlatC 0x00000c00 +#define HC_HShading_Gouraud 0x00001000 +#define HC_HVCycle_Full 0x00000000 +#define HC_HVCycle_AFP 0x00000040 +#define HC_HVCycle_One 0x000000c0 +#define HC_HVCycle_NewA 0x00000000 +#define HC_HVCycle_AA 0x00000010 +#define HC_HVCycle_AB 0x00000020 +#define HC_HVCycle_AC 0x00000030 +#define HC_HVCycle_NewB 0x00000000 +#define HC_HVCycle_BA 0x00000004 +#define HC_HVCycle_BB 0x00000008 +#define HC_HVCycle_BC 0x0000000c +#define HC_HVCycle_NewC 0x00000000 +#define HC_HVCycle_CA 0x00000001 +#define HC_HVCycle_CB 0x00000002 +#define HC_HVCycle_CC 0x00000003 + +/* Command B + */ +#define HC_HLPrst_MASK 0x00010000 +#define HC_HLLastP_MASK 0x00008000 +#define HC_HVPMSK_MASK 0x00007f80 +#define HC_HBFace_MASK 0x00000040 +#define HC_H2nd1VT_MASK 0x0000003f +#define HC_HVPMSK_X 0x00004000 +#define HC_HVPMSK_Y 0x00002000 +#define HC_HVPMSK_Z 0x00001000 +#define HC_HVPMSK_W 0x00000800 +#define HC_HVPMSK_Cd 0x00000400 +#define HC_HVPMSK_Cs 0x00000200 +#define HC_HVPMSK_S 0x00000100 +#define HC_HVPMSK_T 0x00000080 + +/* Enable Setting + */ +#define HC_SubA_HEnable 0x0000 +#define HC_HenTXEnvMap_MASK 0x00200000 +#define HC_HenVertexCNT_MASK 0x00100000 +#define HC_HenCPUDAZ_MASK 0x00080000 +#define HC_HenDASZWC_MASK 0x00040000 +#define HC_HenFBCull_MASK 0x00020000 +#define HC_HenCW_MASK 0x00010000 +#define HC_HenAA_MASK 0x00008000 +#define HC_HenST_MASK 0x00004000 +#define HC_HenZT_MASK 0x00002000 +#define HC_HenZW_MASK 0x00001000 +#define HC_HenAT_MASK 0x00000800 +#define HC_HenAW_MASK 0x00000400 +#define HC_HenSP_MASK 0x00000200 +#define HC_HenLP_MASK 0x00000100 +#define HC_HenTXCH_MASK 0x00000080 +#define HC_HenTXMP_MASK 0x00000040 +#define HC_HenTXPP_MASK 0x00000020 +#define HC_HenTXTR_MASK 0x00000010 +#define HC_HenCS_MASK 0x00000008 +#define HC_HenFOG_MASK 0x00000004 +#define HC_HenABL_MASK 0x00000002 +#define HC_HenDT_MASK 0x00000001 + +/* Z Setting + */ +#define HC_SubA_HZWBBasL 0x0010 +#define HC_SubA_HZWBBasH 0x0011 +#define HC_SubA_HZWBType 0x0012 +#define HC_SubA_HZBiasL 0x0013 +#define HC_SubA_HZWBend 0x0014 +#define HC_SubA_HZWTMD 0x0015 +#define HC_SubA_HZWCDL 0x0016 +#define HC_SubA_HZWCTAGnum 0x0017 +#define HC_SubA_HZCYNum 0x0018 +#define HC_SubA_HZWCFire 0x0019 +/* HC_SubA_HZWBType + */ +#define HC_HZWBType_MASK 0x00800000 +#define HC_HZBiasedWB_MASK 0x00400000 +#define HC_HZONEasFF_MASK 0x00200000 +#define HC_HZOONEasFF_MASK 0x00100000 +#define HC_HZWBFM_MASK 0x00030000 +#define HC_HZWBLoc_MASK 0x0000c000 +#define HC_HZWBPit_MASK 0x00003fff +#define HC_HZWBFM_16 0x00000000 +#define HC_HZWBFM_32 0x00020000 +#define HC_HZWBFM_24 0x00030000 +#define HC_HZWBLoc_Local 0x00000000 +#define HC_HZWBLoc_SyS 0x00004000 +/* HC_SubA_HZWBend + */ +#define HC_HZWBend_MASK 0x00ffe000 +#define HC_HZBiasH_MASK 0x000000ff +#define HC_HZWBend_SHIFT 10 +/* HC_SubA_HZWTMD + */ +#define HC_HZWTMD_MASK 0x00070000 +#define HC_HEBEBias_MASK 0x00007f00 +#define HC_HZNF_MASK 0x000000ff +#define HC_HZWTMD_NeverPass 0x00000000 +#define HC_HZWTMD_LT 0x00010000 +#define HC_HZWTMD_EQ 0x00020000 +#define HC_HZWTMD_LE 0x00030000 +#define HC_HZWTMD_GT 0x00040000 +#define HC_HZWTMD_NE 0x00050000 +#define HC_HZWTMD_GE 0x00060000 +#define HC_HZWTMD_AllPass 0x00070000 +#define HC_HEBEBias_SHIFT 8 +/* HC_SubA_HZWCDL 0x0016 + */ +#define HC_HZWCDL_MASK 0x00ffffff +/* HC_SubA_HZWCTAGnum 0x0017 + */ +#define HC_HZWCTAGnum_MASK 0x00ff0000 +#define HC_HZWCTAGnum_SHIFT 16 +#define HC_HZWCDH_MASK 0x000000ff +#define HC_HZWCDH_SHIFT 0 +/* HC_SubA_HZCYNum 0x0018 + */ +#define HC_HZCYNum_MASK 0x00030000 +#define HC_HZCYNum_SHIFT 16 +#define HC_HZWCQWnum_MASK 0x00003fff +#define HC_HZWCQWnum_SHIFT 0 +/* HC_SubA_HZWCFire 0x0019 + */ +#define HC_ZWCFire_MASK 0x00010000 +#define HC_HZWCQWnumLast_MASK 0x00003fff +#define HC_HZWCQWnumLast_SHIFT 0 + +/* Stencil Setting + */ +#define HC_SubA_HSTREF 0x0023 +#define HC_SubA_HSTMD 0x0024 +/* HC_SubA_HSBFM + */ +#define HC_HSBFM_MASK 0x00030000 +#define HC_HSBLoc_MASK 0x0000c000 +#define HC_HSBPit_MASK 0x00003fff +/* HC_SubA_HSTREF + */ +#define HC_HSTREF_MASK 0x00ff0000 +#define HC_HSTOPMSK_MASK 0x0000ff00 +#define HC_HSTBMSK_MASK 0x000000ff +#define HC_HSTREF_SHIFT 16 +#define HC_HSTOPMSK_SHIFT 8 +/* HC_SubA_HSTMD + */ +#define HC_HSTMD_MASK 0x00070000 +#define HC_HSTOPSF_MASK 0x000001c0 +#define HC_HSTOPSPZF_MASK 0x00000038 +#define HC_HSTOPSPZP_MASK 0x00000007 +#define HC_HSTMD_NeverPass 0x00000000 +#define HC_HSTMD_LT 0x00010000 +#define HC_HSTMD_EQ 0x00020000 +#define HC_HSTMD_LE 0x00030000 +#define HC_HSTMD_GT 0x00040000 +#define HC_HSTMD_NE 0x00050000 +#define HC_HSTMD_GE 0x00060000 +#define HC_HSTMD_AllPass 0x00070000 +#define HC_HSTOPSF_KEEP 0x00000000 +#define HC_HSTOPSF_ZERO 0x00000040 +#define HC_HSTOPSF_REPLACE 0x00000080 +#define HC_HSTOPSF_INCRSAT 0x000000c0 +#define HC_HSTOPSF_DECRSAT 0x00000100 +#define HC_HSTOPSF_INVERT 0x00000140 +#define HC_HSTOPSF_INCR 0x00000180 +#define HC_HSTOPSF_DECR 0x000001c0 +#define HC_HSTOPSPZF_KEEP 0x00000000 +#define HC_HSTOPSPZF_ZERO 0x00000008 +#define HC_HSTOPSPZF_REPLACE 0x00000010 +#define HC_HSTOPSPZF_INCRSAT 0x00000018 +#define HC_HSTOPSPZF_DECRSAT 0x00000020 +#define HC_HSTOPSPZF_INVERT 0x00000028 +#define HC_HSTOPSPZF_INCR 0x00000030 +#define HC_HSTOPSPZF_DECR 0x00000038 +#define HC_HSTOPSPZP_KEEP 0x00000000 +#define HC_HSTOPSPZP_ZERO 0x00000001 +#define HC_HSTOPSPZP_REPLACE 0x00000002 +#define HC_HSTOPSPZP_INCRSAT 0x00000003 +#define HC_HSTOPSPZP_DECRSAT 0x00000004 +#define HC_HSTOPSPZP_INVERT 0x00000005 +#define HC_HSTOPSPZP_INCR 0x00000006 +#define HC_HSTOPSPZP_DECR 0x00000007 + +/* Alpha Setting + */ +#define HC_SubA_HABBasL 0x0030 +#define HC_SubA_HABBasH 0x0031 +#define HC_SubA_HABFM 0x0032 +#define HC_SubA_HATMD 0x0033 +#define HC_SubA_HABLCsat 0x0034 +#define HC_SubA_HABLCop 0x0035 +#define HC_SubA_HABLAsat 0x0036 +#define HC_SubA_HABLAop 0x0037 +#define HC_SubA_HABLRCa 0x0038 +#define HC_SubA_HABLRFCa 0x0039 +#define HC_SubA_HABLRCbias 0x003a +#define HC_SubA_HABLRCb 0x003b +#define HC_SubA_HABLRFCb 0x003c +#define HC_SubA_HABLRAa 0x003d +#define HC_SubA_HABLRAb 0x003e +/* HC_SubA_HABFM + */ +#define HC_HABFM_MASK 0x00030000 +#define HC_HABLoc_MASK 0x0000c000 +#define HC_HABPit_MASK 0x000007ff +/* HC_SubA_HATMD + */ +#define HC_HATMD_MASK 0x00000700 +#define HC_HATREF_MASK 0x000000ff +#define HC_HATMD_NeverPass 0x00000000 +#define HC_HATMD_LT 0x00000100 +#define HC_HATMD_EQ 0x00000200 +#define HC_HATMD_LE 0x00000300 +#define HC_HATMD_GT 0x00000400 +#define HC_HATMD_NE 0x00000500 +#define HC_HATMD_GE 0x00000600 +#define HC_HATMD_AllPass 0x00000700 +/* HC_SubA_HABLCsat + */ +#define HC_HABLCsat_MASK 0x00010000 +#define HC_HABLCa_MASK 0x0000fc00 +#define HC_HABLCa_C_MASK 0x0000c000 +#define HC_HABLCa_OPC_MASK 0x00003c00 +#define HC_HABLFCa_MASK 0x000003f0 +#define HC_HABLFCa_C_MASK 0x00000300 +#define HC_HABLFCa_OPC_MASK 0x000000f0 +#define HC_HABLCbias_MASK 0x0000000f +#define HC_HABLCbias_C_MASK 0x00000008 +#define HC_HABLCbias_OPC_MASK 0x00000007 +/*-- Define the input color. + */ +#define HC_XC_Csrc 0x00000000 +#define HC_XC_Cdst 0x00000001 +#define HC_XC_Asrc 0x00000002 +#define HC_XC_Adst 0x00000003 +#define HC_XC_Fog 0x00000004 +#define HC_XC_HABLRC 0x00000005 +#define HC_XC_minSrcDst 0x00000006 +#define HC_XC_maxSrcDst 0x00000007 +#define HC_XC_mimAsrcInvAdst 0x00000008 +#define HC_XC_OPC 0x00000000 +#define HC_XC_InvOPC 0x00000010 +#define HC_XC_OPCp5 0x00000020 +/*-- Define the input Alpha + */ +#define HC_XA_OPA 0x00000000 +#define HC_XA_InvOPA 0x00000010 +#define HC_XA_OPAp5 0x00000020 +#define HC_XA_0 0x00000000 +#define HC_XA_Asrc 0x00000001 +#define HC_XA_Adst 0x00000002 +#define HC_XA_Fog 0x00000003 +#define HC_XA_minAsrcFog 0x00000004 +#define HC_XA_minAsrcAdst 0x00000005 +#define HC_XA_maxAsrcFog 0x00000006 +#define HC_XA_maxAsrcAdst 0x00000007 +#define HC_XA_HABLRA 0x00000008 +#define HC_XA_minAsrcInvAdst 0x00000008 +#define HC_XA_HABLFRA 0x00000009 +/*-- + */ +#define HC_HABLCa_OPC (HC_XC_OPC << 10) +#define HC_HABLCa_InvOPC (HC_XC_InvOPC << 10) +#define HC_HABLCa_OPCp5 (HC_XC_OPCp5 << 10) +#define HC_HABLCa_Csrc (HC_XC_Csrc << 10) +#define HC_HABLCa_Cdst (HC_XC_Cdst << 10) +#define HC_HABLCa_Asrc (HC_XC_Asrc << 10) +#define HC_HABLCa_Adst (HC_XC_Adst << 10) +#define HC_HABLCa_Fog (HC_XC_Fog << 10) +#define HC_HABLCa_HABLRCa (HC_XC_HABLRC << 10) +#define HC_HABLCa_minSrcDst (HC_XC_minSrcDst << 10) +#define HC_HABLCa_maxSrcDst (HC_XC_maxSrcDst << 10) +#define HC_HABLFCa_OPC (HC_XC_OPC << 4) +#define HC_HABLFCa_InvOPC (HC_XC_InvOPC << 4) +#define HC_HABLFCa_OPCp5 (HC_XC_OPCp5 << 4) +#define HC_HABLFCa_Csrc (HC_XC_Csrc << 4) +#define HC_HABLFCa_Cdst (HC_XC_Cdst << 4) +#define HC_HABLFCa_Asrc (HC_XC_Asrc << 4) +#define HC_HABLFCa_Adst (HC_XC_Adst << 4) +#define HC_HABLFCa_Fog (HC_XC_Fog << 4) +#define HC_HABLFCa_HABLRCa (HC_XC_HABLRC << 4) +#define HC_HABLFCa_minSrcDst (HC_XC_minSrcDst << 4) +#define HC_HABLFCa_maxSrcDst (HC_XC_maxSrcDst << 4) +#define HC_HABLFCa_mimAsrcInvAdst (HC_XC_mimAsrcInvAdst << 4) +#define HC_HABLCbias_HABLRCbias 0x00000000 +#define HC_HABLCbias_Asrc 0x00000001 +#define HC_HABLCbias_Adst 0x00000002 +#define HC_HABLCbias_Fog 0x00000003 +#define HC_HABLCbias_Cin 0x00000004 +/* HC_SubA_HABLCop 0x0035 + */ +#define HC_HABLdot_MASK 0x00010000 +#define HC_HABLCop_MASK 0x00004000 +#define HC_HABLCb_MASK 0x00003f00 +#define HC_HABLCb_C_MASK 0x00003000 +#define HC_HABLCb_OPC_MASK 0x00000f00 +#define HC_HABLFCb_MASK 0x000000fc +#define HC_HABLFCb_C_MASK 0x000000c0 +#define HC_HABLFCb_OPC_MASK 0x0000003c +#define HC_HABLCshift_MASK 0x00000003 +#define HC_HABLCb_OPC (HC_XC_OPC << 8) +#define HC_HABLCb_InvOPC (HC_XC_InvOPC << 8) +#define HC_HABLCb_OPCp5 (HC_XC_OPCp5 << 8) +#define HC_HABLCb_Csrc (HC_XC_Csrc << 8) +#define HC_HABLCb_Cdst (HC_XC_Cdst << 8) +#define HC_HABLCb_Asrc (HC_XC_Asrc << 8) +#define HC_HABLCb_Adst (HC_XC_Adst << 8) +#define HC_HABLCb_Fog (HC_XC_Fog << 8) +#define HC_HABLCb_HABLRCa (HC_XC_HABLRC << 8) +#define HC_HABLCb_minSrcDst (HC_XC_minSrcDst << 8) +#define HC_HABLCb_maxSrcDst (HC_XC_maxSrcDst << 8) +#define HC_HABLFCb_OPC (HC_XC_OPC << 2) +#define HC_HABLFCb_InvOPC (HC_XC_InvOPC << 2) +#define HC_HABLFCb_OPCp5 (HC_XC_OPCp5 << 2) +#define HC_HABLFCb_Csrc (HC_XC_Csrc << 2) +#define HC_HABLFCb_Cdst (HC_XC_Cdst << 2) +#define HC_HABLFCb_Asrc (HC_XC_Asrc << 2) +#define HC_HABLFCb_Adst (HC_XC_Adst << 2) +#define HC_HABLFCb_Fog (HC_XC_Fog << 2) +#define HC_HABLFCb_HABLRCb (HC_XC_HABLRC << 2) +#define HC_HABLFCb_minSrcDst (HC_XC_minSrcDst << 2) +#define HC_HABLFCb_maxSrcDst (HC_XC_maxSrcDst << 2) +#define HC_HABLFCb_mimAsrcInvAdst (HC_XC_mimAsrcInvAdst << 2) +/* HC_SubA_HABLAsat 0x0036 + */ +#define HC_HABLAsat_MASK 0x00010000 +#define HC_HABLAa_MASK 0x0000fc00 +#define HC_HABLAa_A_MASK 0x0000c000 +#define HC_HABLAa_OPA_MASK 0x00003c00 +#define HC_HABLFAa_MASK 0x000003f0 +#define HC_HABLFAa_A_MASK 0x00000300 +#define HC_HABLFAa_OPA_MASK 0x000000f0 +#define HC_HABLAbias_MASK 0x0000000f +#define HC_HABLAbias_A_MASK 0x00000008 +#define HC_HABLAbias_OPA_MASK 0x00000007 +#define HC_HABLAa_OPA (HC_XA_OPA << 10) +#define HC_HABLAa_InvOPA (HC_XA_InvOPA << 10) +#define HC_HABLAa_OPAp5 (HC_XA_OPAp5 << 10) +#define HC_HABLAa_0 (HC_XA_0 << 10) +#define HC_HABLAa_Asrc (HC_XA_Asrc << 10) +#define HC_HABLAa_Adst (HC_XA_Adst << 10) +#define HC_HABLAa_Fog (HC_XA_Fog << 10) +#define HC_HABLAa_minAsrcFog (HC_XA_minAsrcFog << 10) +#define HC_HABLAa_minAsrcAdst (HC_XA_minAsrcAdst << 10) +#define HC_HABLAa_maxAsrcFog (HC_XA_maxAsrcFog << 10) +#define HC_HABLAa_maxAsrcAdst (HC_XA_maxAsrcAdst << 10) +#define HC_HABLAa_HABLRA (HC_XA_HABLRA << 10) +#define HC_HABLFAa_OPA (HC_XA_OPA << 4) +#define HC_HABLFAa_InvOPA (HC_XA_InvOPA << 4) +#define HC_HABLFAa_OPAp5 (HC_XA_OPAp5 << 4) +#define HC_HABLFAa_0 (HC_XA_0 << 4) +#define HC_HABLFAa_Asrc (HC_XA_Asrc << 4) +#define HC_HABLFAa_Adst (HC_XA_Adst << 4) +#define HC_HABLFAa_Fog (HC_XA_Fog << 4) +#define HC_HABLFAa_minAsrcFog (HC_XA_minAsrcFog << 4) +#define HC_HABLFAa_minAsrcAdst (HC_XA_minAsrcAdst << 4) +#define HC_HABLFAa_maxAsrcFog (HC_XA_maxAsrcFog << 4) +#define HC_HABLFAa_maxAsrcAdst (HC_XA_maxAsrcAdst << 4) +#define HC_HABLFAa_minAsrcInvAdst (HC_XA_minAsrcInvAdst << 4) +#define HC_HABLFAa_HABLFRA (HC_XA_HABLFRA << 4) +#define HC_HABLAbias_HABLRAbias 0x00000000 +#define HC_HABLAbias_Asrc 0x00000001 +#define HC_HABLAbias_Adst 0x00000002 +#define HC_HABLAbias_Fog 0x00000003 +#define HC_HABLAbias_Aaa 0x00000004 +/* HC_SubA_HABLAop 0x0037 + */ +#define HC_HABLAop_MASK 0x00004000 +#define HC_HABLAb_MASK 0x00003f00 +#define HC_HABLAb_OPA_MASK 0x00000f00 +#define HC_HABLFAb_MASK 0x000000fc +#define HC_HABLFAb_OPA_MASK 0x0000003c +#define HC_HABLAshift_MASK 0x00000003 +#define HC_HABLAb_OPA (HC_XA_OPA << 8) +#define HC_HABLAb_InvOPA (HC_XA_InvOPA << 8) +#define HC_HABLAb_OPAp5 (HC_XA_OPAp5 << 8) +#define HC_HABLAb_0 (HC_XA_0 << 8) +#define HC_HABLAb_Asrc (HC_XA_Asrc << 8) +#define HC_HABLAb_Adst (HC_XA_Adst << 8) +#define HC_HABLAb_Fog (HC_XA_Fog << 8) +#define HC_HABLAb_minAsrcFog (HC_XA_minAsrcFog << 8) +#define HC_HABLAb_minAsrcAdst (HC_XA_minAsrcAdst << 8) +#define HC_HABLAb_maxAsrcFog (HC_XA_maxAsrcFog << 8) +#define HC_HABLAb_maxAsrcAdst (HC_XA_maxAsrcAdst << 8) +#define HC_HABLAb_HABLRA (HC_XA_HABLRA << 8) +#define HC_HABLFAb_OPA (HC_XA_OPA << 2) +#define HC_HABLFAb_InvOPA (HC_XA_InvOPA << 2) +#define HC_HABLFAb_OPAp5 (HC_XA_OPAp5 << 2) +#define HC_HABLFAb_0 (HC_XA_0 << 2) +#define HC_HABLFAb_Asrc (HC_XA_Asrc << 2) +#define HC_HABLFAb_Adst (HC_XA_Adst << 2) +#define HC_HABLFAb_Fog (HC_XA_Fog << 2) +#define HC_HABLFAb_minAsrcFog (HC_XA_minAsrcFog << 2) +#define HC_HABLFAb_minAsrcAdst (HC_XA_minAsrcAdst << 2) +#define HC_HABLFAb_maxAsrcFog (HC_XA_maxAsrcFog << 2) +#define HC_HABLFAb_maxAsrcAdst (HC_XA_maxAsrcAdst << 2) +#define HC_HABLFAb_minAsrcInvAdst (HC_XA_minAsrcInvAdst << 2) +#define HC_HABLFAb_HABLFRA (HC_XA_HABLFRA << 2) +/* HC_SubA_HABLRAa 0x003d + */ +#define HC_HABLRAa_MASK 0x00ff0000 +#define HC_HABLRFAa_MASK 0x0000ff00 +#define HC_HABLRAbias_MASK 0x000000ff +#define HC_HABLRAa_SHIFT 16 +#define HC_HABLRFAa_SHIFT 8 +/* HC_SubA_HABLRAb 0x003e + */ +#define HC_HABLRAb_MASK 0x0000ff00 +#define HC_HABLRFAb_MASK 0x000000ff +#define HC_HABLRAb_SHIFT 8 + +/* Destination Setting + */ +#define HC_SubA_HDBBasL 0x0040 +#define HC_SubA_HDBBasH 0x0041 +#define HC_SubA_HDBFM 0x0042 +#define HC_SubA_HFBBMSKL 0x0043 +#define HC_SubA_HROP 0x0044 +/* HC_SubA_HDBFM 0x0042 + */ +#define HC_HDBFM_MASK 0x001f0000 +#define HC_HDBLoc_MASK 0x0000c000 +#define HC_HDBPit_MASK 0x00003fff +#define HC_HDBFM_RGB555 0x00000000 +#define HC_HDBFM_RGB565 0x00010000 +#define HC_HDBFM_ARGB4444 0x00020000 +#define HC_HDBFM_ARGB1555 0x00030000 +#define HC_HDBFM_BGR555 0x00040000 +#define HC_HDBFM_BGR565 0x00050000 +#define HC_HDBFM_ABGR4444 0x00060000 +#define HC_HDBFM_ABGR1555 0x00070000 +#define HC_HDBFM_ARGB0888 0x00080000 +#define HC_HDBFM_ARGB8888 0x00090000 +#define HC_HDBFM_ABGR0888 0x000a0000 +#define HC_HDBFM_ABGR8888 0x000b0000 +#define HC_HDBLoc_Local 0x00000000 +#define HC_HDBLoc_Sys 0x00004000 +/* HC_SubA_HROP 0x0044 + */ +#define HC_HROP_MASK 0x00000f00 +#define HC_HFBBMSKH_MASK 0x000000ff +#define HC_HROP_BLACK 0x00000000 +#define HC_HROP_DPon 0x00000100 +#define HC_HROP_DPna 0x00000200 +#define HC_HROP_Pn 0x00000300 +#define HC_HROP_PDna 0x00000400 +#define HC_HROP_Dn 0x00000500 +#define HC_HROP_DPx 0x00000600 +#define HC_HROP_DPan 0x00000700 +#define HC_HROP_DPa 0x00000800 +#define HC_HROP_DPxn 0x00000900 +#define HC_HROP_D 0x00000a00 +#define HC_HROP_DPno 0x00000b00 +#define HC_HROP_P 0x00000c00 +#define HC_HROP_PDno 0x00000d00 +#define HC_HROP_DPo 0x00000e00 +#define HC_HROP_WHITE 0x00000f00 + +/* Fog Setting + */ +#define HC_SubA_HFogLF 0x0050 +#define HC_SubA_HFogCL 0x0051 +#define HC_SubA_HFogCH 0x0052 +#define HC_SubA_HFogStL 0x0053 +#define HC_SubA_HFogStH 0x0054 +#define HC_SubA_HFogOOdMF 0x0055 +#define HC_SubA_HFogOOdEF 0x0056 +#define HC_SubA_HFogEndL 0x0057 +#define HC_SubA_HFogDenst 0x0058 +/* HC_SubA_FogLF 0x0050 + */ +#define HC_FogLF_MASK 0x00000010 +#define HC_FogEq_MASK 0x00000008 +#define HC_FogMD_MASK 0x00000007 +#define HC_FogMD_LocalFog 0x00000000 +#define HC_FogMD_LinearFog 0x00000002 +#define HC_FogMD_ExponentialFog 0x00000004 +#define HC_FogMD_Exponential2Fog 0x00000005 +/* #define HC_FogMD_FogTable 0x00000003 */ + +/* HC_SubA_HFogDenst 0x0058 + */ +#define HC_FogDenst_MASK 0x001fff00 +#define HC_FogEndL_MASK 0x000000ff + +/* Texture subtype definitions + */ +#define HC_SubType_Tex0 0x00000000 +#define HC_SubType_Tex1 0x00000001 +#define HC_SubType_TexGeneral 0x000000fe + +/* Attribute of texture n + */ +#define HC_SubA_HTXnL0BasL 0x0000 +#define HC_SubA_HTXnL1BasL 0x0001 +#define HC_SubA_HTXnL2BasL 0x0002 +#define HC_SubA_HTXnL3BasL 0x0003 +#define HC_SubA_HTXnL4BasL 0x0004 +#define HC_SubA_HTXnL5BasL 0x0005 +#define HC_SubA_HTXnL6BasL 0x0006 +#define HC_SubA_HTXnL7BasL 0x0007 +#define HC_SubA_HTXnL8BasL 0x0008 +#define HC_SubA_HTXnL9BasL 0x0009 +#define HC_SubA_HTXnLaBasL 0x000a +#define HC_SubA_HTXnLbBasL 0x000b +#define HC_SubA_HTXnLcBasL 0x000c +#define HC_SubA_HTXnLdBasL 0x000d +#define HC_SubA_HTXnLeBasL 0x000e +#define HC_SubA_HTXnLfBasL 0x000f +#define HC_SubA_HTXnL10BasL 0x0010 +#define HC_SubA_HTXnL11BasL 0x0011 +#define HC_SubA_HTXnL012BasH 0x0020 +#define HC_SubA_HTXnL345BasH 0x0021 +#define HC_SubA_HTXnL678BasH 0x0022 +#define HC_SubA_HTXnL9abBasH 0x0023 +#define HC_SubA_HTXnLcdeBasH 0x0024 +#define HC_SubA_HTXnLf1011BasH 0x0025 +#define HC_SubA_HTXnL0Pit 0x002b +#define HC_SubA_HTXnL1Pit 0x002c +#define HC_SubA_HTXnL2Pit 0x002d +#define HC_SubA_HTXnL3Pit 0x002e +#define HC_SubA_HTXnL4Pit 0x002f +#define HC_SubA_HTXnL5Pit 0x0030 +#define HC_SubA_HTXnL6Pit 0x0031 +#define HC_SubA_HTXnL7Pit 0x0032 +#define HC_SubA_HTXnL8Pit 0x0033 +#define HC_SubA_HTXnL9Pit 0x0034 +#define HC_SubA_HTXnLaPit 0x0035 +#define HC_SubA_HTXnLbPit 0x0036 +#define HC_SubA_HTXnLcPit 0x0037 +#define HC_SubA_HTXnLdPit 0x0038 +#define HC_SubA_HTXnLePit 0x0039 +#define HC_SubA_HTXnLfPit 0x003a +#define HC_SubA_HTXnL10Pit 0x003b +#define HC_SubA_HTXnL11Pit 0x003c +#define HC_SubA_HTXnL0_5WE 0x004b +#define HC_SubA_HTXnL6_bWE 0x004c +#define HC_SubA_HTXnLc_11WE 0x004d +#define HC_SubA_HTXnL0_5HE 0x0051 +#define HC_SubA_HTXnL6_bHE 0x0052 +#define HC_SubA_HTXnLc_11HE 0x0053 +#define HC_SubA_HTXnL0OS 0x0077 +#define HC_SubA_HTXnTB 0x0078 +#define HC_SubA_HTXnMPMD 0x0079 +#define HC_SubA_HTXnCLODu 0x007a +#define HC_SubA_HTXnFM 0x007b +#define HC_SubA_HTXnTRCH 0x007c +#define HC_SubA_HTXnTRCL 0x007d +#define HC_SubA_HTXnTBC 0x007e +#define HC_SubA_HTXnTRAH 0x007f +#define HC_SubA_HTXnTBLCsat 0x0080 +#define HC_SubA_HTXnTBLCop 0x0081 +#define HC_SubA_HTXnTBLMPfog 0x0082 +#define HC_SubA_HTXnTBLAsat 0x0083 +#define HC_SubA_HTXnTBLRCa 0x0085 +#define HC_SubA_HTXnTBLRCb 0x0086 +#define HC_SubA_HTXnTBLRCc 0x0087 +#define HC_SubA_HTXnTBLRCbias 0x0088 +#define HC_SubA_HTXnTBLRAa 0x0089 +#define HC_SubA_HTXnTBLRFog 0x008a +#define HC_SubA_HTXnBumpM00 0x0090 +#define HC_SubA_HTXnBumpM01 0x0091 +#define HC_SubA_HTXnBumpM10 0x0092 +#define HC_SubA_HTXnBumpM11 0x0093 +#define HC_SubA_HTXnLScale 0x0094 +#define HC_SubA_HTXSMD 0x0000 +/* HC_SubA_HTXnL012BasH 0x0020 + */ +#define HC_HTXnL0BasH_MASK 0x000000ff +#define HC_HTXnL1BasH_MASK 0x0000ff00 +#define HC_HTXnL2BasH_MASK 0x00ff0000 +#define HC_HTXnL1BasH_SHIFT 8 +#define HC_HTXnL2BasH_SHIFT 16 +/* HC_SubA_HTXnL345BasH 0x0021 + */ +#define HC_HTXnL3BasH_MASK 0x000000ff +#define HC_HTXnL4BasH_MASK 0x0000ff00 +#define HC_HTXnL5BasH_MASK 0x00ff0000 +#define HC_HTXnL4BasH_SHIFT 8 +#define HC_HTXnL5BasH_SHIFT 16 +/* HC_SubA_HTXnL678BasH 0x0022 + */ +#define HC_HTXnL6BasH_MASK 0x000000ff +#define HC_HTXnL7BasH_MASK 0x0000ff00 +#define HC_HTXnL8BasH_MASK 0x00ff0000 +#define HC_HTXnL7BasH_SHIFT 8 +#define HC_HTXnL8BasH_SHIFT 16 +/* HC_SubA_HTXnL9abBasH 0x0023 + */ +#define HC_HTXnL9BasH_MASK 0x000000ff +#define HC_HTXnLaBasH_MASK 0x0000ff00 +#define HC_HTXnLbBasH_MASK 0x00ff0000 +#define HC_HTXnLaBasH_SHIFT 8 +#define HC_HTXnLbBasH_SHIFT 16 +/* HC_SubA_HTXnLcdeBasH 0x0024 + */ +#define HC_HTXnLcBasH_MASK 0x000000ff +#define HC_HTXnLdBasH_MASK 0x0000ff00 +#define HC_HTXnLeBasH_MASK 0x00ff0000 +#define HC_HTXnLdBasH_SHIFT 8 +#define HC_HTXnLeBasH_SHIFT 16 +/* HC_SubA_HTXnLcdeBasH 0x0025 + */ +#define HC_HTXnLfBasH_MASK 0x000000ff +#define HC_HTXnL10BasH_MASK 0x0000ff00 +#define HC_HTXnL11BasH_MASK 0x00ff0000 +#define HC_HTXnL10BasH_SHIFT 8 +#define HC_HTXnL11BasH_SHIFT 16 +/* HC_SubA_HTXnL0Pit 0x002b + */ +#define HC_HTXnLnPit_MASK 0x00003fff +#define HC_HTXnEnPit_MASK 0x00080000 +#define HC_HTXnLnPitE_MASK 0x00f00000 +#define HC_HTXnLnPitE_SHIFT 20 +/* HC_SubA_HTXnL0_5WE 0x004b + */ +#define HC_HTXnL0WE_MASK 0x0000000f +#define HC_HTXnL1WE_MASK 0x000000f0 +#define HC_HTXnL2WE_MASK 0x00000f00 +#define HC_HTXnL3WE_MASK 0x0000f000 +#define HC_HTXnL4WE_MASK 0x000f0000 +#define HC_HTXnL5WE_MASK 0x00f00000 +#define HC_HTXnL1WE_SHIFT 4 +#define HC_HTXnL2WE_SHIFT 8 +#define HC_HTXnL3WE_SHIFT 12 +#define HC_HTXnL4WE_SHIFT 16 +#define HC_HTXnL5WE_SHIFT 20 +/* HC_SubA_HTXnL6_bWE 0x004c + */ +#define HC_HTXnL6WE_MASK 0x0000000f +#define HC_HTXnL7WE_MASK 0x000000f0 +#define HC_HTXnL8WE_MASK 0x00000f00 +#define HC_HTXnL9WE_MASK 0x0000f000 +#define HC_HTXnLaWE_MASK 0x000f0000 +#define HC_HTXnLbWE_MASK 0x00f00000 +#define HC_HTXnL7WE_SHIFT 4 +#define HC_HTXnL8WE_SHIFT 8 +#define HC_HTXnL9WE_SHIFT 12 +#define HC_HTXnLaWE_SHIFT 16 +#define HC_HTXnLbWE_SHIFT 20 +/* HC_SubA_HTXnLc_11WE 0x004d + */ +#define HC_HTXnLcWE_MASK 0x0000000f +#define HC_HTXnLdWE_MASK 0x000000f0 +#define HC_HTXnLeWE_MASK 0x00000f00 +#define HC_HTXnLfWE_MASK 0x0000f000 +#define HC_HTXnL10WE_MASK 0x000f0000 +#define HC_HTXnL11WE_MASK 0x00f00000 +#define HC_HTXnLdWE_SHIFT 4 +#define HC_HTXnLeWE_SHIFT 8 +#define HC_HTXnLfWE_SHIFT 12 +#define HC_HTXnL10WE_SHIFT 16 +#define HC_HTXnL11WE_SHIFT 20 +/* HC_SubA_HTXnL0_5HE 0x0051 + */ +#define HC_HTXnL0HE_MASK 0x0000000f +#define HC_HTXnL1HE_MASK 0x000000f0 +#define HC_HTXnL2HE_MASK 0x00000f00 +#define HC_HTXnL3HE_MASK 0x0000f000 +#define HC_HTXnL4HE_MASK 0x000f0000 +#define HC_HTXnL5HE_MASK 0x00f00000 +#define HC_HTXnL1HE_SHIFT 4 +#define HC_HTXnL2HE_SHIFT 8 +#define HC_HTXnL3HE_SHIFT 12 +#define HC_HTXnL4HE_SHIFT 16 +#define HC_HTXnL5HE_SHIFT 20 +/* HC_SubA_HTXnL6_bHE 0x0052 + */ +#define HC_HTXnL6HE_MASK 0x0000000f +#define HC_HTXnL7HE_MASK 0x000000f0 +#define HC_HTXnL8HE_MASK 0x00000f00 +#define HC_HTXnL9HE_MASK 0x0000f000 +#define HC_HTXnLaHE_MASK 0x000f0000 +#define HC_HTXnLbHE_MASK 0x00f00000 +#define HC_HTXnL7HE_SHIFT 4 +#define HC_HTXnL8HE_SHIFT 8 +#define HC_HTXnL9HE_SHIFT 12 +#define HC_HTXnLaHE_SHIFT 16 +#define HC_HTXnLbHE_SHIFT 20 +/* HC_SubA_HTXnLc_11HE 0x0053 + */ +#define HC_HTXnLcHE_MASK 0x0000000f +#define HC_HTXnLdHE_MASK 0x000000f0 +#define HC_HTXnLeHE_MASK 0x00000f00 +#define HC_HTXnLfHE_MASK 0x0000f000 +#define HC_HTXnL10HE_MASK 0x000f0000 +#define HC_HTXnL11HE_MASK 0x00f00000 +#define HC_HTXnLdHE_SHIFT 4 +#define HC_HTXnLeHE_SHIFT 8 +#define HC_HTXnLfHE_SHIFT 12 +#define HC_HTXnL10HE_SHIFT 16 +#define HC_HTXnL11HE_SHIFT 20 +/* HC_SubA_HTXnL0OS 0x0077 + */ +#define HC_HTXnL0OS_MASK 0x003ff000 +#define HC_HTXnLVmax_MASK 0x00000fc0 +#define HC_HTXnLVmin_MASK 0x0000003f +#define HC_HTXnL0OS_SHIFT 12 +#define HC_HTXnLVmax_SHIFT 6 +/* HC_SubA_HTXnTB 0x0078 + */ +#define HC_HTXnTB_MASK 0x00f00000 +#define HC_HTXnFLSe_MASK 0x0000e000 +#define HC_HTXnFLSs_MASK 0x00001c00 +#define HC_HTXnFLTe_MASK 0x00000380 +#define HC_HTXnFLTs_MASK 0x00000070 +#define HC_HTXnFLDs_MASK 0x0000000f +#define HC_HTXnTB_NoTB 0x00000000 +#define HC_HTXnTB_TBC_S 0x00100000 +#define HC_HTXnTB_TBC_T 0x00200000 +#define HC_HTXnTB_TB_S 0x00400000 +#define HC_HTXnTB_TB_T 0x00800000 +#define HC_HTXnFLSe_Nearest 0x00000000 +#define HC_HTXnFLSe_Linear 0x00002000 +#define HC_HTXnFLSe_NonLinear 0x00004000 +#define HC_HTXnFLSe_Sharp 0x00008000 +#define HC_HTXnFLSe_Flat_Gaussian_Cubic 0x0000c000 +#define HC_HTXnFLSs_Nearest 0x00000000 +#define HC_HTXnFLSs_Linear 0x00000400 +#define HC_HTXnFLSs_NonLinear 0x00000800 +#define HC_HTXnFLSs_Flat_Gaussian_Cubic 0x00001800 +#define HC_HTXnFLTe_Nearest 0x00000000 +#define HC_HTXnFLTe_Linear 0x00000080 +#define HC_HTXnFLTe_NonLinear 0x00000100 +#define HC_HTXnFLTe_Sharp 0x00000180 +#define HC_HTXnFLTe_Flat_Gaussian_Cubic 0x00000300 +#define HC_HTXnFLTs_Nearest 0x00000000 +#define HC_HTXnFLTs_Linear 0x00000010 +#define HC_HTXnFLTs_NonLinear 0x00000020 +#define HC_HTXnFLTs_Flat_Gaussian_Cubic 0x00000060 +#define HC_HTXnFLDs_Tex0 0x00000000 +#define HC_HTXnFLDs_Nearest 0x00000001 +#define HC_HTXnFLDs_Linear 0x00000002 +#define HC_HTXnFLDs_NonLinear 0x00000003 +#define HC_HTXnFLDs_Dither 0x00000004 +#define HC_HTXnFLDs_ConstLOD 0x00000005 +#define HC_HTXnFLDs_Ani 0x00000006 +#define HC_HTXnFLDs_AniDither 0x00000007 +/* HC_SubA_HTXnMPMD 0x0079 + */ +#define HC_HTXnMPMD_SMASK 0x00070000 +#define HC_HTXnMPMD_TMASK 0x00380000 +#define HC_HTXnLODDTf_MASK 0x00000007 +#define HC_HTXnXY2ST_MASK 0x00000008 +#define HC_HTXnMPMD_Tsingle 0x00000000 +#define HC_HTXnMPMD_Tclamp 0x00080000 +#define HC_HTXnMPMD_Trepeat 0x00100000 +#define HC_HTXnMPMD_Tmirror 0x00180000 +#define HC_HTXnMPMD_Twrap 0x00200000 +#define HC_HTXnMPMD_Ssingle 0x00000000 +#define HC_HTXnMPMD_Sclamp 0x00010000 +#define HC_HTXnMPMD_Srepeat 0x00020000 +#define HC_HTXnMPMD_Smirror 0x00030000 +#define HC_HTXnMPMD_Swrap 0x00040000 +/* HC_SubA_HTXnCLODu 0x007a + */ +#define HC_HTXnCLODu_MASK 0x000ffc00 +#define HC_HTXnCLODd_MASK 0x000003ff +#define HC_HTXnCLODu_SHIFT 10 +/* HC_SubA_HTXnFM 0x007b + */ +#define HC_HTXnFM_MASK 0x00ff0000 +#define HC_HTXnLoc_MASK 0x00000003 +#define HC_HTXnFM_INDEX 0x00000000 +#define HC_HTXnFM_Intensity 0x00080000 +#define HC_HTXnFM_Lum 0x00100000 +#define HC_HTXnFM_Alpha 0x00180000 +#define HC_HTXnFM_DX 0x00280000 +#define HC_HTXnFM_ARGB16 0x00880000 +#define HC_HTXnFM_ARGB32 0x00980000 +#define HC_HTXnFM_ABGR16 0x00a80000 +#define HC_HTXnFM_ABGR32 0x00b80000 +#define HC_HTXnFM_RGBA16 0x00c80000 +#define HC_HTXnFM_RGBA32 0x00d80000 +#define HC_HTXnFM_BGRA16 0x00e80000 +#define HC_HTXnFM_BGRA32 0x00f80000 +#define HC_HTXnFM_BUMPMAP 0x00380000 +#define HC_HTXnFM_Index1 (HC_HTXnFM_INDEX | 0x00000000) +#define HC_HTXnFM_Index2 (HC_HTXnFM_INDEX | 0x00010000) +#define HC_HTXnFM_Index4 (HC_HTXnFM_INDEX | 0x00020000) +#define HC_HTXnFM_Index8 (HC_HTXnFM_INDEX | 0x00030000) +#define HC_HTXnFM_T1 (HC_HTXnFM_Intensity | 0x00000000) +#define HC_HTXnFM_T2 (HC_HTXnFM_Intensity | 0x00010000) +#define HC_HTXnFM_T4 (HC_HTXnFM_Intensity | 0x00020000) +#define HC_HTXnFM_T8 (HC_HTXnFM_Intensity | 0x00030000) +#define HC_HTXnFM_L1 (HC_HTXnFM_Lum | 0x00000000) +#define HC_HTXnFM_L2 (HC_HTXnFM_Lum | 0x00010000) +#define HC_HTXnFM_L4 (HC_HTXnFM_Lum | 0x00020000) +#define HC_HTXnFM_L8 (HC_HTXnFM_Lum | 0x00030000) +#define HC_HTXnFM_AL44 (HC_HTXnFM_Lum | 0x00040000) +#define HC_HTXnFM_AL88 (HC_HTXnFM_Lum | 0x00050000) +#define HC_HTXnFM_A1 (HC_HTXnFM_Alpha | 0x00000000) +#define HC_HTXnFM_A2 (HC_HTXnFM_Alpha | 0x00010000) +#define HC_HTXnFM_A4 (HC_HTXnFM_Alpha | 0x00020000) +#define HC_HTXnFM_A8 (HC_HTXnFM_Alpha | 0x00030000) +#define HC_HTXnFM_DX1 (HC_HTXnFM_DX | 0x00010000) +#define HC_HTXnFM_DX23 (HC_HTXnFM_DX | 0x00020000) +#define HC_HTXnFM_DX45 (HC_HTXnFM_DX | 0x00030000) +#define HC_HTXnFM_RGB555 (HC_HTXnFM_ARGB16 | 0x00000000) +#define HC_HTXnFM_RGB565 (HC_HTXnFM_ARGB16 | 0x00010000) +#define HC_HTXnFM_ARGB1555 (HC_HTXnFM_ARGB16 | 0x00020000) +#define HC_HTXnFM_ARGB4444 (HC_HTXnFM_ARGB16 | 0x00030000) +#define HC_HTXnFM_ARGB0888 (HC_HTXnFM_ARGB32 | 0x00000000) +#define HC_HTXnFM_ARGB8888 (HC_HTXnFM_ARGB32 | 0x00010000) +#define HC_HTXnFM_BGR555 (HC_HTXnFM_ABGR16 | 0x00000000) +#define HC_HTXnFM_BGR565 (HC_HTXnFM_ABGR16 | 0x00010000) +#define HC_HTXnFM_ABGR1555 (HC_HTXnFM_ABGR16 | 0x00020000) +#define HC_HTXnFM_ABGR4444 (HC_HTXnFM_ABGR16 | 0x00030000) +#define HC_HTXnFM_ABGR0888 (HC_HTXnFM_ABGR32 | 0x00000000) +#define HC_HTXnFM_ABGR8888 (HC_HTXnFM_ABGR32 | 0x00010000) +#define HC_HTXnFM_RGBA5550 (HC_HTXnFM_RGBA16 | 0x00000000) +#define HC_HTXnFM_RGBA5551 (HC_HTXnFM_RGBA16 | 0x00020000) +#define HC_HTXnFM_RGBA4444 (HC_HTXnFM_RGBA16 | 0x00030000) +#define HC_HTXnFM_RGBA8880 (HC_HTXnFM_RGBA32 | 0x00000000) +#define HC_HTXnFM_RGBA8888 (HC_HTXnFM_RGBA32 | 0x00010000) +#define HC_HTXnFM_BGRA5550 (HC_HTXnFM_BGRA16 | 0x00000000) +#define HC_HTXnFM_BGRA5551 (HC_HTXnFM_BGRA16 | 0x00020000) +#define HC_HTXnFM_BGRA4444 (HC_HTXnFM_BGRA16 | 0x00030000) +#define HC_HTXnFM_BGRA8880 (HC_HTXnFM_BGRA32 | 0x00000000) +#define HC_HTXnFM_BGRA8888 (HC_HTXnFM_BGRA32 | 0x00010000) +#define HC_HTXnFM_VU88 (HC_HTXnFM_BUMPMAP | 0x00000000) +#define HC_HTXnFM_LVU655 (HC_HTXnFM_BUMPMAP | 0x00010000) +#define HC_HTXnFM_LVU888 (HC_HTXnFM_BUMPMAP | 0x00020000) +#define HC_HTXnLoc_Local 0x00000000 +#define HC_HTXnLoc_Sys 0x00000002 +#define HC_HTXnLoc_AGP 0x00000003 +/* HC_SubA_HTXnTRAH 0x007f + */ +#define HC_HTXnTRAH_MASK 0x00ff0000 +#define HC_HTXnTRAL_MASK 0x0000ff00 +#define HC_HTXnTBA_MASK 0x000000ff +#define HC_HTXnTRAH_SHIFT 16 +#define HC_HTXnTRAL_SHIFT 8 +/* HC_SubA_HTXnTBLCsat 0x0080 + *-- Define the input texture. + */ +#define HC_XTC_TOPC 0x00000000 +#define HC_XTC_InvTOPC 0x00000010 +#define HC_XTC_TOPCp5 0x00000020 +#define HC_XTC_Cbias 0x00000000 +#define HC_XTC_InvCbias 0x00000010 +#define HC_XTC_0 0x00000000 +#define HC_XTC_Dif 0x00000001 +#define HC_XTC_Spec 0x00000002 +#define HC_XTC_Tex 0x00000003 +#define HC_XTC_Cur 0x00000004 +#define HC_XTC_Adif 0x00000005 +#define HC_XTC_Fog 0x00000006 +#define HC_XTC_Atex 0x00000007 +#define HC_XTC_Acur 0x00000008 +#define HC_XTC_HTXnTBLRC 0x00000009 +#define HC_XTC_Ctexnext 0x0000000a +/*-- + */ +#define HC_HTXnTBLCsat_MASK 0x00800000 +#define HC_HTXnTBLCa_MASK 0x000fc000 +#define HC_HTXnTBLCb_MASK 0x00001f80 +#define HC_HTXnTBLCc_MASK 0x0000003f +#define HC_HTXnTBLCa_TOPC (HC_XTC_TOPC << 14) +#define HC_HTXnTBLCa_InvTOPC (HC_XTC_InvTOPC << 14) +#define HC_HTXnTBLCa_TOPCp5 (HC_XTC_TOPCp5 << 14) +#define HC_HTXnTBLCa_0 (HC_XTC_0 << 14) +#define HC_HTXnTBLCa_Dif (HC_XTC_Dif << 14) +#define HC_HTXnTBLCa_Spec (HC_XTC_Spec << 14) +#define HC_HTXnTBLCa_Tex (HC_XTC_Tex << 14) +#define HC_HTXnTBLCa_Cur (HC_XTC_Cur << 14) +#define HC_HTXnTBLCa_Adif (HC_XTC_Adif << 14) +#define HC_HTXnTBLCa_Fog (HC_XTC_Fog << 14) +#define HC_HTXnTBLCa_Atex (HC_XTC_Atex << 14) +#define HC_HTXnTBLCa_Acur (HC_XTC_Acur << 14) +#define HC_HTXnTBLCa_HTXnTBLRC (HC_XTC_HTXnTBLRC << 14) +#define HC_HTXnTBLCa_Ctexnext (HC_XTC_Ctexnext << 14) +#define HC_HTXnTBLCb_TOPC (HC_XTC_TOPC << 7) +#define HC_HTXnTBLCb_InvTOPC (HC_XTC_InvTOPC << 7) +#define HC_HTXnTBLCb_TOPCp5 (HC_XTC_TOPCp5 << 7) +#define HC_HTXnTBLCb_0 (HC_XTC_0 << 7) +#define HC_HTXnTBLCb_Dif (HC_XTC_Dif << 7) +#define HC_HTXnTBLCb_Spec (HC_XTC_Spec << 7) +#define HC_HTXnTBLCb_Tex (HC_XTC_Tex << 7) +#define HC_HTXnTBLCb_Cur (HC_XTC_Cur << 7) +#define HC_HTXnTBLCb_Adif (HC_XTC_Adif << 7) +#define HC_HTXnTBLCb_Fog (HC_XTC_Fog << 7) +#define HC_HTXnTBLCb_Atex (HC_XTC_Atex << 7) +#define HC_HTXnTBLCb_Acur (HC_XTC_Acur << 7) +#define HC_HTXnTBLCb_HTXnTBLRC (HC_XTC_HTXnTBLRC << 7) +#define HC_HTXnTBLCb_Ctexnext (HC_XTC_Ctexnext << 7) +#define HC_HTXnTBLCc_TOPC (HC_XTC_TOPC << 0) +#define HC_HTXnTBLCc_InvTOPC (HC_XTC_InvTOPC << 0) +#define HC_HTXnTBLCc_TOPCp5 (HC_XTC_TOPCp5 << 0) +#define HC_HTXnTBLCc_0 (HC_XTC_0 << 0) +#define HC_HTXnTBLCc_Dif (HC_XTC_Dif << 0) +#define HC_HTXnTBLCc_Spec (HC_XTC_Spec << 0) +#define HC_HTXnTBLCc_Tex (HC_XTC_Tex << 0) +#define HC_HTXnTBLCc_Cur (HC_XTC_Cur << 0) +#define HC_HTXnTBLCc_Adif (HC_XTC_Adif << 0) +#define HC_HTXnTBLCc_Fog (HC_XTC_Fog << 0) +#define HC_HTXnTBLCc_Atex (HC_XTC_Atex << 0) +#define HC_HTXnTBLCc_Acur (HC_XTC_Acur << 0) +#define HC_HTXnTBLCc_HTXnTBLRC (HC_XTC_HTXnTBLRC << 0) +#define HC_HTXnTBLCc_Ctexnext (HC_XTC_Ctexnext << 0) +/* HC_SubA_HTXnTBLCop 0x0081 + */ +#define HC_HTXnTBLdot_MASK 0x00c00000 +#define HC_HTXnTBLCop_MASK 0x00380000 +#define HC_HTXnTBLCbias_MASK 0x0007c000 +#define HC_HTXnTBLCshift_MASK 0x00001800 +#define HC_HTXnTBLAop_MASK 0x00000380 +#define HC_HTXnTBLAbias_MASK 0x00000078 +#define HC_HTXnTBLAshift_MASK 0x00000003 +#define HC_HTXnTBLCop_Add 0x00000000 +#define HC_HTXnTBLCop_Sub 0x00080000 +#define HC_HTXnTBLCop_Min 0x00100000 +#define HC_HTXnTBLCop_Max 0x00180000 +#define HC_HTXnTBLCop_Mask 0x00200000 +#define HC_HTXnTBLCbias_Cbias (HC_XTC_Cbias << 14) +#define HC_HTXnTBLCbias_InvCbias (HC_XTC_InvCbias << 14) +#define HC_HTXnTBLCbias_0 (HC_XTC_0 << 14) +#define HC_HTXnTBLCbias_Dif (HC_XTC_Dif << 14) +#define HC_HTXnTBLCbias_Spec (HC_XTC_Spec << 14) +#define HC_HTXnTBLCbias_Tex (HC_XTC_Tex << 14) +#define HC_HTXnTBLCbias_Cur (HC_XTC_Cur << 14) +#define HC_HTXnTBLCbias_Adif (HC_XTC_Adif << 14) +#define HC_HTXnTBLCbias_Fog (HC_XTC_Fog << 14) +#define HC_HTXnTBLCbias_Atex (HC_XTC_Atex << 14) +#define HC_HTXnTBLCbias_Acur (HC_XTC_Acur << 14) +#define HC_HTXnTBLCbias_HTXnTBLRC (HC_XTC_HTXnTBLRC << 14) +#define HC_HTXnTBLCshift_1 0x00000000 +#define HC_HTXnTBLCshift_2 0x00000800 +#define HC_HTXnTBLCshift_No 0x00001000 +#define HC_HTXnTBLCshift_DotP 0x00001800 +/*=* John Sheng [2003.7.18] texture combine *=*/ +#define HC_HTXnTBLDOT3 0x00080000 +#define HC_HTXnTBLDOT4 0x000C0000 + +#define HC_HTXnTBLAop_Add 0x00000000 +#define HC_HTXnTBLAop_Sub 0x00000080 +#define HC_HTXnTBLAop_Min 0x00000100 +#define HC_HTXnTBLAop_Max 0x00000180 +#define HC_HTXnTBLAop_Mask 0x00000200 +#define HC_HTXnTBLAbias_Inv 0x00000040 +#define HC_HTXnTBLAbias_Adif 0x00000000 +#define HC_HTXnTBLAbias_Fog 0x00000008 +#define HC_HTXnTBLAbias_Acur 0x00000010 +#define HC_HTXnTBLAbias_HTXnTBLRAbias 0x00000018 +#define HC_HTXnTBLAbias_Atex 0x00000020 +#define HC_HTXnTBLAshift_1 0x00000000 +#define HC_HTXnTBLAshift_2 0x00000001 +#define HC_HTXnTBLAshift_No 0x00000002 +/* #define HC_HTXnTBLAshift_DotP 0x00000003 */ +/* HC_SubA_HTXnTBLMPFog 0x0082 + */ +#define HC_HTXnTBLMPfog_MASK 0x00e00000 +#define HC_HTXnTBLMPfog_0 0x00000000 +#define HC_HTXnTBLMPfog_Adif 0x00200000 +#define HC_HTXnTBLMPfog_Fog 0x00400000 +#define HC_HTXnTBLMPfog_Atex 0x00600000 +#define HC_HTXnTBLMPfog_Acur 0x00800000 +#define HC_HTXnTBLMPfog_GHTXnTBLRFog 0x00a00000 +/* HC_SubA_HTXnTBLAsat 0x0083 + *-- Define the texture alpha input. + */ +#define HC_XTA_TOPA 0x00000000 +#define HC_XTA_InvTOPA 0x00000008 +#define HC_XTA_TOPAp5 0x00000010 +#define HC_XTA_Adif 0x00000000 +#define HC_XTA_Fog 0x00000001 +#define HC_XTA_Acur 0x00000002 +#define HC_XTA_HTXnTBLRA 0x00000003 +#define HC_XTA_Atex 0x00000004 +#define HC_XTA_Atexnext 0x00000005 +/*-- + */ +#define HC_HTXnTBLAsat_MASK 0x00800000 +#define HC_HTXnTBLAMB_MASK 0x00700000 +#define HC_HTXnTBLAa_MASK 0x0007c000 +#define HC_HTXnTBLAb_MASK 0x00000f80 +#define HC_HTXnTBLAc_MASK 0x0000001f +#define HC_HTXnTBLAMB_SHIFT 20 +#define HC_HTXnTBLAa_TOPA (HC_XTA_TOPA << 14) +#define HC_HTXnTBLAa_InvTOPA (HC_XTA_InvTOPA << 14) +#define HC_HTXnTBLAa_TOPAp5 (HC_XTA_TOPAp5 << 14) +#define HC_HTXnTBLAa_Adif (HC_XTA_Adif << 14) +#define HC_HTXnTBLAa_Fog (HC_XTA_Fog << 14) +#define HC_HTXnTBLAa_Acur (HC_XTA_Acur << 14) +#define HC_HTXnTBLAa_HTXnTBLRA (HC_XTA_HTXnTBLRA << 14) +#define HC_HTXnTBLAa_Atex (HC_XTA_Atex << 14) +#define HC_HTXnTBLAa_Atexnext (HC_XTA_Atexnext << 14) +#define HC_HTXnTBLAb_TOPA (HC_XTA_TOPA << 7) +#define HC_HTXnTBLAb_InvTOPA (HC_XTA_InvTOPA << 7) +#define HC_HTXnTBLAb_TOPAp5 (HC_XTA_TOPAp5 << 7) +#define HC_HTXnTBLAb_Adif (HC_XTA_Adif << 7) +#define HC_HTXnTBLAb_Fog (HC_XTA_Fog << 7) +#define HC_HTXnTBLAb_Acur (HC_XTA_Acur << 7) +#define HC_HTXnTBLAb_HTXnTBLRA (HC_XTA_HTXnTBLRA << 7) +#define HC_HTXnTBLAb_Atex (HC_XTA_Atex << 7) +#define HC_HTXnTBLAb_Atexnext (HC_XTA_Atexnext << 7) +#define HC_HTXnTBLAc_TOPA (HC_XTA_TOPA << 0) +#define HC_HTXnTBLAc_InvTOPA (HC_XTA_InvTOPA << 0) +#define HC_HTXnTBLAc_TOPAp5 (HC_XTA_TOPAp5 << 0) +#define HC_HTXnTBLAc_Adif (HC_XTA_Adif << 0) +#define HC_HTXnTBLAc_Fog (HC_XTA_Fog << 0) +#define HC_HTXnTBLAc_Acur (HC_XTA_Acur << 0) +#define HC_HTXnTBLAc_HTXnTBLRA (HC_XTA_HTXnTBLRA << 0) +#define HC_HTXnTBLAc_Atex (HC_XTA_Atex << 0) +#define HC_HTXnTBLAc_Atexnext (HC_XTA_Atexnext << 0) +/* HC_SubA_HTXnTBLRAa 0x0089 + */ +#define HC_HTXnTBLRAa_MASK 0x00ff0000 +#define HC_HTXnTBLRAb_MASK 0x0000ff00 +#define HC_HTXnTBLRAc_MASK 0x000000ff +#define HC_HTXnTBLRAa_SHIFT 16 +#define HC_HTXnTBLRAb_SHIFT 8 +#define HC_HTXnTBLRAc_SHIFT 0 +/* HC_SubA_HTXnTBLRFog 0x008a + */ +#define HC_HTXnTBLRFog_MASK 0x0000ff00 +#define HC_HTXnTBLRAbias_MASK 0x000000ff +#define HC_HTXnTBLRFog_SHIFT 8 +#define HC_HTXnTBLRAbias_SHIFT 0 +/* HC_SubA_HTXnLScale 0x0094 + */ +#define HC_HTXnLScale_MASK 0x0007fc00 +#define HC_HTXnLOff_MASK 0x000001ff +#define HC_HTXnLScale_SHIFT 10 +/* HC_SubA_HTXSMD 0x0000 + */ +#define HC_HTXSMD_MASK 0x00000080 +#define HC_HTXTMD_MASK 0x00000040 +#define HC_HTXNum_MASK 0x00000038 +#define HC_HTXTRMD_MASK 0x00000006 +#define HC_HTXCHCLR_MASK 0x00000001 +#define HC_HTXNum_SHIFT 3 + +/* Texture Palette n + */ +#define HC_SubType_TexPalette0 0x00000000 +#define HC_SubType_TexPalette1 0x00000001 +#define HC_SubType_FogTable 0x00000010 +#define HC_SubType_Stipple 0x00000014 +/* HC_SubA_TexPalette0 0x0000 + */ +#define HC_HTPnA_MASK 0xff000000 +#define HC_HTPnR_MASK 0x00ff0000 +#define HC_HTPnG_MASK 0x0000ff00 +#define HC_HTPnB_MASK 0x000000ff +/* HC_SubA_FogTable 0x0010 + */ +#define HC_HFPn3_MASK 0xff000000 +#define HC_HFPn2_MASK 0x00ff0000 +#define HC_HFPn1_MASK 0x0000ff00 +#define HC_HFPn_MASK 0x000000ff +#define HC_HFPn3_SHIFT 24 +#define HC_HFPn2_SHIFT 16 +#define HC_HFPn1_SHIFT 8 + +/* Auto Testing & Security + */ +#define HC_SubA_HenFIFOAT 0x0000 +#define HC_SubA_HFBDrawFirst 0x0004 +#define HC_SubA_HFBBasL 0x0005 +#define HC_SubA_HFBDst 0x0006 +/* HC_SubA_HenFIFOAT 0x0000 + */ +#define HC_HenFIFOAT_MASK 0x00000020 +#define HC_HenGEMILock_MASK 0x00000010 +#define HC_HenFBASwap_MASK 0x00000008 +#define HC_HenOT_MASK 0x00000004 +#define HC_HenCMDQ_MASK 0x00000002 +#define HC_HenTXCTSU_MASK 0x00000001 +/* HC_SubA_HFBDrawFirst 0x0004 + */ +#define HC_HFBDrawFirst_MASK 0x00000800 +#define HC_HFBQueue_MASK 0x00000400 +#define HC_HFBLock_MASK 0x00000200 +#define HC_HEOF_MASK 0x00000100 +#define HC_HFBBasH_MASK 0x000000ff + +/* GEMI Setting + */ +#define HC_SubA_HTArbRCM 0x0008 +#define HC_SubA_HTArbRZ 0x000a +#define HC_SubA_HTArbWZ 0x000b +#define HC_SubA_HTArbRTX 0x000c +#define HC_SubA_HTArbRCW 0x000d +#define HC_SubA_HTArbE2 0x000e +#define HC_SubA_HArbRQCM 0x0010 +#define HC_SubA_HArbWQCM 0x0011 +#define HC_SubA_HGEMITout 0x0020 +#define HC_SubA_HFthRTXD 0x0040 +#define HC_SubA_HFthRTXA 0x0044 +#define HC_SubA_HCMDQstL 0x0050 +#define HC_SubA_HCMDQendL 0x0051 +#define HC_SubA_HCMDQLen 0x0052 +/* HC_SubA_HTArbRCM 0x0008 + */ +#define HC_HTArbRCM_MASK 0x0000ffff +/* HC_SubA_HTArbRZ 0x000a + */ +#define HC_HTArbRZ_MASK 0x0000ffff +/* HC_SubA_HTArbWZ 0x000b + */ +#define HC_HTArbWZ_MASK 0x0000ffff +/* HC_SubA_HTArbRTX 0x000c + */ +#define HC_HTArbRTX_MASK 0x0000ffff +/* HC_SubA_HTArbRCW 0x000d + */ +#define HC_HTArbRCW_MASK 0x0000ffff +/* HC_SubA_HTArbE2 0x000e + */ +#define HC_HTArbE2_MASK 0x0000ffff +/* HC_SubA_HArbRQCM 0x0010 + */ +#define HC_HTArbRQCM_MASK 0x0000ffff +/* HC_SubA_HArbWQCM 0x0011 + */ +#define HC_HArbWQCM_MASK 0x0000ffff +/* HC_SubA_HGEMITout 0x0020 + */ +#define HC_HGEMITout_MASK 0x000f0000 +#define HC_HNPArbZC_MASK 0x0000ffff +#define HC_HGEMITout_SHIFT 16 +/* HC_SubA_HFthRTXD 0x0040 + */ +#define HC_HFthRTXD_MASK 0x00ff0000 +#define HC_HFthRZD_MASK 0x0000ff00 +#define HC_HFthWZD_MASK 0x000000ff +#define HC_HFthRTXD_SHIFT 16 +#define HC_HFthRZD_SHIFT 8 +/* HC_SubA_HFthRTXA 0x0044 + */ +#define HC_HFthRTXA_MASK 0x000000ff + +/****************************************************************************** +** Define the Halcyon Internal register access constants. For simulator only. +******************************************************************************/ +#define HC_SIMA_HAGPBstL 0x0000 +#define HC_SIMA_HAGPBendL 0x0001 +#define HC_SIMA_HAGPCMNT 0x0002 +#define HC_SIMA_HAGPBpL 0x0003 +#define HC_SIMA_HAGPBpH 0x0004 +#define HC_SIMA_HClipTB 0x0005 +#define HC_SIMA_HClipLR 0x0006 +#define HC_SIMA_HFPClipTL 0x0007 +#define HC_SIMA_HFPClipBL 0x0008 +#define HC_SIMA_HFPClipLL 0x0009 +#define HC_SIMA_HFPClipRL 0x000a +#define HC_SIMA_HFPClipTBH 0x000b +#define HC_SIMA_HFPClipLRH 0x000c +#define HC_SIMA_HLP 0x000d +#define HC_SIMA_HLPRF 0x000e +#define HC_SIMA_HSolidCL 0x000f +#define HC_SIMA_HPixGC 0x0010 +#define HC_SIMA_HSPXYOS 0x0011 +#define HC_SIMA_HCmdA 0x0012 +#define HC_SIMA_HCmdB 0x0013 +#define HC_SIMA_HEnable 0x0014 +#define HC_SIMA_HZWBBasL 0x0015 +#define HC_SIMA_HZWBBasH 0x0016 +#define HC_SIMA_HZWBType 0x0017 +#define HC_SIMA_HZBiasL 0x0018 +#define HC_SIMA_HZWBend 0x0019 +#define HC_SIMA_HZWTMD 0x001a +#define HC_SIMA_HZWCDL 0x001b +#define HC_SIMA_HZWCTAGnum 0x001c +#define HC_SIMA_HZCYNum 0x001d +#define HC_SIMA_HZWCFire 0x001e +/* #define HC_SIMA_HSBBasL 0x001d */ +/* #define HC_SIMA_HSBBasH 0x001e */ +/* #define HC_SIMA_HSBFM 0x001f */ +#define HC_SIMA_HSTREF 0x0020 +#define HC_SIMA_HSTMD 0x0021 +#define HC_SIMA_HABBasL 0x0022 +#define HC_SIMA_HABBasH 0x0023 +#define HC_SIMA_HABFM 0x0024 +#define HC_SIMA_HATMD 0x0025 +#define HC_SIMA_HABLCsat 0x0026 +#define HC_SIMA_HABLCop 0x0027 +#define HC_SIMA_HABLAsat 0x0028 +#define HC_SIMA_HABLAop 0x0029 +#define HC_SIMA_HABLRCa 0x002a +#define HC_SIMA_HABLRFCa 0x002b +#define HC_SIMA_HABLRCbias 0x002c +#define HC_SIMA_HABLRCb 0x002d +#define HC_SIMA_HABLRFCb 0x002e +#define HC_SIMA_HABLRAa 0x002f +#define HC_SIMA_HABLRAb 0x0030 +#define HC_SIMA_HDBBasL 0x0031 +#define HC_SIMA_HDBBasH 0x0032 +#define HC_SIMA_HDBFM 0x0033 +#define HC_SIMA_HFBBMSKL 0x0034 +#define HC_SIMA_HROP 0x0035 +#define HC_SIMA_HFogLF 0x0036 +#define HC_SIMA_HFogCL 0x0037 +#define HC_SIMA_HFogCH 0x0038 +#define HC_SIMA_HFogStL 0x0039 +#define HC_SIMA_HFogStH 0x003a +#define HC_SIMA_HFogOOdMF 0x003b +#define HC_SIMA_HFogOOdEF 0x003c +#define HC_SIMA_HFogEndL 0x003d +#define HC_SIMA_HFogDenst 0x003e +/*---- start of texture 0 setting ---- + */ +#define HC_SIMA_HTX0L0BasL 0x0040 +#define HC_SIMA_HTX0L1BasL 0x0041 +#define HC_SIMA_HTX0L2BasL 0x0042 +#define HC_SIMA_HTX0L3BasL 0x0043 +#define HC_SIMA_HTX0L4BasL 0x0044 +#define HC_SIMA_HTX0L5BasL 0x0045 +#define HC_SIMA_HTX0L6BasL 0x0046 +#define HC_SIMA_HTX0L7BasL 0x0047 +#define HC_SIMA_HTX0L8BasL 0x0048 +#define HC_SIMA_HTX0L9BasL 0x0049 +#define HC_SIMA_HTX0LaBasL 0x004a +#define HC_SIMA_HTX0LbBasL 0x004b +#define HC_SIMA_HTX0LcBasL 0x004c +#define HC_SIMA_HTX0LdBasL 0x004d +#define HC_SIMA_HTX0LeBasL 0x004e +#define HC_SIMA_HTX0LfBasL 0x004f +#define HC_SIMA_HTX0L10BasL 0x0050 +#define HC_SIMA_HTX0L11BasL 0x0051 +#define HC_SIMA_HTX0L012BasH 0x0052 +#define HC_SIMA_HTX0L345BasH 0x0053 +#define HC_SIMA_HTX0L678BasH 0x0054 +#define HC_SIMA_HTX0L9abBasH 0x0055 +#define HC_SIMA_HTX0LcdeBasH 0x0056 +#define HC_SIMA_HTX0Lf1011BasH 0x0057 +#define HC_SIMA_HTX0L0Pit 0x0058 +#define HC_SIMA_HTX0L1Pit 0x0059 +#define HC_SIMA_HTX0L2Pit 0x005a +#define HC_SIMA_HTX0L3Pit 0x005b +#define HC_SIMA_HTX0L4Pit 0x005c +#define HC_SIMA_HTX0L5Pit 0x005d +#define HC_SIMA_HTX0L6Pit 0x005e +#define HC_SIMA_HTX0L7Pit 0x005f +#define HC_SIMA_HTX0L8Pit 0x0060 +#define HC_SIMA_HTX0L9Pit 0x0061 +#define HC_SIMA_HTX0LaPit 0x0062 +#define HC_SIMA_HTX0LbPit 0x0063 +#define HC_SIMA_HTX0LcPit 0x0064 +#define HC_SIMA_HTX0LdPit 0x0065 +#define HC_SIMA_HTX0LePit 0x0066 +#define HC_SIMA_HTX0LfPit 0x0067 +#define HC_SIMA_HTX0L10Pit 0x0068 +#define HC_SIMA_HTX0L11Pit 0x0069 +#define HC_SIMA_HTX0L0_5WE 0x006a +#define HC_SIMA_HTX0L6_bWE 0x006b +#define HC_SIMA_HTX0Lc_11WE 0x006c +#define HC_SIMA_HTX0L0_5HE 0x006d +#define HC_SIMA_HTX0L6_bHE 0x006e +#define HC_SIMA_HTX0Lc_11HE 0x006f +#define HC_SIMA_HTX0L0OS 0x0070 +#define HC_SIMA_HTX0TB 0x0071 +#define HC_SIMA_HTX0MPMD 0x0072 +#define HC_SIMA_HTX0CLODu 0x0073 +#define HC_SIMA_HTX0FM 0x0074 +#define HC_SIMA_HTX0TRCH 0x0075 +#define HC_SIMA_HTX0TRCL 0x0076 +#define HC_SIMA_HTX0TBC 0x0077 +#define HC_SIMA_HTX0TRAH 0x0078 +#define HC_SIMA_HTX0TBLCsat 0x0079 +#define HC_SIMA_HTX0TBLCop 0x007a +#define HC_SIMA_HTX0TBLMPfog 0x007b +#define HC_SIMA_HTX0TBLAsat 0x007c +#define HC_SIMA_HTX0TBLRCa 0x007d +#define HC_SIMA_HTX0TBLRCb 0x007e +#define HC_SIMA_HTX0TBLRCc 0x007f +#define HC_SIMA_HTX0TBLRCbias 0x0080 +#define HC_SIMA_HTX0TBLRAa 0x0081 +#define HC_SIMA_HTX0TBLRFog 0x0082 +#define HC_SIMA_HTX0BumpM00 0x0083 +#define HC_SIMA_HTX0BumpM01 0x0084 +#define HC_SIMA_HTX0BumpM10 0x0085 +#define HC_SIMA_HTX0BumpM11 0x0086 +#define HC_SIMA_HTX0LScale 0x0087 +/*---- end of texture 0 setting ---- 0x008f + */ +#define HC_SIMA_TX0TX1_OFF 0x0050 +/*---- start of texture 1 setting ---- + */ +#define HC_SIMA_HTX1L0BasL (HC_SIMA_HTX0L0BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L1BasL (HC_SIMA_HTX0L1BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L2BasL (HC_SIMA_HTX0L2BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L3BasL (HC_SIMA_HTX0L3BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L4BasL (HC_SIMA_HTX0L4BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L5BasL (HC_SIMA_HTX0L5BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L6BasL (HC_SIMA_HTX0L6BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L7BasL (HC_SIMA_HTX0L7BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L8BasL (HC_SIMA_HTX0L8BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L9BasL (HC_SIMA_HTX0L9BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LaBasL (HC_SIMA_HTX0LaBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LbBasL (HC_SIMA_HTX0LbBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LcBasL (HC_SIMA_HTX0LcBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LdBasL (HC_SIMA_HTX0LdBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LeBasL (HC_SIMA_HTX0LeBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LfBasL (HC_SIMA_HTX0LfBasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L10BasL (HC_SIMA_HTX0L10BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L11BasL (HC_SIMA_HTX0L11BasL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L012BasH (HC_SIMA_HTX0L012BasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L345BasH (HC_SIMA_HTX0L345BasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L678BasH (HC_SIMA_HTX0L678BasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L9abBasH (HC_SIMA_HTX0L9abBasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LcdeBasH (HC_SIMA_HTX0LcdeBasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1Lf1011BasH (HC_SIMA_HTX0Lf1011BasH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L0Pit (HC_SIMA_HTX0L0Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L1Pit (HC_SIMA_HTX0L1Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L2Pit (HC_SIMA_HTX0L2Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L3Pit (HC_SIMA_HTX0L3Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L4Pit (HC_SIMA_HTX0L4Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L5Pit (HC_SIMA_HTX0L5Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L6Pit (HC_SIMA_HTX0L6Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L7Pit (HC_SIMA_HTX0L7Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L8Pit (HC_SIMA_HTX0L8Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L9Pit (HC_SIMA_HTX0L9Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LaPit (HC_SIMA_HTX0LaPit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LbPit (HC_SIMA_HTX0LbPit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LcPit (HC_SIMA_HTX0LcPit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LdPit (HC_SIMA_HTX0LdPit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LePit (HC_SIMA_HTX0LePit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LfPit (HC_SIMA_HTX0LfPit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L10Pit (HC_SIMA_HTX0L10Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L11Pit (HC_SIMA_HTX0L11Pit + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L0_5WE (HC_SIMA_HTX0L0_5WE + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L6_bWE (HC_SIMA_HTX0L6_bWE + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1Lc_11WE (HC_SIMA_HTX0Lc_11WE + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L0_5HE (HC_SIMA_HTX0L0_5HE + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L6_bHE (HC_SIMA_HTX0L6_bHE + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1Lc_11HE (HC_SIMA_HTX0Lc_11HE + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1L0OS (HC_SIMA_HTX0L0OS + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TB (HC_SIMA_HTX0TB + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1MPMD (HC_SIMA_HTX0MPMD + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1CLODu (HC_SIMA_HTX0CLODu + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1FM (HC_SIMA_HTX0FM + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TRCH (HC_SIMA_HTX0TRCH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TRCL (HC_SIMA_HTX0TRCL + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBC (HC_SIMA_HTX0TBC + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TRAH (HC_SIMA_HTX0TRAH + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LTC (HC_SIMA_HTX0LTC + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LTA (HC_SIMA_HTX0LTA + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLCsat (HC_SIMA_HTX0TBLCsat + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLCop (HC_SIMA_HTX0TBLCop + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLMPfog (HC_SIMA_HTX0TBLMPfog + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLAsat (HC_SIMA_HTX0TBLAsat + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRCa (HC_SIMA_HTX0TBLRCa + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRCb (HC_SIMA_HTX0TBLRCb + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRCc (HC_SIMA_HTX0TBLRCc + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRCbias (HC_SIMA_HTX0TBLRCbias + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRAa (HC_SIMA_HTX0TBLRAa + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1TBLRFog (HC_SIMA_HTX0TBLRFog + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1BumpM00 (HC_SIMA_HTX0BumpM00 + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1BumpM01 (HC_SIMA_HTX0BumpM01 + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1BumpM10 (HC_SIMA_HTX0BumpM10 + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1BumpM11 (HC_SIMA_HTX0BumpM11 + HC_SIMA_TX0TX1_OFF) +#define HC_SIMA_HTX1LScale (HC_SIMA_HTX0LScale + HC_SIMA_TX0TX1_OFF) +/*---- end of texture 1 setting ---- 0xaf + */ +#define HC_SIMA_HTXSMD 0x00b0 +#define HC_SIMA_HenFIFOAT 0x00b1 +#define HC_SIMA_HFBDrawFirst 0x00b2 +#define HC_SIMA_HFBBasL 0x00b3 +#define HC_SIMA_HTArbRCM 0x00b4 +#define HC_SIMA_HTArbRZ 0x00b5 +#define HC_SIMA_HTArbWZ 0x00b6 +#define HC_SIMA_HTArbRTX 0x00b7 +#define HC_SIMA_HTArbRCW 0x00b8 +#define HC_SIMA_HTArbE2 0x00b9 +#define HC_SIMA_HGEMITout 0x00ba +#define HC_SIMA_HFthRTXD 0x00bb +#define HC_SIMA_HFthRTXA 0x00bc +/* Define the texture palette 0 + */ +#define HC_SIMA_HTP0 0x0100 +#define HC_SIMA_HTP1 0x0200 +#define HC_SIMA_FOGTABLE 0x0300 +#define HC_SIMA_STIPPLE 0x0400 +#define HC_SIMA_HE3Fire 0x0440 +#define HC_SIMA_TRANS_SET 0x0441 +#define HC_SIMA_HREngSt 0x0442 +#define HC_SIMA_HRFIFOempty 0x0443 +#define HC_SIMA_HRFIFOfull 0x0444 +#define HC_SIMA_HRErr 0x0445 +#define HC_SIMA_FIFOstatus 0x0446 + +/****************************************************************************** +** Define the AGP command header. +******************************************************************************/ +#define HC_ACMD_MASK 0xfe000000 +#define HC_ACMD_SUB_MASK 0x0c000000 +#define HC_ACMD_HCmdA 0xee000000 +#define HC_ACMD_HCmdB 0xec000000 +#define HC_ACMD_HCmdC 0xea000000 +#define HC_ACMD_H1 0xf0000000 +#define HC_ACMD_H2 0xf2000000 +#define HC_ACMD_H3 0xf4000000 +#define HC_ACMD_H4 0xf6000000 + +#define HC_ACMD_H1IO_MASK 0x000001ff +#define HC_ACMD_H2IO1_MASK 0x001ff000 +#define HC_ACMD_H2IO2_MASK 0x000001ff +#define HC_ACMD_H2IO1_SHIFT 12 +#define HC_ACMD_H2IO2_SHIFT 0 +#define HC_ACMD_H3IO_MASK 0x000001ff +#define HC_ACMD_H3COUNT_MASK 0x01fff000 +#define HC_ACMD_H3COUNT_SHIFT 12 +#define HC_ACMD_H4ID_MASK 0x000001ff +#define HC_ACMD_H4COUNT_MASK 0x01fffe00 +#define HC_ACMD_H4COUNT_SHIFT 9 + +/******************************************************************************** +** Define Header +********************************************************************************/ +#define HC_HEADER2 0xF210F110 + +/******************************************************************************** +** Define Dummy Value +********************************************************************************/ +#define HC_DUMMY 0xCCCCCCCC +/******************************************************************************** +** Define for DMA use +********************************************************************************/ +#define HALCYON_HEADER2 0XF210F110 +#define HALCYON_FIRECMD 0XEE100000 +#define HALCYON_FIREMASK 0XFFF00000 +#define HALCYON_CMDB 0XEC000000 +#define HALCYON_CMDBMASK 0XFFFE0000 +#define HALCYON_SUB_ADDR0 0X00000000 +#define HALCYON_HEADER1MASK 0XFFFFFC00 +#define HALCYON_HEADER1 0XF0000000 +#define HC_SubA_HAGPBstL 0x0060 +#define HC_SubA_HAGPBendL 0x0061 +#define HC_SubA_HAGPCMNT 0x0062 +#define HC_SubA_HAGPBpL 0x0063 +#define HC_SubA_HAGPBpH 0x0064 +#define HC_HAGPCMNT_MASK 0x00800000 +#define HC_HCmdErrClr_MASK 0x00400000 +#define HC_HAGPBendH_MASK 0x0000ff00 +#define HC_HAGPBstH_MASK 0x000000ff +#define HC_HAGPBendH_SHIFT 8 +#define HC_HAGPBstH_SHIFT 0 +#define HC_HAGPBpL_MASK 0x00fffffc +#define HC_HAGPBpID_MASK 0x00000003 +#define HC_HAGPBpID_PAUSE 0x00000000 +#define HC_HAGPBpID_JUMP 0x00000001 +#define HC_HAGPBpID_STOP 0x00000002 +#define HC_HAGPBpH_MASK 0x00ffffff + + +#define VIA_VIDEO_HEADER5 0xFE040000 +#define VIA_VIDEO_HEADER6 0xFE050000 +#define VIA_VIDEO_HEADER7 0xFE060000 +#define VIA_VIDEOMASK 0xFFFF0000 +#endif diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c new file mode 100644 index 00000000000..82f83945162 --- /dev/null +++ b/drivers/char/drm/via_dma.c @@ -0,0 +1,741 @@ +/* via_dma.c -- DMA support for the VIA Unichrome/Pro + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A. + * All Rights Reserved. + * + * Copyright 2004 The Unichrome project. + * 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 COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + * + * Authors: + * Tungsten Graphics, + * Erdi Chen, + * Thomas Hellstrom. + */ + +#include "drmP.h" +#include "drm.h" +#include "via_drm.h" +#include "via_drv.h" +#include "via_3d_reg.h" + +#define CMDBUF_ALIGNMENT_SIZE (0x100) +#define CMDBUF_ALIGNMENT_MASK (0x0ff) + +/* defines for VIA 3D registers */ +#define VIA_REG_STATUS 0x400 +#define VIA_REG_TRANSET 0x43C +#define VIA_REG_TRANSPACE 0x440 + +/* VIA_REG_STATUS(0x400): Engine Status */ +#define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */ +#define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */ +#define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */ +#define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */ + +#define SetReg2DAGP(nReg, nData) { \ + *((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1; \ + *((uint32_t *)(vb) + 1) = (nData); \ + vb = ((uint32_t *)vb) + 2; \ + dev_priv->dma_low +=8; \ +} + +#define via_flush_write_combine() DRM_MEMORYBARRIER() + +#define VIA_OUT_RING_QW(w1,w2) \ + *vb++ = (w1); \ + *vb++ = (w2); \ + dev_priv->dma_low += 8; + +static void via_cmdbuf_start(drm_via_private_t * dev_priv); +static void via_cmdbuf_pause(drm_via_private_t * dev_priv); +static void via_cmdbuf_reset(drm_via_private_t * dev_priv); +static void via_cmdbuf_rewind(drm_via_private_t * dev_priv); +static int via_wait_idle(drm_via_private_t * dev_priv); +static void via_pad_cache(drm_via_private_t *dev_priv, int qwords); + + +/* + * Free space in command buffer. + */ + +static uint32_t +via_cmdbuf_space(drm_via_private_t *dev_priv) +{ + uint32_t agp_base = dev_priv->dma_offset + + (uint32_t) dev_priv->agpAddr; + uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base; + + return ((hw_addr <= dev_priv->dma_low) ? + (dev_priv->dma_high + hw_addr - dev_priv->dma_low) : + (hw_addr - dev_priv->dma_low)); +} + +/* + * How much does the command regulator lag behind? + */ + +static uint32_t +via_cmdbuf_lag(drm_via_private_t *dev_priv) +{ + uint32_t agp_base = dev_priv->dma_offset + + (uint32_t) dev_priv->agpAddr; + uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base; + + return ((hw_addr <= dev_priv->dma_low) ? + (dev_priv->dma_low - hw_addr) : + (dev_priv->dma_wrap + dev_priv->dma_low - hw_addr)); +} + +/* + * Check that the given size fits in the buffer, otherwise wait. + */ + +static inline int +via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size) +{ + uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; + uint32_t cur_addr, hw_addr, next_addr; + volatile uint32_t *hw_addr_ptr; + uint32_t count; + hw_addr_ptr = dev_priv->hw_addr_ptr; + cur_addr = dev_priv->dma_low; + next_addr = cur_addr + size + 512*1024; + count = 1000000; + do { + hw_addr = *hw_addr_ptr - agp_base; + if (count-- == 0) { + DRM_ERROR("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n", + hw_addr, cur_addr, next_addr); + return -1; + } + } while ((cur_addr < hw_addr) && (next_addr >= hw_addr)); + return 0; +} + + +/* + * Checks whether buffer head has reach the end. Rewind the ring buffer + * when necessary. + * + * Returns virtual pointer to ring buffer. + */ + +static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv, + unsigned int size) +{ + if ((dev_priv->dma_low + size + 4*CMDBUF_ALIGNMENT_SIZE) > dev_priv->dma_high) { + via_cmdbuf_rewind(dev_priv); + } + if (via_cmdbuf_wait(dev_priv, size) != 0) { + return NULL; + } + + return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low); +} + +int via_dma_cleanup(drm_device_t * dev) +{ + if (dev->dev_private) { + drm_via_private_t *dev_priv = + (drm_via_private_t *) dev->dev_private; + + if (dev_priv->ring.virtual_start) { + via_cmdbuf_reset(dev_priv); + + drm_core_ioremapfree(&dev_priv->ring.map, dev); + dev_priv->ring.virtual_start = NULL; + } + + } + + return 0; +} + +static int via_initialize(drm_device_t * dev, + drm_via_private_t * dev_priv, + drm_via_dma_init_t * init) +{ + if (!dev_priv || !dev_priv->mmio) { + DRM_ERROR("via_dma_init called before via_map_init\n"); + return DRM_ERR(EFAULT); + } + + if (dev_priv->ring.virtual_start != NULL) { + DRM_ERROR("%s called again without calling cleanup\n", + __FUNCTION__); + return DRM_ERR(EFAULT); + } + + if (!dev->agp || !dev->agp->base) { + DRM_ERROR("%s called with no agp memory available\n", + __FUNCTION__); + return DRM_ERR(EFAULT); + } + + dev_priv->ring.map.offset = dev->agp->base + init->offset; + dev_priv->ring.map.size = init->size; + dev_priv->ring.map.type = 0; + dev_priv->ring.map.flags = 0; + dev_priv->ring.map.mtrr = 0; + + drm_core_ioremap(&dev_priv->ring.map, dev); + + if (dev_priv->ring.map.handle == NULL) { + via_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return DRM_ERR(ENOMEM); + } + + dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + + dev_priv->dma_ptr = dev_priv->ring.virtual_start; + dev_priv->dma_low = 0; + dev_priv->dma_high = init->size; + dev_priv->dma_wrap = init->size; + dev_priv->dma_offset = init->offset; + dev_priv->last_pause_ptr = NULL; + dev_priv->hw_addr_ptr = dev_priv->mmio->handle + init->reg_pause_addr; + + via_cmdbuf_start(dev_priv); + + return 0; +} + +int via_dma_init(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + drm_via_dma_init_t init; + int retcode = 0; + + DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t *) data, + sizeof(init)); + + switch (init.func) { + case VIA_INIT_DMA: + if (!capable(CAP_SYS_ADMIN)) + retcode = DRM_ERR(EPERM); + else + retcode = via_initialize(dev, dev_priv, &init); + break; + case VIA_CLEANUP_DMA: + if (!capable(CAP_SYS_ADMIN)) + retcode = DRM_ERR(EPERM); + else + retcode = via_dma_cleanup(dev); + break; + case VIA_DMA_INITIALIZED: + retcode = (dev_priv->ring.virtual_start != NULL) ? + 0: DRM_ERR( EFAULT ); + break; + default: + retcode = DRM_ERR(EINVAL); + break; + } + + return retcode; +} + + + +static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd) +{ + drm_via_private_t *dev_priv; + uint32_t *vb; + int ret; + + dev_priv = (drm_via_private_t *) dev->dev_private; + + if (dev_priv->ring.virtual_start == NULL) { + DRM_ERROR("%s called without initializing AGP ring buffer.\n", + __FUNCTION__); + return DRM_ERR(EFAULT); + } + + if (cmd->size > VIA_PCI_BUF_SIZE) { + return DRM_ERR(ENOMEM); + } + + + if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size)) + return DRM_ERR(EFAULT); + + /* + * Running this function on AGP memory is dead slow. Therefore + * we run it on a temporary cacheable system memory buffer and + * copy it to AGP memory when ready. + */ + + + if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 1))) { + return ret; + } + + + vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size); + if (vb == NULL) { + return DRM_ERR(EAGAIN); + } + + memcpy(vb, dev_priv->pci_buf, cmd->size); + + dev_priv->dma_low += cmd->size; + + /* + * Small submissions somehow stalls the CPU. (AGP cache effects?) + * pad to greater size. + */ + + if (cmd->size < 0x100) + via_pad_cache(dev_priv,(0x100 - cmd->size) >> 3); + via_cmdbuf_pause(dev_priv); + + return 0; +} + +int via_driver_dma_quiescent(drm_device_t * dev) +{ + drm_via_private_t *dev_priv = dev->dev_private; + + if (!via_wait_idle(dev_priv)) { + return DRM_ERR(EBUSY); + } + return 0; +} + +int via_flush_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + + LOCK_TEST_WITH_RETURN( dev, filp ); + + return via_driver_dma_quiescent(dev); +} + +int via_cmdbuffer(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_via_cmdbuffer_t cmdbuf; + int ret; + + LOCK_TEST_WITH_RETURN( dev, filp ); + + DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t *) data, + sizeof(cmdbuf)); + + DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size); + + ret = via_dispatch_cmdbuffer(dev, &cmdbuf); + if (ret) { + return ret; + } + + return 0; +} + +extern int +via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size); +static int via_dispatch_pci_cmdbuffer(drm_device_t * dev, + drm_via_cmdbuffer_t * cmd) +{ + drm_via_private_t *dev_priv = dev->dev_private; + int ret; + + if (cmd->size > VIA_PCI_BUF_SIZE) { + return DRM_ERR(ENOMEM); + } + if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size)) + return DRM_ERR(EFAULT); + + if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 0))) { + return ret; + } + + ret = via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf, cmd->size); + return ret; +} + +int via_pci_cmdbuffer(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_via_cmdbuffer_t cmdbuf; + int ret; + + LOCK_TEST_WITH_RETURN( dev, filp ); + + DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t *) data, + sizeof(cmdbuf)); + + DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf, + cmdbuf.size); + + ret = via_dispatch_pci_cmdbuffer(dev, &cmdbuf); + if (ret) { + return ret; + } + + return 0; +} + + +static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv, + uint32_t * vb, int qw_count) +{ + for (; qw_count > 0; --qw_count) { + VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY); + } + return vb; +} + + +/* + * This function is used internally by ring buffer mangement code. + * + * Returns virtual pointer to ring buffer. + */ +static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv) +{ + return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low); +} + +/* + * Hooks a segment of data into the tail of the ring-buffer by + * modifying the pause address stored in the buffer itself. If + * the regulator has already paused, restart it. + */ +static int via_hook_segment(drm_via_private_t *dev_priv, + uint32_t pause_addr_hi, uint32_t pause_addr_lo, + int no_pci_fire) +{ + int paused, count; + volatile uint32_t *paused_at = dev_priv->last_pause_ptr; + + via_flush_write_combine(); + while(! *(via_get_dma(dev_priv)-1)); + *dev_priv->last_pause_ptr = pause_addr_lo; + via_flush_write_combine(); + + /* + * The below statement is inserted to really force the flush. + * Not sure it is needed. + */ + + while(! *dev_priv->last_pause_ptr); + dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; + while(! *dev_priv->last_pause_ptr); + + + paused = 0; + count = 20; + + while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--); + if ((count <= 8) && (count >= 0)) { + uint32_t rgtr, ptr; + rgtr = *(dev_priv->hw_addr_ptr); + ptr = ((char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) + + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4 - + CMDBUF_ALIGNMENT_SIZE; + if (rgtr <= ptr) { + DRM_ERROR("Command regulator\npaused at count %d, address %x, " + "while current pause address is %x.\n" + "Please mail this message to " + "\n", + count, rgtr, ptr); + } + } + + if (paused && !no_pci_fire) { + uint32_t rgtr,ptr; + uint32_t ptr_low; + + count = 1000000; + while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) && count--); + + rgtr = *(dev_priv->hw_addr_ptr); + ptr = ((char *)paused_at - dev_priv->dma_ptr) + + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; + + + ptr_low = (ptr > 3*CMDBUF_ALIGNMENT_SIZE) ? + ptr - 3*CMDBUF_ALIGNMENT_SIZE : 0; + if (rgtr <= ptr && rgtr >= ptr_low) { + VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); + VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); + VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); + } + } + return paused; +} + + + +static int via_wait_idle(drm_via_private_t * dev_priv) +{ + int count = 10000000; + while (count-- && (VIA_READ(VIA_REG_STATUS) & + (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | + VIA_3D_ENG_BUSY))) ; + return count; +} + +static uint32_t *via_align_cmd(drm_via_private_t * dev_priv, uint32_t cmd_type, + uint32_t addr, uint32_t *cmd_addr_hi, + uint32_t *cmd_addr_lo, + int skip_wait) +{ + uint32_t agp_base; + uint32_t cmd_addr, addr_lo, addr_hi; + uint32_t *vb; + uint32_t qw_pad_count; + + if (!skip_wait) + via_cmdbuf_wait(dev_priv, 2*CMDBUF_ALIGNMENT_SIZE); + + vb = via_get_dma(dev_priv); + VIA_OUT_RING_QW( HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) | + (VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16); + agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; + qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) - + ((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3); + + + cmd_addr = (addr) ? addr : + agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3); + addr_lo = ((HC_SubA_HAGPBpL << 24) | (cmd_type & HC_HAGPBpID_MASK) | + (cmd_addr & HC_HAGPBpL_MASK)); + addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24)); + + vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1); + VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi, + *cmd_addr_lo = addr_lo); + return vb; +} + + + + +static void via_cmdbuf_start(drm_via_private_t * dev_priv) +{ + uint32_t pause_addr_lo, pause_addr_hi; + uint32_t start_addr, start_addr_lo; + uint32_t end_addr, end_addr_lo; + uint32_t command; + uint32_t agp_base; + + + dev_priv->dma_low = 0; + + agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; + start_addr = agp_base; + end_addr = agp_base + dev_priv->dma_high; + + start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF)); + end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF)); + command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) | + ((end_addr & 0xff000000) >> 16)); + + dev_priv->last_pause_ptr = + via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, + &pause_addr_hi, & pause_addr_lo, 1) - 1; + + via_flush_write_combine(); + while(! *dev_priv->last_pause_ptr); + + VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); + VIA_WRITE(VIA_REG_TRANSPACE, command); + VIA_WRITE(VIA_REG_TRANSPACE, start_addr_lo); + VIA_WRITE(VIA_REG_TRANSPACE, end_addr_lo); + + VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); + VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); + + VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); +} + +static void via_pad_cache(drm_via_private_t *dev_priv, int qwords) +{ + uint32_t *vb; + + via_cmdbuf_wait(dev_priv, qwords + 2); + vb = via_get_dma(dev_priv); + VIA_OUT_RING_QW( HC_HEADER2, HC_ParaType_NotTex << 16); + via_align_buffer(dev_priv,vb,qwords); +} + +static inline void via_dummy_bitblt(drm_via_private_t * dev_priv) +{ + uint32_t *vb = via_get_dma(dev_priv); + SetReg2DAGP(0x0C, (0 | (0 << 16))); + SetReg2DAGP(0x10, 0 | (0 << 16)); + SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000); +} + + +static void via_cmdbuf_jump(drm_via_private_t * dev_priv) +{ + uint32_t agp_base; + uint32_t pause_addr_lo, pause_addr_hi; + uint32_t jump_addr_lo, jump_addr_hi; + volatile uint32_t *last_pause_ptr; + uint32_t dma_low_save1, dma_low_save2; + + agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; + via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, + &jump_addr_lo, 0); + + dev_priv->dma_wrap = dev_priv->dma_low; + + + /* + * Wrap command buffer to the beginning. + */ + + dev_priv->dma_low = 0; + if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) { + DRM_ERROR("via_cmdbuf_jump failed\n"); + } + + via_dummy_bitblt(dev_priv); + via_dummy_bitblt(dev_priv); + + last_pause_ptr = via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, + &pause_addr_lo, 0) -1; + via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, + &pause_addr_lo, 0); + + *last_pause_ptr = pause_addr_lo; + dma_low_save1 = dev_priv->dma_low; + + /* + * Now, set a trap that will pause the regulator if it tries to rerun the old + * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause + * and reissues the jump command over PCI, while the regulator has already taken the jump + * and actually paused at the current buffer end). + * There appears to be no other way to detect this condition, since the hw_addr_pointer + * does not seem to get updated immediately when a jump occurs. + */ + + last_pause_ptr = via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, + &pause_addr_lo, 0) -1; + via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, + &pause_addr_lo, 0); + *last_pause_ptr = pause_addr_lo; + + dma_low_save2 = dev_priv->dma_low; + dev_priv->dma_low = dma_low_save1; + via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0); + dev_priv->dma_low = dma_low_save2; + via_hook_segment( dev_priv, pause_addr_hi, pause_addr_lo, 0); +} + + +static void via_cmdbuf_rewind(drm_via_private_t * dev_priv) +{ + via_cmdbuf_jump(dev_priv); +} + +static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type) +{ + uint32_t pause_addr_lo, pause_addr_hi; + + via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0); + via_hook_segment( dev_priv, pause_addr_hi, pause_addr_lo, 0); +} + + +static void via_cmdbuf_pause(drm_via_private_t * dev_priv) +{ + via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE); +} + +static void via_cmdbuf_reset(drm_via_private_t * dev_priv) +{ + via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP); + via_wait_idle(dev_priv); +} + +/* + * User interface to the space and lag functions. + */ + +int +via_cmdbuf_size(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_via_cmdbuf_size_t d_siz; + int ret = 0; + uint32_t tmp_size, count; + drm_via_private_t *dev_priv; + + DRM_DEBUG("via cmdbuf_size\n"); + LOCK_TEST_WITH_RETURN( dev, filp ); + + dev_priv = (drm_via_private_t *) dev->dev_private; + + if (dev_priv->ring.virtual_start == NULL) { + DRM_ERROR("%s called without initializing AGP ring buffer.\n", + __FUNCTION__); + return DRM_ERR(EFAULT); + } + + DRM_COPY_FROM_USER_IOCTL(d_siz, (drm_via_cmdbuf_size_t *) data, + sizeof(d_siz)); + + + count = 1000000; + tmp_size = d_siz.size; + switch(d_siz.func) { + case VIA_CMDBUF_SPACE: + while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz.size) && count--) { + if (!d_siz.wait) { + break; + } + } + if (!count) { + DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n"); + ret = DRM_ERR(EAGAIN); + } + break; + case VIA_CMDBUF_LAG: + while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz.size) && count--) { + if (!d_siz.wait) { + break; + } + } + if (!count) { + DRM_ERROR("VIA_CMDBUF_LAG timed out.\n"); + ret = DRM_ERR(EAGAIN); + } + break; + default: + ret = DRM_ERR(EFAULT); + } + d_siz.size = tmp_size; + + DRM_COPY_TO_USER_IOCTL((drm_via_cmdbuf_size_t *) data, d_siz, + sizeof(d_siz)); + return ret; +} diff --git a/drivers/char/drm/via_drm.h b/drivers/char/drm/via_drm.h new file mode 100644 index 00000000000..4588c9bd181 --- /dev/null +++ b/drivers/char/drm/via_drm.h @@ -0,0 +1,243 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. 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 + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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. + */ +#ifndef _VIA_DRM_H_ +#define _VIA_DRM_H_ + +/* WARNING: These defines must be the same as what the Xserver uses. + * if you change them, you must change the defines in the Xserver. + */ + +#ifndef _VIA_DEFINES_ +#define _VIA_DEFINES_ + +#ifndef __KERNEL__ +#include "via_drmclient.h" +#endif + +#define VIA_NR_SAREA_CLIPRECTS 8 +#define VIA_NR_XVMC_PORTS 10 +#define VIA_NR_XVMC_LOCKS 5 +#define VIA_MAX_CACHELINE_SIZE 64 +#define XVMCLOCKPTR(saPriv,lockNo) \ + ((volatile drm_hw_lock_t *)(((((unsigned long) (saPriv)->XvMCLockArea) + \ + (VIA_MAX_CACHELINE_SIZE - 1)) & \ + ~(VIA_MAX_CACHELINE_SIZE - 1)) + \ + VIA_MAX_CACHELINE_SIZE*(lockNo))) + +/* Each region is a minimum of 64k, and there are at most 64 of them. + */ +#define VIA_NR_TEX_REGIONS 64 +#define VIA_LOG_MIN_TEX_REGION_SIZE 16 +#endif + +#define VIA_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */ +#define VIA_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */ +#define VIA_UPLOAD_CTX 0x4 +#define VIA_UPLOAD_BUFFERS 0x8 +#define VIA_UPLOAD_TEX0 0x10 +#define VIA_UPLOAD_TEX1 0x20 +#define VIA_UPLOAD_CLIPRECTS 0x40 +#define VIA_UPLOAD_ALL 0xff + +/* VIA specific ioctls */ +#define DRM_VIA_ALLOCMEM 0x00 +#define DRM_VIA_FREEMEM 0x01 +#define DRM_VIA_AGP_INIT 0x02 +#define DRM_VIA_FB_INIT 0x03 +#define DRM_VIA_MAP_INIT 0x04 +#define DRM_VIA_DEC_FUTEX 0x05 +#define NOT_USED +#define DRM_VIA_DMA_INIT 0x07 +#define DRM_VIA_CMDBUFFER 0x08 +#define DRM_VIA_FLUSH 0x09 +#define DRM_VIA_PCICMD 0x0a +#define DRM_VIA_CMDBUF_SIZE 0x0b +#define NOT_USED +#define DRM_VIA_WAIT_IRQ 0x0d + +#define DRM_IOCTL_VIA_ALLOCMEM DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t) +#define DRM_IOCTL_VIA_FREEMEM DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_FREEMEM, drm_via_mem_t) +#define DRM_IOCTL_VIA_AGP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_AGP_INIT, drm_via_agp_t) +#define DRM_IOCTL_VIA_FB_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_FB_INIT, drm_via_fb_t) +#define DRM_IOCTL_VIA_MAP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_MAP_INIT, drm_via_init_t) +#define DRM_IOCTL_VIA_DEC_FUTEX DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_DEC_FUTEX, drm_via_futex_t) +#define DRM_IOCTL_VIA_DMA_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_DMA_INIT, drm_via_dma_init_t) +#define DRM_IOCTL_VIA_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_CMDBUFFER, drm_via_cmdbuffer_t) +#define DRM_IOCTL_VIA_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_VIA_FLUSH) +#define DRM_IOCTL_VIA_PCICMD DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_PCICMD, drm_via_cmdbuffer_t) +#define DRM_IOCTL_VIA_CMDBUF_SIZE DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_CMDBUF_SIZE, \ + drm_via_cmdbuf_size_t) +#define DRM_IOCTL_VIA_WAIT_IRQ DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_WAIT_IRQ, drm_via_irqwait_t) + +/* Indices into buf.Setup where various bits of state are mirrored per + * context and per buffer. These can be fired at the card as a unit, + * or in a piecewise fashion as required. + */ + +#define VIA_TEX_SETUP_SIZE 8 + +/* Flags for clear ioctl + */ +#define VIA_FRONT 0x1 +#define VIA_BACK 0x2 +#define VIA_DEPTH 0x4 +#define VIA_STENCIL 0x8 +#define VIDEO 0 +#define AGP 1 +typedef struct { + uint32_t offset; + uint32_t size; +} drm_via_agp_t; + +typedef struct { + uint32_t offset; + uint32_t size; +} drm_via_fb_t; + +typedef struct { + uint32_t context; + uint32_t type; + uint32_t size; + unsigned long index; + unsigned long offset; +} drm_via_mem_t; + +typedef struct _drm_via_init { + enum { + VIA_INIT_MAP = 0x01, + VIA_CLEANUP_MAP = 0x02 + } func; + + unsigned long sarea_priv_offset; + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long agpAddr; +} drm_via_init_t; + +typedef struct _drm_via_futex { + enum { + VIA_FUTEX_WAIT = 0x00, + VIA_FUTEX_WAKE = 0X01 + } func; + uint32_t ms; + uint32_t lock; + uint32_t val; +} drm_via_futex_t; + +typedef struct _drm_via_dma_init { + enum { + VIA_INIT_DMA = 0x01, + VIA_CLEANUP_DMA = 0x02, + VIA_DMA_INITIALIZED = 0x03 + } func; + + unsigned long offset; + unsigned long size; + unsigned long reg_pause_addr; +} drm_via_dma_init_t; + +typedef struct _drm_via_cmdbuffer { + char *buf; + unsigned long size; +} drm_via_cmdbuffer_t; + +/* Warning: If you change the SAREA structure you must change the Xserver + * structure as well */ + +typedef struct _drm_via_tex_region { + unsigned char next, prev; /* indices to form a circular LRU */ + unsigned char inUse; /* owned by a client, or free? */ + int age; /* tracked by clients to update local LRU's */ +} drm_via_tex_region_t; + +typedef struct _drm_via_sarea { + unsigned int dirty; + unsigned int nbox; + drm_clip_rect_t boxes[VIA_NR_SAREA_CLIPRECTS]; + drm_via_tex_region_t texList[VIA_NR_TEX_REGIONS + 1]; + int texAge; /* last time texture was uploaded */ + int ctxOwner; /* last context to upload state */ + int vertexPrim; + + /* + * Below is for XvMC. + * We want the lock integers alone on, and aligned to, a cache line. + * Therefore this somewhat strange construct. + */ + + char XvMCLockArea[VIA_MAX_CACHELINE_SIZE * (VIA_NR_XVMC_LOCKS + 1)]; + + unsigned int XvMCDisplaying[VIA_NR_XVMC_PORTS]; + unsigned int XvMCSubPicOn[VIA_NR_XVMC_PORTS]; + unsigned int XvMCCtxNoGrabbed; /* Last context to hold decoder */ + +} drm_via_sarea_t; + +typedef struct _drm_via_cmdbuf_size { + enum { + VIA_CMDBUF_SPACE = 0x01, + VIA_CMDBUF_LAG = 0x02 + } func; + int wait; + uint32_t size; +} drm_via_cmdbuf_size_t; + +typedef enum { + VIA_IRQ_ABSOLUTE = 0x0, + VIA_IRQ_RELATIVE = 0x1, + VIA_IRQ_SIGNAL = 0x10000000, + VIA_IRQ_FORCE_SEQUENCE = 0x20000000 +} via_irq_seq_type_t; + +#define VIA_IRQ_FLAGS_MASK 0xF0000000 + +struct drm_via_wait_irq_request{ + unsigned irq; + via_irq_seq_type_t type; + uint32_t sequence; + uint32_t signal; +}; + +typedef union drm_via_irqwait { + struct drm_via_wait_irq_request request; + struct drm_wait_vblank_reply reply; +} drm_via_irqwait_t; + +#ifdef __KERNEL__ + +int via_fb_init(DRM_IOCTL_ARGS); +int via_mem_alloc(DRM_IOCTL_ARGS); +int via_mem_free(DRM_IOCTL_ARGS); +int via_agp_init(DRM_IOCTL_ARGS); +int via_map_init(DRM_IOCTL_ARGS); +int via_decoder_futex(DRM_IOCTL_ARGS); +int via_dma_init(DRM_IOCTL_ARGS); +int via_cmdbuffer(DRM_IOCTL_ARGS); +int via_flush_ioctl(DRM_IOCTL_ARGS); +int via_pci_cmdbuffer(DRM_IOCTL_ARGS); +int via_cmdbuf_size(DRM_IOCTL_ARGS); +int via_wait_irq(DRM_IOCTL_ARGS); + +#endif +#endif /* _VIA_DRM_H_ */ diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c new file mode 100644 index 00000000000..275eefc7922 --- /dev/null +++ b/drivers/char/drm/via_drv.c @@ -0,0 +1,126 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. 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 + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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 +#include "drmP.h" +#include "via_drm.h" +#include "via_drv.h" + +#include "drm_pciids.h" + +static int postinit(struct drm_device *dev, unsigned long flags) +{ + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", + DRIVER_NAME, + DRIVER_MAJOR, + DRIVER_MINOR, + DRIVER_PATCHLEVEL, + DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev) + ); + return 0; +} + +static int version(drm_version_t * version) +{ + int len; + + version->version_major = DRIVER_MAJOR; + version->version_minor = DRIVER_MINOR; + version->version_patchlevel = DRIVER_PATCHLEVEL; + DRM_COPY(version->name, DRIVER_NAME); + DRM_COPY(version->date, DRIVER_DATE); + DRM_COPY(version->desc, DRIVER_DESC); + return 0; +} + +static struct pci_device_id pciidlist[] = { + viadrv_PCI_IDS +}; + +static drm_ioctl_desc_t ioctls[] = { + [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, 1, 0}, + [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, 1, 0} +}; + +static struct drm_driver driver = { + .driver_features = + DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | + DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, + .context_ctor = via_init_context, + .context_dtor = via_final_context, + .vblank_wait = via_driver_vblank_wait, + .irq_preinstall = via_driver_irq_preinstall, + .irq_postinstall = via_driver_irq_postinstall, + .irq_uninstall = via_driver_irq_uninstall, + .irq_handler = via_driver_irq_handler, + .dma_quiescent = via_driver_dma_quiescent, + .reclaim_buffers = drm_core_reclaim_buffers, + .get_map_ofs = drm_core_get_map_ofs, + .get_reg_ofs = drm_core_get_reg_ofs, + .postinit = postinit, + .version = version, + .ioctls = ioctls, + .num_ioctls = DRM_ARRAY_SIZE(ioctls), + .fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .ioctl = drm_ioctl, + .mmap = drm_mmap, + .poll = drm_poll, + .fasync = drm_fasync, + }, + .pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, + } +}; + +static int __init via_init(void) +{ + via_init_command_verifier(); + return drm_init(&driver); +} + +static void __exit via_exit(void) +{ + drm_exit(&driver); +} + +module_init(via_init); +module_exit(via_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h new file mode 100644 index 00000000000..4eaa8b7c4c9 --- /dev/null +++ b/drivers/char/drm/via_drv.h @@ -0,0 +1,118 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. 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 + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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. + */ +#ifndef _VIA_DRV_H_ +#define _VIA_DRV_H_ + +#define DRIVER_AUTHOR "VIA" + +#define DRIVER_NAME "via" +#define DRIVER_DESC "VIA Unichrome / Pro" +#define DRIVER_DATE "20050523" + +#define DRIVER_MAJOR 2 +#define DRIVER_MINOR 6 +#define DRIVER_PATCHLEVEL 3 + +#include "via_verifier.h" + +#define VIA_PCI_BUF_SIZE 60000 +#define VIA_FIRE_BUF_SIZE 1024 +#define VIA_NUM_IRQS 2 + + + +typedef struct drm_via_ring_buffer { + drm_map_t map; + char *virtual_start; +} drm_via_ring_buffer_t; + +typedef uint32_t maskarray_t[5]; + +typedef struct drm_via_irq { + atomic_t irq_received; + uint32_t pending_mask; + uint32_t enable_mask; + wait_queue_head_t irq_queue; +} drm_via_irq_t; + +typedef struct drm_via_private { + drm_via_sarea_t *sarea_priv; + drm_map_t *sarea; + drm_map_t *fb; + drm_map_t *mmio; + unsigned long agpAddr; + wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS]; + char *dma_ptr; + unsigned int dma_low; + unsigned int dma_high; + unsigned int dma_offset; + uint32_t dma_wrap; + volatile uint32_t *last_pause_ptr; + volatile uint32_t *hw_addr_ptr; + drm_via_ring_buffer_t ring; + struct timeval last_vblank; + int last_vblank_valid; + unsigned usec_per_vblank; + drm_via_state_t hc_state; + char pci_buf[VIA_PCI_BUF_SIZE]; + const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; + uint32_t num_fire_offsets; + int pro_group_a; + drm_via_irq_t via_irqs[VIA_NUM_IRQS]; + unsigned num_irqs; + maskarray_t *irq_masks; + uint32_t irq_enable_mask; + uint32_t irq_pending_mask; +} drm_via_private_t; + +/* VIA MMIO register access */ +#define VIA_BASE ((dev_priv->mmio)) + +#define VIA_READ(reg) DRM_READ32(VIA_BASE, reg) +#define VIA_WRITE(reg,val) DRM_WRITE32(VIA_BASE, reg, val) +#define VIA_READ8(reg) DRM_READ8(VIA_BASE, reg) +#define VIA_WRITE8(reg,val) DRM_WRITE8(VIA_BASE, reg, val) + +extern int via_init_context(drm_device_t * dev, int context); +extern int via_final_context(drm_device_t * dev, int context); + +extern int via_do_cleanup_map(drm_device_t * dev); +extern int via_map_init(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence); + +extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); +extern void via_driver_irq_preinstall(drm_device_t * dev); +extern void via_driver_irq_postinstall(drm_device_t * dev); +extern void via_driver_irq_uninstall(drm_device_t * dev); + +extern int via_dma_cleanup(drm_device_t * dev); +extern void via_init_command_verifier(void); +extern int via_driver_dma_quiescent(drm_device_t * dev); +extern void via_init_futex(drm_via_private_t *dev_priv); +extern void via_cleanup_futex(drm_via_private_t *dev_priv); +extern void via_release_futex(drm_via_private_t *dev_priv, int context); + + +#endif diff --git a/drivers/char/drm/via_ds.c b/drivers/char/drm/via_ds.c new file mode 100644 index 00000000000..daf3df75a20 --- /dev/null +++ b/drivers/char/drm/via_ds.c @@ -0,0 +1,280 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * + * 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 + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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 +#include +#include +#include +#include +#include +#include +#include + +#include "via_ds.h" +extern unsigned int VIA_DEBUG; + +set_t *via_setInit(void) +{ + int i; + set_t *set; + set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER); + for (i = 0; i < SET_SIZE; i++) { + set->list[i].free_next = i + 1; + set->list[i].alloc_next = -1; + } + set->list[SET_SIZE - 1].free_next = -1; + set->free = 0; + set->alloc = -1; + set->trace = -1; + return set; +} + +int via_setAdd(set_t * set, ITEM_TYPE item) +{ + int free = set->free; + if (free != -1) { + set->list[free].val = item; + set->free = set->list[free].free_next; + } else { + return 0; + } + set->list[free].alloc_next = set->alloc; + set->alloc = free; + set->list[free].free_next = -1; + return 1; +} + +int via_setDel(set_t * set, ITEM_TYPE item) +{ + int alloc = set->alloc; + int prev = -1; + + while (alloc != -1) { + if (set->list[alloc].val == item) { + if (prev != -1) + set->list[prev].alloc_next = + set->list[alloc].alloc_next; + else + set->alloc = set->list[alloc].alloc_next; + break; + } + prev = alloc; + alloc = set->list[alloc].alloc_next; + } + + if (alloc == -1) + return 0; + + set->list[alloc].free_next = set->free; + set->free = alloc; + set->list[alloc].alloc_next = -1; + + return 1; +} + +/* setFirst -> setAdd -> setNext is wrong */ + +int via_setFirst(set_t * set, ITEM_TYPE * item) +{ + if (set->alloc == -1) + return 0; + + *item = set->list[set->alloc].val; + set->trace = set->list[set->alloc].alloc_next; + + return 1; +} + +int via_setNext(set_t * set, ITEM_TYPE * item) +{ + if (set->trace == -1) + return 0; + + *item = set->list[set->trace].val; + set->trace = set->list[set->trace].alloc_next; + + return 1; +} + +int via_setDestroy(set_t * set) +{ + drm_free(set, sizeof(set_t), DRM_MEM_DRIVER); + + return 1; +} + +#define ISFREE(bptr) ((bptr)->free) + +#define fprintf(fmt, arg...) do{}while(0) + +memHeap_t *via_mmInit(int ofs, int size) +{ + PMemBlock blocks; + + if (size <= 0) + return 0; + + blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER); + + if (blocks) { + blocks->ofs = ofs; + blocks->size = size; + blocks->free = 1; + return (memHeap_t *) blocks; + } else + return 0; +} + +static TMemBlock *SliceBlock(TMemBlock * p, + int startofs, int size, + int reserved, int alignment) +{ + TMemBlock *newblock; + + /* break left */ + if (startofs > p->ofs) { + newblock = + (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), + DRM_MEM_DRIVER); + newblock->ofs = startofs; + newblock->size = p->size - (startofs - p->ofs); + newblock->free = 1; + newblock->next = p->next; + p->size -= newblock->size; + p->next = newblock; + p = newblock; + } + + /* break right */ + if (size < p->size) { + newblock = + (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), + DRM_MEM_DRIVER); + newblock->ofs = startofs + size; + newblock->size = p->size - size; + newblock->free = 1; + newblock->next = p->next; + p->size = size; + p->next = newblock; + } + + /* p = middle block */ + p->align = alignment; + p->free = 0; + p->reserved = reserved; + return p; +} + +PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2, + int startSearch) +{ + int mask, startofs, endofs; + TMemBlock *p; + + if (!heap || align2 < 0 || size <= 0) + return NULL; + + mask = (1 << align2) - 1; + startofs = 0; + p = (TMemBlock *) heap; + + while (p) { + if (ISFREE(p)) { + startofs = (p->ofs + mask) & ~mask; + + if (startofs < startSearch) + startofs = startSearch; + + endofs = startofs + size; + + if (endofs <= (p->ofs + p->size)) + break; + } + + p = p->next; + } + + if (!p) + return NULL; + + p = SliceBlock(p, startofs, size, 0, mask + 1); + p->heap = heap; + + return p; +} + +static __inline__ int Join2Blocks(TMemBlock * p) +{ + if (p->free && p->next && p->next->free) { + TMemBlock *q = p->next; + p->size += q->size; + p->next = q->next; + drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER); + + return 1; + } + + return 0; +} + +int via_mmFreeMem(PMemBlock b) +{ + TMemBlock *p, *prev; + + if (!b) + return 0; + + if (!b->heap) { + fprintf(stderr, "no heap\n"); + + return -1; + } + + p = b->heap; + prev = NULL; + + while (p && p != b) { + prev = p; + p = p->next; + } + + if (!p || p->free || p->reserved) { + if (!p) + fprintf(stderr, "block not found in heap\n"); + else if (p->free) + fprintf(stderr, "block already free\n"); + else + fprintf(stderr, "block is reserved\n"); + + return -1; + } + + p->free = 1; + Join2Blocks(p); + + if (prev) + Join2Blocks(prev); + + return 0; +} diff --git a/drivers/char/drm/via_ds.h b/drivers/char/drm/via_ds.h new file mode 100644 index 00000000000..be9c7f9f1ae --- /dev/null +++ b/drivers/char/drm/via_ds.h @@ -0,0 +1,104 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * 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 + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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. + */ +#ifndef _via_ds_h_ +#define _via_ds_h_ + +#include "drmP.h" + +/* Set Data Structure */ +#define SET_SIZE 5000 +typedef unsigned long ITEM_TYPE; + +typedef struct { + ITEM_TYPE val; + int alloc_next, free_next; +} list_item_t; + +typedef struct { + int alloc; + int free; + int trace; + list_item_t list[SET_SIZE]; +} set_t; + +set_t *via_setInit(void); +int via_setAdd(set_t * set, ITEM_TYPE item); +int via_setDel(set_t * set, ITEM_TYPE item); +int via_setFirst(set_t * set, ITEM_TYPE * item); +int via_setNext(set_t * set, ITEM_TYPE * item); +int via_setDestroy(set_t * set); + +#endif + +#ifndef MM_INC +#define MM_INC + +struct mem_block_t { + struct mem_block_t *next; + struct mem_block_t *heap; + int ofs, size; + int align; + int free:1; + int reserved:1; +}; +typedef struct mem_block_t TMemBlock; +typedef struct mem_block_t *PMemBlock; + +/* a heap is just the first block in a chain */ +typedef struct mem_block_t memHeap_t; + +static __inline__ int mmBlockSize(PMemBlock b) +{ + return b->size; +} + +static __inline__ int mmOffset(PMemBlock b) +{ + return b->ofs; +} + +static __inline__ void mmMarkReserved(PMemBlock b) +{ + b->reserved = 1; +} + +/* + * input: total size in bytes + * return: a heap pointer if OK, NULL if error + */ +memHeap_t *via_mmInit(int ofs, int size); + +PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2, + int startSearch); + +/* + * Free block starts at offset + * input: pointer to a block + * return: 0 if OK, -1 if error + */ +int via_mmFreeMem(PMemBlock b); + +#endif diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c new file mode 100644 index 00000000000..e8027f3a93b --- /dev/null +++ b/drivers/char/drm/via_irq.c @@ -0,0 +1,339 @@ +/* via_irq.c + * + * Copyright 2004 BEAM Ltd. + * Copyright 2002 Tungsten Graphics, Inc. + * Copyright 2005 Thomas Hellstrom. + * 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * BEAM LTD, TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + * Authors: + * Terry Barnaby + * Keith Whitwell + * Thomas Hellstrom + * + * This code provides standard DRM access to the Via Unichrome / Pro Vertical blank + * interrupt, as well as an infrastructure to handle other interrupts of the chip. + * The refresh rate is also calculated for video playback sync purposes. + */ + +#include "drmP.h" +#include "drm.h" +#include "via_drm.h" +#include "via_drv.h" + +#define VIA_REG_INTERRUPT 0x200 + +/* VIA_REG_INTERRUPT */ +#define VIA_IRQ_GLOBAL (1 << 31) +#define VIA_IRQ_VBLANK_ENABLE (1 << 19) +#define VIA_IRQ_VBLANK_PENDING (1 << 3) +#define VIA_IRQ_HQV0_ENABLE (1 << 11) +#define VIA_IRQ_HQV1_ENABLE (1 << 25) +#define VIA_IRQ_HQV0_PENDING (1 << 9) +#define VIA_IRQ_HQV1_PENDING (1 << 10) + +/* + * Device-specific IRQs go here. This type might need to be extended with + * the register if there are multiple IRQ control registers. + * Currently we activate the HQV interrupts of Unichrome Pro group A. + */ + +static maskarray_t via_pro_group_a_irqs[] = { + {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, 0x00000000 }, + {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, 0x00000000 }}; +static int via_num_pro_group_a = sizeof(via_pro_group_a_irqs)/sizeof(maskarray_t); + +static maskarray_t via_unichrome_irqs[] = {}; +static int via_num_unichrome = sizeof(via_unichrome_irqs)/sizeof(maskarray_t); + + +static unsigned time_diff(struct timeval *now,struct timeval *then) +{ + return (now->tv_usec >= then->tv_usec) ? + now->tv_usec - then->tv_usec : + 1000000 - (then->tv_usec - now->tv_usec); +} + +irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) +{ + drm_device_t *dev = (drm_device_t *) arg; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + u32 status; + int handled = 0; + struct timeval cur_vblank; + drm_via_irq_t *cur_irq = dev_priv->via_irqs; + int i; + + status = VIA_READ(VIA_REG_INTERRUPT); + if (status & VIA_IRQ_VBLANK_PENDING) { + atomic_inc(&dev->vbl_received); + if (!(atomic_read(&dev->vbl_received) & 0x0F)) { + do_gettimeofday(&cur_vblank); + if (dev_priv->last_vblank_valid) { + dev_priv->usec_per_vblank = + time_diff( &cur_vblank,&dev_priv->last_vblank) >> 4; + } + dev_priv->last_vblank = cur_vblank; + dev_priv->last_vblank_valid = 1; + } + if (!(atomic_read(&dev->vbl_received) & 0xFF)) { + DRM_DEBUG("US per vblank is: %u\n", + dev_priv->usec_per_vblank); + } + DRM_WAKEUP(&dev->vbl_queue); + drm_vbl_send_signals(dev); + handled = 1; + } + + + for (i=0; inum_irqs; ++i) { + if (status & cur_irq->pending_mask) { + atomic_inc( &cur_irq->irq_received ); + DRM_WAKEUP( &cur_irq->irq_queue ); + handled = 1; + } + cur_irq++; + } + + /* Acknowlege interrupts */ + VIA_WRITE(VIA_REG_INTERRUPT, status); + + + if (handled) + return IRQ_HANDLED; + else + return IRQ_NONE; +} + +static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv) +{ + u32 status; + + if (dev_priv) { + /* Acknowlege interrupts */ + status = VIA_READ(VIA_REG_INTERRUPT); + VIA_WRITE(VIA_REG_INTERRUPT, status | + dev_priv->irq_pending_mask); + } +} + +int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + unsigned int cur_vblank; + int ret = 0; + + DRM_DEBUG("viadrv_vblank_wait\n"); + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return -EINVAL; + } + + viadrv_acknowledge_irqs(dev_priv); + + /* Assume that the user has missed the current sequence number + * by about a day rather than she wants to wait for years + * using vertical blanks... + */ + + DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, + (((cur_vblank = atomic_read(&dev->vbl_received)) - + *sequence) <= (1 << 23))); + + *sequence = cur_vblank; + return ret; +} + +static int +via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, + unsigned int *sequence) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + unsigned int cur_irq_sequence; + drm_via_irq_t *cur_irq = dev_priv->via_irqs; + int ret = 0; + maskarray_t *masks = dev_priv->irq_masks; + + DRM_DEBUG("%s\n", __FUNCTION__); + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + return DRM_ERR(EINVAL); + } + + if (irq >= dev_priv->num_irqs ) { + DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, irq); + return DRM_ERR(EINVAL); + } + + cur_irq += irq; + + if (masks[irq][2] && !force_sequence) { + DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ, + ((VIA_READ(masks[irq][2]) & masks[irq][3]) == masks[irq][4])); + cur_irq_sequence = atomic_read(&cur_irq->irq_received); + } else { + DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ, + (((cur_irq_sequence = atomic_read(&cur_irq->irq_received)) - + *sequence) <= (1 << 23))); + } + *sequence = cur_irq_sequence; + return ret; +} + + +/* + * drm_dma.h hooks + */ + +void via_driver_irq_preinstall(drm_device_t * dev) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + u32 status; + drm_via_irq_t *cur_irq = dev_priv->via_irqs; + int i; + + DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv); + if (dev_priv) { + + dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE; + dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING; + + dev_priv->irq_masks = (dev_priv->pro_group_a) ? + via_pro_group_a_irqs : via_unichrome_irqs; + dev_priv->num_irqs = (dev_priv->pro_group_a) ? + via_num_pro_group_a : via_num_unichrome; + + for(i=0; i < dev_priv->num_irqs; ++i) { + atomic_set(&cur_irq->irq_received, 0); + cur_irq->enable_mask = dev_priv->irq_masks[i][0]; + cur_irq->pending_mask = dev_priv->irq_masks[i][1]; + DRM_INIT_WAITQUEUE( &cur_irq->irq_queue ); + dev_priv->irq_enable_mask |= cur_irq->enable_mask; + dev_priv->irq_pending_mask |= cur_irq->pending_mask; + cur_irq++; + + DRM_DEBUG("Initializing IRQ %d\n", i); + } + + dev_priv->last_vblank_valid = 0; + + // Clear VSync interrupt regs + status = VIA_READ(VIA_REG_INTERRUPT); + VIA_WRITE(VIA_REG_INTERRUPT, status & + ~(dev_priv->irq_enable_mask)); + + /* Clear bits if they're already high */ + viadrv_acknowledge_irqs(dev_priv); + } +} + +void via_driver_irq_postinstall(drm_device_t * dev) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + u32 status; + + DRM_DEBUG("via_driver_irq_postinstall\n"); + if (dev_priv) { + status = VIA_READ(VIA_REG_INTERRUPT); + VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL + | dev_priv->irq_enable_mask); + + /* Some magic, oh for some data sheets ! */ + + VIA_WRITE8(0x83d4, 0x11); + VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30); + + } +} + +void via_driver_irq_uninstall(drm_device_t * dev) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + u32 status; + + DRM_DEBUG("driver_irq_uninstall)\n"); + if (dev_priv) { + + /* Some more magic, oh for some data sheets ! */ + + VIA_WRITE8(0x83d4, 0x11); + VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30); + + status = VIA_READ(VIA_REG_INTERRUPT); + VIA_WRITE(VIA_REG_INTERRUPT, status & + ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask)); + } +} + +int via_wait_irq(DRM_IOCTL_ARGS) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + drm_via_irqwait_t __user *argp = (void __user *)data; + drm_via_irqwait_t irqwait; + struct timeval now; + int ret = 0; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + drm_via_irq_t *cur_irq = dev_priv->via_irqs; + int force_sequence; + + if (!dev->irq) + return DRM_ERR(EINVAL); + + DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait)); + if (irqwait.request.irq >= dev_priv->num_irqs) { + DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, + irqwait.request.irq); + return DRM_ERR(EINVAL); + } + + cur_irq += irqwait.request.irq; + + switch (irqwait.request.type & ~VIA_IRQ_FLAGS_MASK) { + case VIA_IRQ_RELATIVE: + irqwait.request.sequence += atomic_read(&cur_irq->irq_received); + irqwait.request.type &= ~_DRM_VBLANK_RELATIVE; + case VIA_IRQ_ABSOLUTE: + break; + default: + return DRM_ERR(EINVAL); + } + + if (irqwait.request.type & VIA_IRQ_SIGNAL) { + DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n", + __FUNCTION__); + return DRM_ERR(EINVAL); + } + + force_sequence = (irqwait.request.type & VIA_IRQ_FORCE_SEQUENCE); + + ret = via_driver_irq_wait(dev, irqwait.request.irq, force_sequence, + &irqwait.request.sequence); + do_gettimeofday(&now); + irqwait.reply.tval_sec = now.tv_sec; + irqwait.reply.tval_usec = now.tv_usec; + + DRM_COPY_TO_USER_IOCTL(argp, irqwait, sizeof(irqwait)); + + return ret; +} diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c new file mode 100644 index 00000000000..0be829b6ec6 --- /dev/null +++ b/drivers/char/drm/via_map.c @@ -0,0 +1,110 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. 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 + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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 "drmP.h" +#include "via_drm.h" +#include "via_drv.h" + +static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init) +{ + drm_via_private_t *dev_priv; + + DRM_DEBUG("%s\n", __FUNCTION__); + + dev_priv = drm_alloc(sizeof(drm_via_private_t), DRM_MEM_DRIVER); + if (dev_priv == NULL) + return -ENOMEM; + + memset(dev_priv, 0, sizeof(drm_via_private_t)); + + DRM_GETSAREA(); + if (!dev_priv->sarea) { + DRM_ERROR("could not find sarea!\n"); + dev->dev_private = (void *)dev_priv; + via_do_cleanup_map(dev); + return -EINVAL; + } + + dev_priv->fb = drm_core_findmap(dev, init->fb_offset); + if (!dev_priv->fb) { + DRM_ERROR("could not find framebuffer!\n"); + dev->dev_private = (void *)dev_priv; + via_do_cleanup_map(dev); + return -EINVAL; + } + dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); + if (!dev_priv->mmio) { + DRM_ERROR("could not find mmio region!\n"); + dev->dev_private = (void *)dev_priv; + via_do_cleanup_map(dev); + return -EINVAL; + } + + dev_priv->sarea_priv = + (drm_via_sarea_t *) ((u8 *) dev_priv->sarea->handle + + init->sarea_priv_offset); + + dev_priv->agpAddr = init->agpAddr; + + via_init_futex( dev_priv ); + dev_priv->pro_group_a = (dev->pdev->device == 0x3118); + + dev->dev_private = (void *)dev_priv; + return 0; +} + +int via_do_cleanup_map(drm_device_t * dev) +{ + if (dev->dev_private) { + + drm_via_private_t *dev_priv = dev->dev_private; + + via_dma_cleanup(dev); + + drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER); + dev->dev_private = NULL; + } + + return 0; +} + +int via_map_init(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_via_init_t init; + + DRM_DEBUG("%s\n", __FUNCTION__); + + DRM_COPY_FROM_USER_IOCTL(init, (drm_via_init_t *) data, sizeof(init)); + + switch (init.func) { + case VIA_INIT_MAP: + return via_do_init_map(dev, &init); + case VIA_CLEANUP_MAP: + return via_do_cleanup_map(dev); + } + + return -EINVAL; +} + + diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c new file mode 100644 index 00000000000..c22712f44d4 --- /dev/null +++ b/drivers/char/drm/via_mm.c @@ -0,0 +1,358 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. 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 + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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 "drmP.h" +#include "via_drm.h" +#include "via_drv.h" +#include "via_ds.h" +#include "via_mm.h" + +#define MAX_CONTEXT 100 + +typedef struct { + int used; + int context; + set_t *sets[2]; /* 0 for frame buffer, 1 for AGP , 2 for System */ +} via_context_t; + +static via_context_t global_ppriv[MAX_CONTEXT]; + +static int via_agp_alloc(drm_via_mem_t * mem); +static int via_agp_free(drm_via_mem_t * mem); +static int via_fb_alloc(drm_via_mem_t * mem); +static int via_fb_free(drm_via_mem_t * mem); + +static int add_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + + for (i = 0; i < MAX_CONTEXT; i++) { + if (global_ppriv[i].used && global_ppriv[i].context == context) { + retval = via_setAdd(global_ppriv[i].sets[type], val); + break; + } + } + + return retval; +} + +static int del_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + + for (i = 0; i < MAX_CONTEXT; i++) + if (global_ppriv[i].used && global_ppriv[i].context == context) { + retval = via_setDel(global_ppriv[i].sets[type], val); + break; + } + + return retval; +} + +/* agp memory management */ +static memHeap_t *AgpHeap = NULL; + +int via_agp_init(DRM_IOCTL_ARGS) +{ + drm_via_agp_t agp; + + DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t *) data, sizeof(agp)); + + AgpHeap = via_mmInit(agp.offset, agp.size); + + DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)agp.offset, (unsigned long)agp.size); + + return 0; +} + +/* fb memory management */ +static memHeap_t *FBHeap = NULL; + +int via_fb_init(DRM_IOCTL_ARGS) +{ + drm_via_fb_t fb; + + DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t *) data, sizeof(fb)); + + FBHeap = via_mmInit(fb.offset, fb.size); + + DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)fb.offset, (unsigned long)fb.size); + + return 0; +} + +int via_init_context(struct drm_device *dev, int context) +{ + int i; + + for (i = 0; i < MAX_CONTEXT; i++) + if (global_ppriv[i].used && + (global_ppriv[i].context == context)) + break; + + if (i >= MAX_CONTEXT) { + for (i = 0; i < MAX_CONTEXT; i++) { + if (!global_ppriv[i].used) { + global_ppriv[i].context = context; + global_ppriv[i].used = 1; + global_ppriv[i].sets[0] = via_setInit(); + global_ppriv[i].sets[1] = via_setInit(); + DRM_DEBUG("init allocation set, socket=%d," + " context = %d\n", i, context); + break; + } + } + + if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) || + (global_ppriv[i].sets[1] == NULL)) { + return 0; + } + } + + return 1; +} + +int via_final_context(struct drm_device *dev, int context) +{ + int i; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + + for (i = 0; i < MAX_CONTEXT; i++) + if (global_ppriv[i].used && + (global_ppriv[i].context == context)) + break; + + if (i < MAX_CONTEXT) { + set_t *set; + ITEM_TYPE item; + int retval; + + DRM_DEBUG("find socket %d, context = %d\n", i, context); + + /* Video Memory */ + set = global_ppriv[i].sets[0]; + retval = via_setFirst(set, &item); + while (retval) { + DRM_DEBUG("free video memory 0x%lx\n", item); + via_mmFreeMem((PMemBlock) item); + retval = via_setNext(set, &item); + } + via_setDestroy(set); + + /* AGP Memory */ + set = global_ppriv[i].sets[1]; + retval = via_setFirst(set, &item); + while (retval) { + DRM_DEBUG("free agp memory 0x%lx\n", item); + via_mmFreeMem((PMemBlock) item); + retval = via_setNext(set, &item); + } + via_setDestroy(set); + global_ppriv[i].used = 0; + } + via_release_futex(dev_priv, context); + + +#if defined(__linux__) + /* Linux specific until context tracking code gets ported to BSD */ + /* Last context, perform cleanup */ + if (dev->ctx_count == 1 && dev->dev_private) { + DRM_DEBUG("Last Context\n"); + if (dev->irq) + drm_irq_uninstall(dev); + + via_cleanup_futex(dev_priv); + via_do_cleanup_map(dev); + } +#endif + + return 1; +} + +int via_mem_alloc(DRM_IOCTL_ARGS) +{ + drm_via_mem_t mem; + + DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t *) data, sizeof(mem)); + + switch (mem.type) { + case VIDEO: + if (via_fb_alloc(&mem) < 0) + return -EFAULT; + DRM_COPY_TO_USER_IOCTL((drm_via_mem_t *) data, mem, + sizeof(mem)); + return 0; + case AGP: + if (via_agp_alloc(&mem) < 0) + return -EFAULT; + DRM_COPY_TO_USER_IOCTL((drm_via_mem_t *) data, mem, + sizeof(mem)); + return 0; + } + + return -EFAULT; +} + +static int via_fb_alloc(drm_via_mem_t * mem) +{ + drm_via_mm_t fb; + PMemBlock block; + int retval = 0; + + if (!FBHeap) + return -1; + + fb.size = mem->size; + fb.context = mem->context; + + block = via_mmAllocMem(FBHeap, fb.size, 5, 0); + if (block) { + fb.offset = block->ofs; + fb.free = (unsigned long)block; + if (!add_alloc_set(fb.context, VIDEO, fb.free)) { + DRM_DEBUG("adding to allocation set fails\n"); + via_mmFreeMem((PMemBlock) fb.free); + retval = -1; + } + } else { + fb.offset = 0; + fb.size = 0; + fb.free = 0; + retval = -1; + } + + mem->offset = fb.offset; + mem->index = fb.free; + + DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, + (int)fb.offset); + + return retval; +} + +static int via_agp_alloc(drm_via_mem_t * mem) +{ + drm_via_mm_t agp; + PMemBlock block; + int retval = 0; + + if (!AgpHeap) + return -1; + + agp.size = mem->size; + agp.context = mem->context; + + block = via_mmAllocMem(AgpHeap, agp.size, 5, 0); + if (block) { + agp.offset = block->ofs; + agp.free = (unsigned long)block; + if (!add_alloc_set(agp.context, AGP, agp.free)) { + DRM_DEBUG("adding to allocation set fails\n"); + via_mmFreeMem((PMemBlock) agp.free); + retval = -1; + } + } else { + agp.offset = 0; + agp.size = 0; + agp.free = 0; + } + + mem->offset = agp.offset; + mem->index = agp.free; + + DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, + (unsigned int)agp.offset); + return retval; +} + +int via_mem_free(DRM_IOCTL_ARGS) +{ + drm_via_mem_t mem; + + DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t *) data, sizeof(mem)); + + switch (mem.type) { + + case VIDEO: + if (via_fb_free(&mem) == 0) + return 0; + break; + case AGP: + if (via_agp_free(&mem) == 0) + return 0; + break; + } + + return -EFAULT; +} + +static int via_fb_free(drm_via_mem_t * mem) +{ + drm_via_mm_t fb; + int retval = 0; + + if (!FBHeap) { + return -1; + } + + fb.free = mem->index; + fb.context = mem->context; + + if (!fb.free) { + return -1; + + } + + via_mmFreeMem((PMemBlock) fb.free); + + if (!del_alloc_set(fb.context, VIDEO, fb.free)) { + retval = -1; + } + + DRM_DEBUG("free fb, free = %ld\n", fb.free); + + return retval; +} + +static int via_agp_free(drm_via_mem_t * mem) +{ + drm_via_mm_t agp; + + int retval = 0; + + agp.free = mem->index; + agp.context = mem->context; + + if (!agp.free) + return -1; + + via_mmFreeMem((PMemBlock) agp.free); + + if (!del_alloc_set(agp.context, AGP, agp.free)) { + retval = -1; + } + + DRM_DEBUG("free agp, free = %ld\n", agp.free); + + return retval; +} diff --git a/drivers/char/drm/via_mm.h b/drivers/char/drm/via_mm.h new file mode 100644 index 00000000000..d57efda57c7 --- /dev/null +++ b/drivers/char/drm/via_mm.h @@ -0,0 +1,40 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. 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 + * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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. + */ +#ifndef _via_drm_mm_h_ +#define _via_drm_mm_h_ + +typedef struct { + unsigned int context; + unsigned int size; + unsigned long offset; + unsigned long free; +} drm_via_mm_t; + +typedef struct { + unsigned int size; + unsigned long handle; + void *virtual; +} drm_via_dma_t; + +#endif diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c new file mode 100644 index 00000000000..07923b0c7a9 --- /dev/null +++ b/drivers/char/drm/via_verifier.c @@ -0,0 +1,1061 @@ +/* + * Copyright 2004 The Unichrome Project. All Rights Reserved. + * Copyright 2005 Thomas Hellstrom. 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(S), AND/OR THE COPYRIGHT HOLDER(S) 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. + * + * Author: Thomas Hellstrom 2004, 2005. + * This code was written using docs obtained under NDA from VIA Inc. + * + * Don't run this code directly on an AGP buffer. Due to cache problems it will + * be very slow. + */ + + +#include "via_3d_reg.h" +#include "drmP.h" +#include "drm.h" +#include "via_drm.h" +#include "via_verifier.h" +#include "via_drv.h" + +typedef enum{ + state_command, + state_header2, + state_header1, + state_vheader5, + state_vheader6, + state_error +} verifier_state_t; + + +typedef enum{ + no_check = 0, + check_for_header2, + check_for_header1, + check_for_header2_err, + check_for_header1_err, + check_for_fire, + check_z_buffer_addr0, + check_z_buffer_addr1, + check_z_buffer_addr_mode, + check_destination_addr0, + check_destination_addr1, + check_destination_addr_mode, + check_for_dummy, + check_for_dd, + check_texture_addr0, + check_texture_addr1, + check_texture_addr2, + check_texture_addr3, + check_texture_addr4, + check_texture_addr5, + check_texture_addr6, + check_texture_addr7, + check_texture_addr8, + check_texture_addr_mode, + check_for_vertex_count, + check_number_texunits, + forbidden_command +}hazard_t; + +/* + * Associates each hazard above with a possible multi-command + * sequence. For example an address that is split over multiple + * commands and that needs to be checked at the first command + * that does not include any part of the address. + */ + +static drm_via_sequence_t seqs[] = { + no_sequence, + no_sequence, + no_sequence, + no_sequence, + no_sequence, + no_sequence, + z_address, + z_address, + z_address, + dest_address, + dest_address, + dest_address, + no_sequence, + no_sequence, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + tex_address, + no_sequence +}; + +typedef struct{ + unsigned int code; + hazard_t hz; +} hz_init_t; + + + +static hz_init_t init_table1[] = { + {0xf2, check_for_header2_err}, + {0xf0, check_for_header1_err}, + {0xee, check_for_fire}, + {0xcc, check_for_dummy}, + {0xdd, check_for_dd}, + {0x00, no_check}, + {0x10, check_z_buffer_addr0}, + {0x11, check_z_buffer_addr1}, + {0x12, check_z_buffer_addr_mode}, + {0x13, no_check}, + {0x14, no_check}, + {0x15, no_check}, + {0x23, no_check}, + {0x24, no_check}, + {0x33, no_check}, + {0x34, no_check}, + {0x35, no_check}, + {0x36, no_check}, + {0x37, no_check}, + {0x38, no_check}, + {0x39, no_check}, + {0x3A, no_check}, + {0x3B, no_check}, + {0x3C, no_check}, + {0x3D, no_check}, + {0x3E, no_check}, + {0x40, check_destination_addr0}, + {0x41, check_destination_addr1}, + {0x42, check_destination_addr_mode}, + {0x43, no_check}, + {0x44, no_check}, + {0x50, no_check}, + {0x51, no_check}, + {0x52, no_check}, + {0x53, no_check}, + {0x54, no_check}, + {0x55, no_check}, + {0x56, no_check}, + {0x57, no_check}, + {0x58, no_check}, + {0x70, no_check}, + {0x71, no_check}, + {0x78, no_check}, + {0x79, no_check}, + {0x7A, no_check}, + {0x7B, no_check}, + {0x7C, no_check}, + {0x7D, check_for_vertex_count} +}; + + + +static hz_init_t init_table2[] = { + {0xf2, check_for_header2_err}, + {0xf0, check_for_header1_err}, + {0xee, check_for_fire}, + {0xcc, check_for_dummy}, + {0x00, check_texture_addr0}, + {0x01, check_texture_addr0}, + {0x02, check_texture_addr0}, + {0x03, check_texture_addr0}, + {0x04, check_texture_addr0}, + {0x05, check_texture_addr0}, + {0x06, check_texture_addr0}, + {0x07, check_texture_addr0}, + {0x08, check_texture_addr0}, + {0x09, check_texture_addr0}, + {0x20, check_texture_addr1}, + {0x21, check_texture_addr1}, + {0x22, check_texture_addr1}, + {0x23, check_texture_addr4}, + {0x2B, check_texture_addr3}, + {0x2C, check_texture_addr3}, + {0x2D, check_texture_addr3}, + {0x2E, check_texture_addr3}, + {0x2F, check_texture_addr3}, + {0x30, check_texture_addr3}, + {0x31, check_texture_addr3}, + {0x32, check_texture_addr3}, + {0x33, check_texture_addr3}, + {0x34, check_texture_addr3}, + {0x4B, check_texture_addr5}, + {0x4C, check_texture_addr6}, + {0x51, check_texture_addr7}, + {0x52, check_texture_addr8}, + {0x77, check_texture_addr2}, + {0x78, no_check}, + {0x79, no_check}, + {0x7A, no_check}, + {0x7B, check_texture_addr_mode}, + {0x7C, no_check}, + {0x7D, no_check}, + {0x7E, no_check}, + {0x7F, no_check}, + {0x80, no_check}, + {0x81, no_check}, + {0x82, no_check}, + {0x83, no_check}, + {0x85, no_check}, + {0x86, no_check}, + {0x87, no_check}, + {0x88, no_check}, + {0x89, no_check}, + {0x8A, no_check}, + {0x90, no_check}, + {0x91, no_check}, + {0x92, no_check}, + {0x93, no_check} +}; + +static hz_init_t init_table3[] = { + {0xf2, check_for_header2_err}, + {0xf0, check_for_header1_err}, + {0xcc, check_for_dummy}, + {0x00, check_number_texunits} +}; + + +static hazard_t table1[256]; +static hazard_t table2[256]; +static hazard_t table3[256]; + + + +static __inline__ int +eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words) +{ + if ((*buf - buf_end) >= num_words) { + *buf += num_words; + return 0; + } + DRM_ERROR("Illegal termination of DMA command buffer\n"); + return 1; +} + + +/* + * Partially stolen from drm_memory.h + */ + +static __inline__ drm_map_t * +via_drm_lookup_agp_map (drm_via_state_t *seq, unsigned long offset, unsigned long size, + drm_device_t *dev) +{ + struct list_head *list; + drm_map_list_t *r_list; + drm_map_t *map = seq->map_cache; + + if (map && map->offset <= offset && (offset + size) <= (map->offset + map->size)) { + return map; + } + + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *) list; + map = r_list->map; + if (!map) + continue; + if (map->offset <= offset && (offset + size) <= (map->offset + map->size) && + !(map->flags & _DRM_RESTRICTED) && (map->type == _DRM_AGP)) { + seq->map_cache = map; + return map; + } + } + return NULL; +} + + +/* + * Require that all AGP texture levels reside in the same AGP map which should + * be mappable by the client. This is not a big restriction. + * FIXME: To actually enforce this security policy strictly, drm_rmmap + * would have to wait for dma quiescent before removing an AGP map. + * The via_drm_lookup_agp_map call in reality seems to take + * very little CPU time. + */ + + +static __inline__ int +finish_current_sequence(drm_via_state_t *cur_seq) +{ + switch(cur_seq->unfinished) { + case z_address: + DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr); + break; + case dest_address: + DRM_DEBUG("Destination start address is 0x%x\n", cur_seq->d_addr); + break; + case tex_address: + if (cur_seq->agp_texture) { + unsigned start = cur_seq->tex_level_lo[cur_seq->texture]; + unsigned end = cur_seq->tex_level_hi[cur_seq->texture]; + unsigned long lo=~0, hi=0, tmp; + uint32_t *addr, *pitch, *height, tex; + unsigned i; + + if (end > 9) end = 9; + if (start > 9) start = 9; + + addr =&(cur_seq->t_addr[tex = cur_seq->texture][start]); + pitch = &(cur_seq->pitch[tex][start]); + height = &(cur_seq->height[tex][start]); + + for (i=start; i<= end; ++i) { + tmp = *addr++; + if (tmp < lo) lo = tmp; + tmp += (*height++ << *pitch++); + if (tmp > hi) hi = tmp; + } + + if (! via_drm_lookup_agp_map (cur_seq, lo, hi - lo, cur_seq->dev)) { + DRM_ERROR("AGP texture is not in allowed map\n"); + return 2; + } + } + break; + default: + break; + } + cur_seq->unfinished = no_sequence; + return 0; +} + +static __inline__ int +investigate_hazard( uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq) +{ + register uint32_t tmp, *tmp_addr; + + if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) { + int ret; + if ((ret = finish_current_sequence(cur_seq))) return ret; + } + + switch(hz) { + case check_for_header2: + if (cmd == HALCYON_HEADER2) return 1; + return 0; + case check_for_header1: + if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) return 1; + return 0; + case check_for_header2_err: + if (cmd == HALCYON_HEADER2) return 1; + DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n"); + break; + case check_for_header1_err: + if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) return 1; + DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n"); + break; + case check_for_fire: + if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD) return 1; + DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n"); + break; + case check_for_dummy: + if (HC_DUMMY == cmd) return 0; + DRM_ERROR("Illegal DMA HC_DUMMY command\n"); + break; + case check_for_dd: + if (0xdddddddd == cmd) return 0; + DRM_ERROR("Illegal DMA 0xdddddddd command\n"); + break; + case check_z_buffer_addr0: + cur_seq->unfinished = z_address; + cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) | + (cmd & 0x00FFFFFF); + return 0; + case check_z_buffer_addr1: + cur_seq->unfinished = z_address; + cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) | + ((cmd & 0xFF) << 24); + return 0; + case check_z_buffer_addr_mode: + cur_seq->unfinished = z_address; + if ((cmd & 0x0000C000) == 0) return 0; + DRM_ERROR("Attempt to place Z buffer in system memory\n"); + return 2; + case check_destination_addr0: + cur_seq->unfinished = dest_address; + cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) | + (cmd & 0x00FFFFFF); + return 0; + case check_destination_addr1: + cur_seq->unfinished = dest_address; + cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) | + ((cmd & 0xFF) << 24); + return 0; + case check_destination_addr_mode: + cur_seq->unfinished = dest_address; + if ((cmd & 0x0000C000) == 0) return 0; + DRM_ERROR("Attempt to place 3D drawing buffer in system memory\n"); + return 2; + case check_texture_addr0: + cur_seq->unfinished = tex_address; + tmp = (cmd >> 24); + tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp]; + *tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF); + return 0; + case check_texture_addr1: + cur_seq->unfinished = tex_address; + tmp = ((cmd >> 24) - 0x20); + tmp += tmp << 1; + tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp]; + *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24); + tmp_addr++; + *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16); + tmp_addr++; + *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8); + return 0; + case check_texture_addr2: + cur_seq->unfinished = tex_address; + cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F; + cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6; + return 0; + case check_texture_addr3: + cur_seq->unfinished = tex_address; + tmp = ((cmd >> 24) - 0x2B); + cur_seq->pitch[cur_seq->texture][tmp] = (cmd & 0x00F00000) >> 20; + if (!tmp && (cmd & 0x000FFFFF)) { + DRM_ERROR("Unimplemented texture level 0 pitch mode.\n"); + return 2; + } + return 0; + case check_texture_addr4: + cur_seq->unfinished = tex_address; + tmp_addr = &cur_seq->t_addr[cur_seq->texture][9]; + *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24); + return 0; + case check_texture_addr5: + case check_texture_addr6: + cur_seq->unfinished = tex_address; + /* + * Texture width. We don't care since we have the pitch. + */ + return 0; + case check_texture_addr7: + cur_seq->unfinished = tex_address; + tmp_addr = &(cur_seq->height[cur_seq->texture][0]); + tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20); + tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16); + tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12); + tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8); + tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4); + tmp_addr[0] = 1 << (cmd & 0x0000000F); + return 0; + case check_texture_addr8: + cur_seq->unfinished = tex_address; + tmp_addr = &(cur_seq->height[cur_seq->texture][0]); + tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12); + tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8); + tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4); + tmp_addr[6] = 1 << (cmd & 0x0000000F); + return 0; + case check_texture_addr_mode: + cur_seq->unfinished = tex_address; + if ( 2 == (tmp = cmd & 0x00000003)) { + DRM_ERROR("Attempt to fetch texture from system memory.\n"); + return 2; + } + cur_seq->agp_texture = (tmp == 3); + cur_seq->tex_palette_size[cur_seq->texture] = + (cmd >> 16) & 0x000000007; + return 0; + case check_for_vertex_count: + cur_seq->vertex_count = cmd & 0x0000FFFF; + return 0; + case check_number_texunits: + cur_seq->multitex = (cmd >> 3) & 1; + return 0; + default: + DRM_ERROR("Illegal DMA data: 0x%x\n", cmd); + return 2; + } + return 2; +} + + +static __inline__ int +via_check_prim_list(uint32_t const **buffer, const uint32_t *buf_end, + drm_via_state_t *cur_seq) +{ + drm_via_private_t *dev_priv = (drm_via_private_t *) cur_seq->dev->dev_private; + uint32_t a_fire, bcmd , dw_count; + int ret = 0; + int have_fire; + const uint32_t *buf = *buffer; + + while(buf < buf_end) { + have_fire = 0; + if ((buf_end - buf) < 2) { + DRM_ERROR("Unexpected termination of primitive list.\n"); + ret = 1; + break; + } + if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB) break; + bcmd = *buf++; + if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) { + DRM_ERROR("Expected Vertex List A command, got 0x%x\n", + *buf); + ret = 1; + break; + } + a_fire = *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK; + + /* + * How many dwords per vertex ? + */ + + if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) { + DRM_ERROR("Illegal B command vertex data for AGP.\n"); + ret = 1; + break; + } + + dw_count = 0; + if (bcmd & (1 << 7)) dw_count += (cur_seq->multitex) ? 2:1; + if (bcmd & (1 << 8)) dw_count += (cur_seq->multitex) ? 2:1; + if (bcmd & (1 << 9)) dw_count++; + if (bcmd & (1 << 10)) dw_count++; + if (bcmd & (1 << 11)) dw_count++; + if (bcmd & (1 << 12)) dw_count++; + if (bcmd & (1 << 13)) dw_count++; + if (bcmd & (1 << 14)) dw_count++; + + while(buf < buf_end) { + if (*buf == a_fire) { + if (dev_priv->num_fire_offsets >= VIA_FIRE_BUF_SIZE) { + DRM_ERROR("Fire offset buffer full.\n"); + ret = 1; + break; + } + dev_priv->fire_offsets[dev_priv->num_fire_offsets++] = buf; + have_fire = 1; + buf++; + if (buf < buf_end && *buf == a_fire) + buf++; + break; + } + if ((*buf == HALCYON_HEADER2) || + ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) { + DRM_ERROR("Missing Vertex Fire command, " + "Stray Vertex Fire command or verifier " + "lost sync.\n"); + ret = 1; + break; + } + if ((ret = eat_words(&buf, buf_end, dw_count))) + break; + } + if (buf >= buf_end && !have_fire) { + DRM_ERROR("Missing Vertex Fire command or verifier " + "lost sync.\n"); + ret = 1; + break; + } + if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) { + DRM_ERROR("AGP Primitive list end misaligned.\n"); + ret = 1; + break; + } + } + *buffer = buf; + return ret; +} + + + + + +static __inline__ verifier_state_t +via_check_header2( uint32_t const **buffer, const uint32_t *buf_end, + drm_via_state_t *hc_state) +{ + uint32_t cmd; + int hz_mode; + hazard_t hz; + const uint32_t *buf = *buffer; + const hazard_t *hz_table; + + + if ((buf_end - buf) < 2) { + DRM_ERROR("Illegal termination of DMA HALCYON_HEADER2 sequence.\n"); + return state_error; + } + buf++; + cmd = (*buf++ & 0xFFFF0000) >> 16; + + switch(cmd) { + case HC_ParaType_CmdVdata: + if (via_check_prim_list(&buf, buf_end, hc_state )) + return state_error; + *buffer = buf; + return state_command; + case HC_ParaType_NotTex: + hz_table = table1; + break; + case HC_ParaType_Tex: + hc_state->texture = 0; + hz_table = table2; + break; + case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)): + hc_state->texture = 1; + hz_table = table2; + break; + case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)): + hz_table = table3; + break; + case HC_ParaType_Auto: + if (eat_words(&buf, buf_end, 2)) + return state_error; + *buffer = buf; + return state_command; + case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)): + if (eat_words(&buf, buf_end, 32)) + return state_error; + *buffer = buf; + return state_command; + case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)): + case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)): + DRM_ERROR("Texture palettes are rejected because of " + "lack of info how to determine their size.\n"); + return state_error; + case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)): + DRM_ERROR("Fog factor palettes are rejected because of " + "lack of info how to determine their size.\n"); + return state_error; + default: + + /* + * There are some unimplemented HC_ParaTypes here, that + * need to be implemented if the Mesa driver is extended. + */ + + DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 " + "DMA subcommand: 0x%x. Previous dword: 0x%x\n", + cmd, *(buf -2)); + *buffer = buf; + return state_error; + } + + while(buf < buf_end) { + cmd = *buf++; + if ((hz = hz_table[cmd >> 24])) { + if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) { + if (hz_mode == 1) { + buf--; + break; + } + return state_error; + } + } else if (hc_state->unfinished && + finish_current_sequence(hc_state)) { + return state_error; + } + } + if (hc_state->unfinished && finish_current_sequence(hc_state)) { + return state_error; + } + *buffer = buf; + return state_command; +} + +static __inline__ verifier_state_t +via_parse_header2( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end, + int *fire_count) +{ + uint32_t cmd; + const uint32_t *buf = *buffer; + const uint32_t *next_fire; + int burst = 0; + + next_fire = dev_priv->fire_offsets[*fire_count]; + buf++; + cmd = (*buf & 0xFFFF0000) >> 16; + VIA_WRITE(HC_REG_TRANS_SET + HC_REG_BASE, *buf++); + switch(cmd) { + case HC_ParaType_CmdVdata: + while ((buf < buf_end) && + (*fire_count < dev_priv->num_fire_offsets) && + (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB ) { + while(buf <= next_fire) { + VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++); + burst += 4; + } + if ( ( buf < buf_end ) && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) + buf++; + + if (++(*fire_count) < dev_priv->num_fire_offsets) + next_fire = dev_priv->fire_offsets[*fire_count]; + } + break; + default: + while(buf < buf_end) { + + if ( *buf == HC_HEADER2 || + (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 || + (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 || + (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6 ) break; + + VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++); + burst +=4; + } + } + *buffer = buf; + return state_command; +} + + + +static __inline__ int +verify_mmio_address( uint32_t address) +{ + if ((address > 0x3FF) && (address < 0xC00 )) { + DRM_ERROR("Invalid VIDEO DMA command. " + "Attempt to access 3D- or command burst area.\n"); + return 1; + } else if ((address > 0xCFF) && (address < 0x1300)) { + DRM_ERROR("Invalid VIDEO DMA command. " + "Attempt to access PCI DMA area.\n"); + return 1; + } else if (address > 0x13FF ) { + DRM_ERROR("Invalid VIDEO DMA command. " + "Attempt to access VGA registers.\n"); + return 1; + } + return 0; +} + +static __inline__ int +verify_video_tail( uint32_t const **buffer, const uint32_t *buf_end, uint32_t dwords) +{ + const uint32_t *buf = *buffer; + + if (buf_end - buf < dwords) { + DRM_ERROR("Illegal termination of video command.\n"); + return 1; + } + while (dwords--) { + if (*buf++) { + DRM_ERROR("Illegal video command tail.\n"); + return 1; + } + } + *buffer = buf; + return 0; +} + + +static __inline__ verifier_state_t +via_check_header1( uint32_t const **buffer, const uint32_t *buf_end ) +{ + uint32_t cmd; + const uint32_t *buf = *buffer; + verifier_state_t ret = state_command; + + while (buf < buf_end) { + cmd = *buf; + if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) && + (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) { + if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) + break; + DRM_ERROR("Invalid HALCYON_HEADER1 command. " + "Attempt to access 3D- or command burst area.\n"); + ret = state_error; + break; + } else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) { + if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) + break; + DRM_ERROR("Invalid HALCYON_HEADER1 command. " + "Attempt to access VGA registers.\n"); + ret = state_error; + break; + } else { + buf += 2; + } + } + *buffer = buf; + return ret; +} + +static __inline__ verifier_state_t +via_parse_header1( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end ) +{ + register uint32_t cmd; + const uint32_t *buf = *buffer; + + while (buf < buf_end) { + cmd = *buf; + if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) break; + VIA_WRITE( (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf); + buf++; + } + *buffer = buf; + return state_command; +} + +static __inline__ verifier_state_t +via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end ) +{ + uint32_t data; + const uint32_t *buf = *buffer; + + if (buf_end - buf < 4) { + DRM_ERROR("Illegal termination of video header5 command\n"); + return state_error; + } + + data = *buf++ & ~VIA_VIDEOMASK; + if (verify_mmio_address(data)) + return state_error; + + data = *buf++; + if (*buf++ != 0x00F50000) { + DRM_ERROR("Illegal header5 header data\n"); + return state_error; + } + if (*buf++ != 0x00000000) { + DRM_ERROR("Illegal header5 header data\n"); + return state_error; + } + if (eat_words(&buf, buf_end, data)) + return state_error; + if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) + return state_error; + *buffer = buf; + return state_command; + +} + +static __inline__ verifier_state_t +via_parse_vheader5( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end ) +{ + uint32_t addr, count, i; + const uint32_t *buf = *buffer; + + addr = *buf++ & ~VIA_VIDEOMASK; + i = count = *buf; + buf += 3; + while(i--) { + VIA_WRITE(addr, *buf++); + } + if (count & 3) buf += 4 - (count & 3); + *buffer = buf; + return state_command; +} + + +static __inline__ verifier_state_t +via_check_vheader6( uint32_t const **buffer, const uint32_t *buf_end ) +{ + uint32_t data; + const uint32_t *buf = *buffer; + uint32_t i; + + + if (buf_end - buf < 4) { + DRM_ERROR("Illegal termination of video header6 command\n"); + return state_error; + } + buf++; + data = *buf++; + if (*buf++ != 0x00F60000) { + DRM_ERROR("Illegal header6 header data\n"); + return state_error; + } + if (*buf++ != 0x00000000) { + DRM_ERROR("Illegal header6 header data\n"); + return state_error; + } + if ((buf_end - buf) < (data << 1)) { + DRM_ERROR("Illegal termination of video header6 command\n"); + return state_error; + } + for (i=0; idev_private; + drm_via_state_t *hc_state = &dev_priv->hc_state; + drm_via_state_t saved_state = *hc_state; + uint32_t cmd; + const uint32_t *buf_end = buf + ( size >> 2 ); + verifier_state_t state = state_command; + int pro_group_a = dev_priv->pro_group_a; + + hc_state->dev = dev; + hc_state->unfinished = no_sequence; + hc_state->map_cache = NULL; + hc_state->agp = agp; + hc_state->buf_start = buf; + dev_priv->num_fire_offsets = 0; + + while (buf < buf_end) { + + switch (state) { + case state_header2: + state = via_check_header2( &buf, buf_end, hc_state ); + break; + case state_header1: + state = via_check_header1( &buf, buf_end ); + break; + case state_vheader5: + state = via_check_vheader5( &buf, buf_end ); + break; + case state_vheader6: + state = via_check_vheader6( &buf, buf_end ); + break; + case state_command: + if (HALCYON_HEADER2 == (cmd = *buf)) + state = state_header2; + else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) + state = state_header1; + else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) + state = state_vheader5; + else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) + state = state_vheader6; + else { + DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n", + cmd); + state = state_error; + } + break; + case state_error: + default: + *hc_state = saved_state; + return DRM_ERR(EINVAL); + } + } + if (state == state_error) { + *hc_state = saved_state; + return DRM_ERR(EINVAL); + } + return 0; +} + +int +via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size) +{ + + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + uint32_t cmd; + const uint32_t *buf_end = buf + ( size >> 2 ); + verifier_state_t state = state_command; + int fire_count = 0; + + while (buf < buf_end) { + + switch (state) { + case state_header2: + state = via_parse_header2( dev_priv, &buf, buf_end, &fire_count ); + break; + case state_header1: + state = via_parse_header1( dev_priv, &buf, buf_end ); + break; + case state_vheader5: + state = via_parse_vheader5( dev_priv, &buf, buf_end ); + break; + case state_vheader6: + state = via_parse_vheader6( dev_priv, &buf, buf_end ); + break; + case state_command: + if (HALCYON_HEADER2 == (cmd = *buf)) + state = state_header2; + else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) + state = state_header1; + else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) + state = state_vheader5; + else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) + state = state_vheader6; + else { + DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n", + cmd); + state = state_error; + } + break; + case state_error: + default: + return DRM_ERR(EINVAL); + } + } + if (state == state_error) { + return DRM_ERR(EINVAL); + } + return 0; +} + + + +static void +setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size) +{ + int i; + + for(i=0; i<256; ++i) { + table[i] = forbidden_command; + } + + for(i=0; idecoder_queue[i])); + XVMCLOCKPTR(dev_priv->sarea_priv, i)->lock = 0; + } +} + +void +via_cleanup_futex(drm_via_private_t *dev_priv) +{ +} + +void +via_release_futex(drm_via_private_t *dev_priv, int context) +{ + unsigned int i; + volatile int *lock; + + for (i=0; i < VIA_NR_XVMC_LOCKS; ++i) { + lock = (int *) XVMCLOCKPTR(dev_priv->sarea_priv, i); + if ( (_DRM_LOCKING_CONTEXT( *lock ) == context)) { + if (_DRM_LOCK_IS_HELD( *lock ) && (*lock & _DRM_LOCK_CONT)) { + DRM_WAKEUP( &(dev_priv->decoder_queue[i])); + } + *lock = 0; + } + } +} + +int +via_decoder_futex(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_via_futex_t fx; + volatile int *lock; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + drm_via_sarea_t *sAPriv = dev_priv->sarea_priv; + int ret = 0; + + DRM_DEBUG("%s\n", __FUNCTION__); + + DRM_COPY_FROM_USER_IOCTL(fx, (drm_via_futex_t *) data, sizeof(fx)); + + if (fx.lock > VIA_NR_XVMC_LOCKS) + return -EFAULT; + + lock = (int *)XVMCLOCKPTR(sAPriv, fx.lock); + + switch (fx.func) { + case VIA_FUTEX_WAIT: + DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx.lock], + (fx.ms / 10) * (DRM_HZ / 100), *lock != fx.val); + return ret; + case VIA_FUTEX_WAKE: + DRM_WAKEUP(&(dev_priv->decoder_queue[fx.lock])); + return 0; + } + return 0; +} + -- cgit v1.2.3 From 0dfc62465ef92c7ddcb1ba223bf062453566fd0f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 31 May 2005 20:39:20 +0100 Subject: [MTD] NAND: Reorganize chip locking The code was wrong in several aspects. The locking order was inconsistent, the device aquire code did not reset a variable after a wakeup and the wakeup handling was not working for applications where multiple chips are sharing a single hardware controller. When a hardware controller is available the locking is now reduced to the hardware controller lock and the waitqueue is moved to the hardware controller structure in order to avoid a wake_up_all(). The problem was pointed out by Ben Dooks, who also found the missing variable reset as main cause for his deadlock problem. Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 57 ++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index f1db0bf9306..bbe0283433d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.143 2005/05/19 16:10:22 gleixner Exp $ + * $Id: nand_base.c,v 1.145 2005/05/31 20:32:53 gleixner Exp $ * * 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 @@ -167,17 +167,21 @@ static void nand_release_device (struct mtd_info *mtd) /* De-select the NAND device */ this->select_chip(mtd, -1); - /* Do we have a hardware controller ? */ + if (this->controller) { + /* Release the controller and the chip */ spin_lock(&this->controller->lock); this->controller->active = NULL; + this->state = FL_READY; + wake_up(&this->controller->wq); spin_unlock(&this->controller->lock); + } else { + /* Release the chip */ + spin_lock(&this->chip_lock); + this->state = FL_READY; + wake_up(&this->wq); + spin_unlock(&this->chip_lock); } - /* Release the chip */ - spin_lock (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock (&this->chip_lock); } /** @@ -753,37 +757,34 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, */ static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) { - struct nand_chip *active = this; - + struct nand_chip *active; + spinlock_t *lock; + wait_queue_head_t *wq; DECLARE_WAITQUEUE (wait, current); - /* - * Grab the lock and see if the device is available - */ + lock = (this->controller) ? &this->controller->lock : &this->chip_lock; + wq = (this->controller) ? &this->controller->wq : &this->wq; retry: + active = this; + spin_lock(lock); + /* Hardware controller shared among independend devices */ if (this->controller) { - spin_lock (&this->controller->lock); if (this->controller->active) active = this->controller->active; else this->controller->active = this; - spin_unlock (&this->controller->lock); } - - if (active == this) { - spin_lock (&this->chip_lock); - if (this->state == FL_READY) { - this->state = new_state; - spin_unlock (&this->chip_lock); - return; - } - } - set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&active->wq, &wait); - spin_unlock (&active->chip_lock); - schedule (); - remove_wait_queue (&active->wq, &wait); + if (active == this && this->state == FL_READY) { + this->state = new_state; + spin_unlock(lock); + return; + } + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(wq, &wait); + spin_unlock(lock); + schedule(); + remove_wait_queue(wq, &wait); goto retry; } -- cgit v1.2.3 From 02b15e343aeefb49f8cac949be599d78250a568f Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Tue, 7 Jun 2005 00:04:39 +0100 Subject: [MTD] XIP for AMD CFI flash. Author: Vitaly Wool Signed-off-by: Todd Poynor Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/Kconfig | 4 +- drivers/mtd/chips/cfi_cmdset_0002.c | 402 ++++++++++++++++++++++++++++-------- drivers/mtd/chips/fwh_lock.h | 6 +- drivers/mtd/maps/map_funcs.c | 11 +- 4 files changed, 323 insertions(+), 100 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index f4eda1e40d5..b5dc59389bb 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/chips/Kconfig -# $Id: Kconfig,v 1.14 2005/02/08 17:11:15 nico Exp $ +# $Id: Kconfig,v 1.15 2005/06/06 23:04:35 tpoynor Exp $ menu "RAM/ROM/Flash chip drivers" depends on MTD!=n @@ -300,7 +300,7 @@ config MTD_JEDEC config MTD_XIP bool "XIP aware MTD support" - depends on !SMP && MTD_CFI_INTELEXT && EXPERIMENTAL + depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && EXPERIMENTAL default y if XIP_KERNEL help This allows MTD support to work with flash memory which is also diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 49cd8120713..e42eefbda0e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -4,16 +4,20 @@ * * Copyright (C) 2000 Crossnet Co. * Copyright (C) 2004 Arcom Control Systems Ltd + * Copyright (C) 2005 MontaVista Software Inc. * * 2_by_8 routines added by Simon Munton * * 4_by_16 work by Carolyn J. Smith * + * XIP support hooks by Vitaly Wool (based on code for Intel flash + * by Nicolas Pitre) + * * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com * * This code is GPL * - * $Id: cfi_cmdset_0002.c,v 1.116 2005/05/24 13:29:42 gleixner Exp $ + * $Id: cfi_cmdset_0002.c,v 1.117 2005/06/06 23:04:35 tpoynor Exp $ * */ @@ -34,6 +38,7 @@ #include #include #include +#include #define AMD_BOOTLOC_BUG #define FORCE_WORD_WRITE 0 @@ -393,7 +398,7 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) * correctly and is therefore not done (particulary with interleaved chips * as each chip must be checked independantly of the others). */ -static int chip_ready(struct map_info *map, unsigned long addr) +static int __xipram chip_ready(struct map_info *map, unsigned long addr) { map_word d, t; @@ -418,7 +423,7 @@ static int chip_ready(struct map_info *map, unsigned long addr) * as each chip must be checked independantly of the others). * */ -static int chip_good(struct map_info *map, unsigned long addr, map_word expected) +static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected) { map_word oldd, curd; @@ -448,12 +453,12 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr if (time_after(jiffies, timeo)) { printk(KERN_ERR "Waiting for chip to be ready timed out.\n"); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return -EIO; } - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); cfi_udelay(1); - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); /* Someone else might have been playing with it. */ goto retry; } @@ -501,15 +506,23 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr return -EIO; } - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); cfi_udelay(1); - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING. So we can just loop here. */ } chip->state = FL_READY; return 0; + case FL_XIP_WHILE_ERASING: + if (mode != FL_READY && mode != FL_POINT && + (!cfip || !(cfip->EraseSuspend&2))) + goto sleep; + chip->oldstate = chip->state; + chip->state = FL_READY; + return 0; + case FL_POINT: /* Only if there's no operation suspended... */ if (mode == FL_READY && chip->oldstate == FL_READY) @@ -519,10 +532,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr sleep: set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); goto resettime; } } @@ -540,6 +553,11 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad chip->state = FL_ERASING; break; + case FL_XIP_WHILE_ERASING: + chip->state = chip->oldstate; + chip->oldstate = FL_READY; + break; + case FL_READY: case FL_STATUS: /* We should really make set_vpp() count, rather than doing this */ @@ -551,6 +569,198 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad wake_up(&chip->wq); } +#ifdef CONFIG_MTD_XIP + +/* + * No interrupt what so ever can be serviced while the flash isn't in array + * mode. This is ensured by the xip_disable() and xip_enable() functions + * enclosing any code path where the flash is known not to be in array mode. + * And within a XIP disabled code path, only functions marked with __xipram + * may be called and nothing else (it's a good thing to inspect generated + * assembly to make sure inline functions were actually inlined and that gcc + * didn't emit calls to its own support functions). Also configuring MTD CFI + * support to a single buswidth and a single interleave is also recommended. + */ +#include +static void xip_disable(struct map_info *map, struct flchip *chip, + unsigned long adr) +{ + /* TODO: chips with no XIP use should ignore and return */ + (void) map_read(map, adr); /* ensure mmu mapping is up to date */ + local_irq_disable(); +} + +static void __xipram xip_enable(struct map_info *map, struct flchip *chip, + unsigned long adr) +{ + struct cfi_private *cfi = map->fldrv_priv; + + if (chip->state != FL_POINT && chip->state != FL_READY) { + map_write(map, CMD(0xf0), adr); + chip->state = FL_READY; + } + (void) map_read(map, adr); + asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */ + local_irq_enable(); +} + +/* + * When a delay is required for the flash operation to complete, the + * xip_udelay() function is polling for both the given timeout and pending + * (but still masked) hardware interrupts. Whenever there is an interrupt + * pending then the flash erase operation is suspended, array mode restored + * and interrupts unmasked. Task scheduling might also happen at that + * point. The CPU eventually returns from the interrupt or the call to + * schedule() and the suspended flash operation is resumed for the remaining + * of the delay period. + * + * Warning: this function _will_ fool interrupt latency tracing tools. + */ + +static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, + unsigned long adr, int usec) +{ + struct cfi_private *cfi = map->fldrv_priv; + struct cfi_pri_amdstd *extp = cfi->cmdset_priv; + map_word status, OK = CMD(0x80); + unsigned long suspended, start = xip_currtime(); + flstate_t oldstate; + + do { + cpu_relax(); + if (xip_irqpending() && extp && + ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) && + (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) { + /* + * Let's suspend the erase operation when supported. + * Note that we currently don't try to suspend + * interleaved chips if there is already another + * operation suspended (imagine what happens + * when one chip was already done with the current + * operation while another chip suspended it, then + * we resume the whole thing at once). Yes, it + * can happen! + */ + map_write(map, CMD(0xb0), adr); + usec -= xip_elapsed_since(start); + suspended = xip_currtime(); + do { + if (xip_elapsed_since(suspended) > 100000) { + /* + * The chip doesn't want to suspend + * after waiting for 100 msecs. + * This is a critical error but there + * is not much we can do here. + */ + return; + } + status = map_read(map, adr); + } while (!map_word_andequal(map, status, OK, OK)); + + /* Suspend succeeded */ + oldstate = chip->state; + if (!map_word_bitsset(map, status, CMD(0x40))) + break; + chip->state = FL_XIP_WHILE_ERASING; + chip->erase_suspended = 1; + map_write(map, CMD(0xf0), adr); + (void) map_read(map, adr); + asm volatile (".rep 8; nop; .endr"); + local_irq_enable(); + spin_unlock(chip->mutex); + asm volatile (".rep 8; nop; .endr"); + cond_resched(); + + /* + * We're back. However someone else might have + * decided to go write to the chip if we are in + * a suspended erase state. If so let's wait + * until it's done. + */ + spin_lock(chip->mutex); + while (chip->state != FL_XIP_WHILE_ERASING) { + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + spin_lock(chip->mutex); + } + /* Disallow XIP again */ + local_irq_disable(); + + /* Resume the write or erase operation */ + map_write(map, CMD(0x30), adr); + chip->state = oldstate; + start = xip_currtime(); + } else if (usec >= 1000000/HZ) { + /* + * Try to save on CPU power when waiting delay + * is at least a system timer tick period. + * No need to be extremely accurate here. + */ + xip_cpu_idle(); + } + status = map_read(map, adr); + } while (!map_word_andequal(map, status, OK, OK) + && xip_elapsed_since(start) < usec); +} + +#define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec) + +/* + * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while + * the flash is actively programming or erasing since we have to poll for + * the operation to complete anyway. We can't do that in a generic way with + * a XIP setup so do it before the actual flash operation in this case + * and stub it out from INVALIDATE_CACHE_UDELAY. + */ +#define XIP_INVAL_CACHED_RANGE(map, from, size) \ + INVALIDATE_CACHED_RANGE(map, from, size) + +#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \ + UDELAY(map, chip, adr, usec) + +/* + * Extra notes: + * + * Activating this XIP support changes the way the code works a bit. For + * example the code to suspend the current process when concurrent access + * happens is never executed because xip_udelay() will always return with the + * same chip state as it was entered with. This is why there is no care for + * the presence of add_wait_queue() or schedule() calls from within a couple + * xip_disable()'d areas of code, like in do_erase_oneblock for example. + * The queueing and scheduling are always happening within xip_udelay(). + * + * Similarly, get_chip() and put_chip() just happen to always be executed + * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state + * is in array mode, therefore never executing many cases therein and not + * causing any problem with XIP. + */ + +#else + +#define xip_disable(map, chip, adr) +#define xip_enable(map, chip, adr) +#define XIP_INVAL_CACHED_RANGE(x...) + +#define UDELAY(map, chip, adr, usec) \ +do { \ + spin_unlock(chip->mutex); \ + cfi_udelay(usec); \ + spin_lock(chip->mutex); \ +} while (0) + +#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \ +do { \ + spin_unlock(chip->mutex); \ + INVALIDATE_CACHED_RANGE(map, adr, len); \ + cfi_udelay(usec); \ + spin_lock(chip->mutex); \ +} while (0) + +#endif static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) { @@ -563,10 +773,10 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof /* Ensure cmd read/writes are aligned. */ cmd_addr = adr & ~(map_bankwidth(map)-1); - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, cmd_addr, FL_READY); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -579,7 +789,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof put_chip(map, chip, cmd_addr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return 0; } @@ -633,7 +843,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi struct cfi_private *cfi = map->fldrv_priv; retry: - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); if (chip->state != FL_READY){ #if 0 @@ -642,7 +852,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); @@ -671,7 +881,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); wake_up(&chip->wq); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return 0; } @@ -720,7 +930,7 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len, } -static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum) +static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum) { struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; @@ -740,10 +950,10 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned adr += chip->start; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_WRITING); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -763,7 +973,9 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned goto op_done; } + XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map)); ENABLE_VPP(map); + xip_disable(map, chip, adr); retry: cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); @@ -771,9 +983,9 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned map_write(map, datum, adr); chip->state = FL_WRITING; - cfi_spin_unlock(chip->mutex); - cfi_udelay(chip->word_write_time); - cfi_spin_lock(chip->mutex); + INVALIDATE_CACHE_UDELAY(map, chip, + adr, map_bankwidth(map), + chip->word_write_time); /* See comment above for timeout value. */ timeo = jiffies + uWriteTimeout; @@ -784,11 +996,11 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); timeo = jiffies + (HZ / 2); /* FIXME */ - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); continue; } @@ -796,14 +1008,14 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned break; if (time_after(jiffies, timeo)) { + xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); + xip_disable(map, chip, adr); break; } /* Latency issues. Drop the lock, wait a while and retry */ - cfi_spin_unlock(chip->mutex); - cfi_udelay(1); - cfi_spin_lock(chip->mutex); + UDELAY(map, chip, adr, 1); } /* Did we succeed? */ if (!chip_good(map, adr, datum)) { @@ -816,10 +1028,11 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned ret = -EIO; } + xip_enable(map, chip, adr); op_done: chip->state = FL_READY; put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -851,7 +1064,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, map_word tmp_buf; retry: - cfi_spin_lock(cfi->chips[chipnum].mutex); + spin_lock(cfi->chips[chipnum].mutex); if (cfi->chips[chipnum].state != FL_READY) { #if 0 @@ -860,7 +1073,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&cfi->chips[chipnum].wq, &wait); - cfi_spin_unlock(cfi->chips[chipnum].mutex); + spin_unlock(cfi->chips[chipnum].mutex); schedule(); remove_wait_queue(&cfi->chips[chipnum].wq, &wait); @@ -874,7 +1087,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, /* Load 'tmp_buf' with old contents of flash */ tmp_buf = map_read(map, bus_ofs+chipstart); - cfi_spin_unlock(cfi->chips[chipnum].mutex); + spin_unlock(cfi->chips[chipnum].mutex); /* Number of bytes to copy from buffer */ n = min_t(int, len, map_bankwidth(map)-i); @@ -929,7 +1142,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, map_word tmp_buf; retry1: - cfi_spin_lock(cfi->chips[chipnum].mutex); + spin_lock(cfi->chips[chipnum].mutex); if (cfi->chips[chipnum].state != FL_READY) { #if 0 @@ -938,7 +1151,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&cfi->chips[chipnum].wq, &wait); - cfi_spin_unlock(cfi->chips[chipnum].mutex); + spin_unlock(cfi->chips[chipnum].mutex); schedule(); remove_wait_queue(&cfi->chips[chipnum].wq, &wait); @@ -951,7 +1164,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, tmp_buf = map_read(map, ofs + chipstart); - cfi_spin_unlock(cfi->chips[chipnum].mutex); + spin_unlock(cfi->chips[chipnum].mutex); tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); @@ -970,8 +1183,9 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, /* * FIXME: interleaved mode not tested, and probably not supported! */ -static inline int do_write_buffer(struct map_info *map, struct flchip *chip, - unsigned long adr, const u_char *buf, int len) +static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, + unsigned long adr, const u_char *buf, + int len) { struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; @@ -985,10 +1199,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, adr += chip->start; cmd_adr = adr; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_WRITING); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -997,7 +1211,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", __func__, adr, datum.x[0] ); + XIP_INVAL_CACHED_RANGE(map, adr, len); ENABLE_VPP(map); + xip_disable(map, chip, cmd_adr); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -1027,9 +1244,9 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, map_write(map, CMD(0x29), cmd_adr); chip->state = FL_WRITING; - cfi_spin_unlock(chip->mutex); - cfi_udelay(chip->buffer_write_time); - cfi_spin_lock(chip->mutex); + INVALIDATE_CACHE_UDELAY(map, chip, + adr, map_bankwidth(map), + chip->word_write_time); timeo = jiffies + uWriteTimeout; @@ -1040,38 +1257,39 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); timeo = jiffies + (HZ / 2); /* FIXME */ - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); continue; } - if (chip_ready(map, adr)) + if (chip_ready(map, adr)) { + xip_enable(map, chip, adr); goto op_done; + } if( time_after(jiffies, timeo)) break; /* Latency issues. Drop the lock, wait a while and retry */ - cfi_spin_unlock(chip->mutex); - cfi_udelay(1); - cfi_spin_lock(chip->mutex); + UDELAY(map, chip, adr, 1); } - printk(KERN_WARNING "MTD %s(): software timeout\n", - __func__ ); - /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); + xip_enable(map, chip, adr); /* FIXME - should have reset delay before continuing */ + printk(KERN_WARNING "MTD %s(): software timeout\n", + __func__ ); + ret = -EIO; op_done: chip->state = FL_READY; put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -1161,7 +1379,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, * Handle devices with one erase region, that only implement * the chip erase command. */ -static inline int do_erase_chip(struct map_info *map, struct flchip *chip) +static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) { struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; @@ -1171,17 +1389,20 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) adr = cfi->addr_unlock1; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_WRITING); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", __func__, chip->start ); + XIP_INVAL_CACHED_RANGE(map, adr, map->size); ENABLE_VPP(map); + xip_disable(map, chip, adr); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -1193,9 +1414,9 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) chip->erase_suspended = 0; chip->in_progress_block_addr = adr; - cfi_spin_unlock(chip->mutex); - msleep(chip->erase_time/2); - cfi_spin_lock(chip->mutex); + INVALIDATE_CACHE_UDELAY(map, chip, + adr, map->size, + chip->erase_time*500); timeo = jiffies + (HZ*20); @@ -1204,10 +1425,10 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) /* Someone's suspended the erase. Sleep */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); continue; } if (chip->erase_suspended) { @@ -1227,10 +1448,7 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) } /* Latency issues. Drop the lock, wait a while and retry */ - cfi_spin_unlock(chip->mutex); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - cfi_spin_lock(chip->mutex); + UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ if (!chip_good(map, adr, map_word_ff(map))) { @@ -1242,14 +1460,15 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) } chip->state = FL_READY; + xip_enable(map, chip, adr); put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } -static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) +static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) { struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; @@ -1258,17 +1477,20 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u adr += chip->start; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_ERASING); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", __func__, adr ); + XIP_INVAL_CACHED_RANGE(map, adr, len); ENABLE_VPP(map); + xip_disable(map, chip, adr); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -1279,10 +1501,10 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u chip->state = FL_ERASING; chip->erase_suspended = 0; chip->in_progress_block_addr = adr; - - cfi_spin_unlock(chip->mutex); - msleep(chip->erase_time/2); - cfi_spin_lock(chip->mutex); + + INVALIDATE_CACHE_UDELAY(map, chip, + adr, len, + chip->erase_time*500); timeo = jiffies + (HZ*20); @@ -1291,10 +1513,10 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u /* Someone's suspended the erase. Sleep */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); continue; } if (chip->erase_suspended) { @@ -1304,20 +1526,20 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u chip->erase_suspended = 0; } - if (chip_ready(map, adr)) + if (chip_ready(map, adr)) { + xip_enable(map, chip, adr); break; + } if (time_after(jiffies, timeo)) { + xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__ ); break; } /* Latency issues. Drop the lock, wait a while and retry */ - cfi_spin_unlock(chip->mutex); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - cfi_spin_lock(chip->mutex); + UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ if (!chip_good(map, adr, map_word_ff(map))) { @@ -1330,7 +1552,7 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u chip->state = FL_READY; put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -1390,7 +1612,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) chip = &cfi->chips[i]; retry: - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); switch(chip->state) { case FL_READY: @@ -1404,14 +1626,14 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) * with the chip now anyway. */ case FL_SYNCING: - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); break; default: /* Not an idle state */ add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); @@ -1426,13 +1648,13 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) for (i--; i >=0; i--) { chip = &cfi->chips[i]; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; wake_up(&chip->wq); } - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); } } @@ -1448,7 +1670,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) for (i=0; !ret && inumchips; i++) { chip = &cfi->chips[i]; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); switch(chip->state) { case FL_READY: @@ -1468,7 +1690,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) ret = -EAGAIN; break; } - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); } /* Unlock the chips again */ @@ -1477,13 +1699,13 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) for (i--; i >=0; i--) { chip = &cfi->chips[i]; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); if (chip->state == FL_PM_SUSPENDED) { chip->state = chip->oldstate; wake_up(&chip->wq); } - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); } } @@ -1502,7 +1724,7 @@ static void cfi_amdstd_resume(struct mtd_info *mtd) chip = &cfi->chips[i]; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); if (chip->state == FL_PM_SUSPENDED) { chip->state = FL_READY; @@ -1512,7 +1734,7 @@ static void cfi_amdstd_resume(struct mtd_info *mtd) else printk(KERN_ERR "Argh. Chip not in PM_SUSPENDED state upon resume()\n"); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); } } diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index fbf44708a86..e1a5b76596c 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h @@ -58,10 +58,10 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, * to flash memory - that means that we don't have to check status * and timeout. */ - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_LOCKING); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -71,7 +71,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, /* Done and happy. */ chip->state = FL_READY; put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return 0; } diff --git a/drivers/mtd/maps/map_funcs.c b/drivers/mtd/maps/map_funcs.c index 38f6a7af53f..9105e6ca0aa 100644 --- a/drivers/mtd/maps/map_funcs.c +++ b/drivers/mtd/maps/map_funcs.c @@ -1,5 +1,5 @@ /* - * $Id: map_funcs.c,v 1.9 2004/07/13 22:33:15 dwmw2 Exp $ + * $Id: map_funcs.c,v 1.10 2005/06/06 23:04:36 tpoynor Exp $ * * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS * is enabled. @@ -9,23 +9,24 @@ #include #include +#include -static map_word simple_map_read(struct map_info *map, unsigned long ofs) +static map_word __xipram simple_map_read(struct map_info *map, unsigned long ofs) { return inline_map_read(map, ofs); } -static void simple_map_write(struct map_info *map, const map_word datum, unsigned long ofs) +static void __xipram simple_map_write(struct map_info *map, const map_word datum, unsigned long ofs) { inline_map_write(map, datum, ofs); } -static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +static void __xipram simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) { inline_map_copy_from(map, to, from, len); } -static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +static void __xipram simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) { inline_map_copy_to(map, to, from, len); } -- cgit v1.2.3 From be76c5fb406fad93ab93ba39e7858e03d58c5d30 Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Tue, 7 Jun 2005 16:04:29 +0100 Subject: [MTD] Fix commandline parser alignement Add alignment to cmdline. From: "Timofei V. Bondarenko" Signed-off-by: Joern Engel Signed-off-by: Thomas Gleixner --- drivers/mtd/cmdlinepart.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 60ab4b89a2f..ef24837019d 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -1,5 +1,5 @@ /* - * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $ + * $Id: cmdlinepart.c,v 1.18 2005/06/07 15:04:26 joern Exp $ * * Read flash partition table from command line * @@ -239,7 +239,8 @@ static int mtdpart_setup_real(char *s) &num_parts, /* out: number of parts */ 0, /* first partition */ (unsigned char**)&this_mtd, /* out: extra mem */ - mtd_id_len + 1 + sizeof(*this_mtd)); + mtd_id_len + 1 + sizeof(*this_mtd) + + sizeof(void*)-1 /*alignment*/); if(!parts) { /* @@ -252,6 +253,9 @@ static int mtdpart_setup_real(char *s) return 0; } + /* align this_mtd */ + this_mtd = (struct cmdline_mtd_partition *) + ALIGN((unsigned long)this_mtd, sizeof(void*)); /* enter results */ this_mtd->parts = parts; this_mtd->num_parts = num_parts; -- cgit v1.2.3 From c9e0536523f5191395d62f6c84d007e6ffd38d33 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 14 Jun 2005 16:39:57 +0100 Subject: [MTD] NAND: Fix broken bad block table scan Make the bad block table search functional again Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_bbt.c | 53 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index c85c69dec54..5ac2d296222 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -6,7 +6,7 @@ * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_bbt.c,v 1.31 2005/02/16 17:09:36 dedekind Exp $ + * $Id: nand_bbt.c,v 1.33 2005/06/14 15:47:56 gleixner Exp $ * * 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 @@ -80,14 +80,14 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des int i, end = 0; uint8_t *p = buf; + end = paglen + td->offs; if (td->options & NAND_BBT_SCANEMPTY) { - end = paglen + td->offs; for (i = 0; i < end; i++) { if (p[i] != 0xff) return -1; } - p += end; } + p += end; /* Compare the pattern */ for (i = 0; i < td->len; i++) { @@ -106,6 +106,32 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des return 0; } +/** + * check_short_pattern - [GENERIC] check if a pattern is in the buffer + * @buf: the buffer to search + * @len: the length of buffer to search + * @paglen: the pagelength + * @td: search pattern descriptor + * + * Check for a pattern at the given place. Used to search bad block + * tables and good / bad block identifiers. Same as check_pattern, but + * no optional empty check and the pattern is expected to start + * at offset 0. + * +*/ +static int check_short_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) +{ + int i; + uint8_t *p = buf; + + /* Compare the pattern */ + for (i = 0; i < td->len; i++) { + if (p[i] != td->pattern[i]) + return -1; + } + return 0; +} + /** * read_bbt - [GENERIC] Read the bad block table starting from page * @mtd: MTD device structure @@ -316,18 +342,25 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr readlen, &retlen, &buf[0]); if (ret) return ret; - } - if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { - this->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", - i >> 1, (unsigned int) from); - break; + + if (check_short_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { + this->bbt[i >> 3] |= 0x03 << (i & 0x6); + printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", + i >> 1, (unsigned int) from); + break; + } + } else { + if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { + this->bbt[i >> 3] |= 0x03 << (i & 0x6); + printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", + i >> 1, (unsigned int) from); + break; + } } } i += 2; from += (1 << this->bbt_erase_shift); } - return 0; } -- cgit v1.2.3 From d7e78d4f2173298c34e88f496c3acea247feec61 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 17 Jun 2005 16:02:09 +0100 Subject: [MTD] NAND: Change exports to _GPL Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bbe0283433d..1bd71a598c7 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.145 2005/05/31 20:32:53 gleixner Exp $ + * $Id: nand_base.c,v 1.146 2005/06/17 15:02:06 gleixner Exp $ * * 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 @@ -2686,8 +2686,8 @@ void nand_release (struct mtd_info *mtd) kfree (this->data_buf); } -EXPORT_SYMBOL (nand_scan); -EXPORT_SYMBOL (nand_release); +EXPORT_SYMBOL_GPL (nand_scan); +EXPORT_SYMBOL_GPL (nand_release); MODULE_LICENSE ("GPL"); MODULE_AUTHOR ("Steven J. Hill , Thomas Gleixner "); -- cgit v1.2.3 From a4f957f16d41b9ff944dddd84c4892496a129f68 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 20 Jun 2005 12:48:25 +0100 Subject: [MTD] NAND: s3c24xx updates Fix error in timing generation, Tacls is only in the range 0..3 Add proper support for the s3c2440 NAND controller, which has now been tested on several s3c2440 implementations. Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/Kconfig | 7 +- drivers/mtd/nand/s3c2410.c | 180 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 152 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f7801eb730c..94b1d0e3ec8 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/nand/Kconfig -# $Id: Kconfig,v 1.26 2005/01/05 12:42:24 dwmw2 Exp $ +# $Id: Kconfig,v 1.31 2005/06/20 12:03:21 bjd Exp $ menu "NAND Flash Device Drivers" depends on MTD!=n @@ -95,10 +95,11 @@ config MTD_NAND_PPCHAMELEONEVB This enables the NAND flash driver on the PPChameleon EVB Board. config MTD_NAND_S3C2410 - tristate "NAND Flash support for S3C2410 SoC" + tristate "NAND Flash support for S3C2410/S3C2440 SoC" depends on ARCH_S3C2410 && MTD_NAND help - This enables the NAND flash controller on the S3C2410. + This enables the NAND flash controller on the S3C2410 and S3C2440 + SoCs No board specfic support is done by this driver, each board must advertise a platform_device for the driver to attach. diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 64b1d95e3e3..630a9c0edf3 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -1,10 +1,10 @@ /* linux/drivers/mtd/nand/s3c2410.c * - * Copyright (c) 2004 Simtec Electronics + * Copyright (c) 2004,2005 Simtec Electronics * http://www.simtec.co.uk/products/SWLINUX/ * Ben Dooks * - * Samsung S3C2410 NAND driver + * Samsung S3C2410/S3C240 NAND driver * * Changelog: * 21-Sep-2004 BJD Initial version @@ -13,8 +13,11 @@ * 12-Oct-2004 BJD Fixed errors in use of platform data * 18-Feb-2005 BJD Fix sparse errors * 14-Mar-2005 BJD Applied tglx's code reduction patch + * 02-May-2005 BJD Fixed s3c2440 support + * 02-May-2005 BJD Reduced hwcontrol decode + * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug * - * $Id: s3c2410.c,v 1.12 2005/03/17 11:31:26 bjd Exp $ + * $Id: s3c2410.c,v 1.13 2005/06/20 11:48:21 bjd Exp $ * * 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 @@ -104,6 +107,8 @@ struct s3c2410_nand_info { struct clk *clk; void __iomem *regs; int mtd_count; + + unsigned char is_s3c2440; }; /* conversion functions */ @@ -168,12 +173,12 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, /* calculate the timing information for the controller */ if (plat != NULL) { - tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 8); + tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4); twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8); } else { /* default timings */ - tacls = 8; + tacls = 4; twrph0 = 8; twrph1 = 8; } @@ -188,10 +193,16 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, to_ns(twrph0, clkrate), to_ns(twrph1, clkrate)); - cfg = S3C2410_NFCONF_EN; - cfg |= S3C2410_NFCONF_TACLS(tacls-1); - cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1); - cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1); + if (!info->is_s3c2440) { + cfg = S3C2410_NFCONF_EN; + cfg |= S3C2410_NFCONF_TACLS(tacls-1); + cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1); + cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1); + } else { + cfg = S3C2440_NFCONF_TACLS(tacls-1); + cfg |= S3C2440_NFCONF_TWRPH0(twrph0-1); + cfg |= S3C2440_NFCONF_TWRPH1(twrph1-1); + } pr_debug(PFX "NF_CONF is 0x%lx\n", cfg); @@ -206,15 +217,20 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) struct s3c2410_nand_info *info; struct s3c2410_nand_mtd *nmtd; struct nand_chip *this = mtd->priv; + void __iomem *reg; unsigned long cur; + unsigned long bit; nmtd = this->priv; info = nmtd->info; - cur = readl(info->regs + S3C2410_NFCONF); + bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE; + reg = info->regs+((info->is_s3c2440) ? S3C2440_NFCONT:S3C2410_NFCONF); + + cur = readl(reg); if (chip == -1) { - cur |= S3C2410_NFCONF_nFCE; + cur |= bit; } else { if (chip > nmtd->set->nr_chips) { printk(KERN_ERR PFX "chip %d out of range\n", chip); @@ -226,45 +242,72 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) (info->platform->select_chip)(nmtd->set, chip); } - cur &= ~S3C2410_NFCONF_nFCE; + cur &= ~bit; } - writel(cur, info->regs + S3C2410_NFCONF); + writel(cur, reg); } -/* command and control functions */ +/* command and control functions + * + * Note, these all use tglx's method of changing the IO_ADDR_W field + * to make the code simpler, and use the nand layer's code to issue the + * command and address sequences via the proper IO ports. + * +*/ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); struct nand_chip *chip = mtd->priv; - unsigned long cur; switch (cmd) { case NAND_CTL_SETNCE: - cur = readl(info->regs + S3C2410_NFCONF); - cur &= ~S3C2410_NFCONF_nFCE; - writel(cur, info->regs + S3C2410_NFCONF); + case NAND_CTL_CLRNCE: + printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__); + break; + + case NAND_CTL_SETCLE: + chip->IO_ADDR_W = info->regs + S3C2410_NFCMD; + break; + + case NAND_CTL_SETALE: + chip->IO_ADDR_W = info->regs + S3C2410_NFADDR; + break; + + /* NAND_CTL_CLRCLE: */ + /* NAND_CTL_CLRALE: */ + default: + chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; break; + } +} + +/* command and control functions */ + +static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + struct nand_chip *chip = mtd->priv; + switch (cmd) { + case NAND_CTL_SETNCE: case NAND_CTL_CLRNCE: - cur = readl(info->regs + S3C2410_NFCONF); - cur |= S3C2410_NFCONF_nFCE; - writel(cur, info->regs + S3C2410_NFCONF); + printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__); break; case NAND_CTL_SETCLE: - chip->IO_ADDR_W = info->regs + S3C2410_NFCMD; + chip->IO_ADDR_W = info->regs + S3C2440_NFCMD; break; case NAND_CTL_SETALE: - chip->IO_ADDR_W = info->regs + S3C2410_NFADDR; + chip->IO_ADDR_W = info->regs + S3C2440_NFADDR; break; /* NAND_CTL_CLRCLE: */ /* NAND_CTL_CLRALE: */ default: - chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; + chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; break; } } @@ -278,9 +321,12 @@ static int s3c2410_nand_devready(struct mtd_info *mtd) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + if (info->is_s3c2440) + return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; } + /* ECC handling functions */ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, @@ -303,6 +349,12 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, return -1; } +/* ECC functions + * + * These allow the s3c2410 and s3c2440 to use the controller's ECC + * generator block to ECC the data as it passes through] +*/ + static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); @@ -313,6 +365,15 @@ static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) writel(ctrl, info->regs + S3C2410_NFCONF); } +static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + unsigned long ctrl; + + ctrl = readl(info->regs + S3C2440_NFCONT); + writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT); +} + static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { @@ -329,7 +390,26 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, } -/* over-ride the standard functions for a little more speed? */ +static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, + const u_char *dat, u_char *ecc_code) +{ + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + unsigned long ecc = readl(info->regs + S3C2440_NFMECC0); + + ecc_code[0] = ecc; + ecc_code[1] = ecc >> 8; + ecc_code[2] = ecc >> 16; + + pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", + ecc_code[0], ecc_code[1], ecc_code[2]); + + return 0; +} + + +/* over-ride the standard functions for a little more speed. We can + * use read/write block to move the data buffers to/from the controller +*/ static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) { @@ -444,6 +524,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, chip->options = 0; chip->controller = &info->controller; + if (info->is_s3c2440) { + chip->IO_ADDR_R = info->regs + S3C2440_NFDATA; + chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; + chip->hwcontrol = s3c2440_nand_hwcontrol; + } + nmtd->info = info; nmtd->mtd.priv = chip; nmtd->set = set; @@ -454,6 +540,11 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, chip->calculate_ecc = s3c2410_nand_calculate_ecc; chip->eccmode = NAND_ECC_HW3_512; chip->autooob = &nand_hw_eccoob; + + if (info->is_s3c2440) { + chip->enable_hwecc = s3c2440_nand_enable_hwecc; + chip->calculate_ecc = s3c2440_nand_calculate_ecc; + } } else { chip->eccmode = NAND_ECC_SOFT; } @@ -467,7 +558,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, * nand layer to look for devices */ -static int s3c2410_nand_probe(struct device *dev) +static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) { struct platform_device *pdev = to_platform_device(dev); struct s3c2410_platform_nand *plat = to_nand_plat(dev); @@ -493,6 +584,7 @@ static int s3c2410_nand_probe(struct device *dev) dev_set_drvdata(dev, info); spin_lock_init(&info->controller.lock); + init_waitqueue_head(&info->controller.wq); /* get the clock source and enable it */ @@ -508,7 +600,8 @@ static int s3c2410_nand_probe(struct device *dev) /* allocate and map the resource */ - res = pdev->resource; /* assume that the flash has one resource */ + /* currently we assume we have the one resource */ + res = pdev->resource; size = res->end - res->start + 1; info->area = request_mem_region(res->start, size, pdev->name); @@ -519,9 +612,10 @@ static int s3c2410_nand_probe(struct device *dev) goto exit_error; } - info->device = dev; - info->platform = plat; - info->regs = ioremap(res->start, size); + info->device = dev; + info->platform = plat; + info->regs = ioremap(res->start, size); + info->is_s3c2440 = is_s3c2440; if (info->regs == NULL) { printk(KERN_ERR PFX "cannot reserve register region\n"); @@ -586,6 +680,18 @@ static int s3c2410_nand_probe(struct device *dev) return err; } +/* driver device registration */ + +static int s3c2410_nand_probe(struct device *dev) +{ + return s3c24xx_nand_probe(dev, 0); +} + +static int s3c2440_nand_probe(struct device *dev) +{ + return s3c24xx_nand_probe(dev, 1); +} + static struct device_driver s3c2410_nand_driver = { .name = "s3c2410-nand", .bus = &platform_bus_type, @@ -593,14 +699,24 @@ static struct device_driver s3c2410_nand_driver = { .remove = s3c2410_nand_remove, }; +static struct device_driver s3c2440_nand_driver = { + .name = "s3c2440-nand", + .bus = &platform_bus_type, + .probe = s3c2440_nand_probe, + .remove = s3c2410_nand_remove, +}; + static int __init s3c2410_nand_init(void) { - printk("S3C2410 NAND Driver, (c) 2004 Simtec Electronics\n"); + printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n"); + + driver_register(&s3c2440_nand_driver); return driver_register(&s3c2410_nand_driver); } static void __exit s3c2410_nand_exit(void) { + driver_unregister(&s3c2440_nand_driver); driver_unregister(&s3c2410_nand_driver); } @@ -609,4 +725,4 @@ module_exit(s3c2410_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ben Dooks "); -MODULE_DESCRIPTION("S3C2410 MTD NAND driver"); +MODULE_DESCRIPTION("S3C24XX MTD NAND driver"); -- cgit v1.2.3 From af2c80e926ad5335d00a8d507928aff4e8ff1877 Mon Sep 17 00:00:00 2001 From: ? Date: Mon, 20 Jun 2005 13:22:55 +0100 Subject: [MTD] ms02-nv: Fix 64bit operation Replace KSEG1ADDR() with CKSEG1ADDR() as the former does not work for 64-bit configurations anymore. Signed-off-by: Maciej W. Rozycki Signed-off-by: Thomas Gleixner --- drivers/mtd/devices/ms02-nv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index 380ff08d29e..f5026cee087 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c @@ -6,7 +6,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * $Id: ms02-nv.c,v 1.8 2005/01/05 18:05:12 dwmw2 Exp $ + * $Id: ms02-nv.c,v 1.10 2005/06/20 12:24:41 macro Exp $ */ #include @@ -99,8 +99,8 @@ static inline uint ms02nv_probe_one(ulong addr) * The firmware writes MS02NV_ID at MS02NV_MAGIC and also * a diagnostic status at MS02NV_DIAG. */ - ms02nv_diagp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_DIAG)); - ms02nv_magicp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_MAGIC)); + ms02nv_diagp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_DIAG)); + ms02nv_magicp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_MAGIC)); err = get_dbe(ms02nv_magic, ms02nv_magicp); if (err) return 0; @@ -233,7 +233,7 @@ static int __init ms02nv_init_one(ulong addr) goto err_out_csr_res; } - printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMiB.\n", + printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %zuMiB.\n", mtd->index, ms02nv_name, addr, size >> 20); mp->next = root_ms02nv_mtd; -- cgit v1.2.3 From bd7bcf52dabba9c391142fd515221fcb87b7c712 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 23 Jun 2005 10:38:54 +0100 Subject: [MTD] NAND: Add ST chip IDs. From: Domenico DI TULLIO Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_ids.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 4b2bfae6f50..efe246961b6 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -2,8 +2,8 @@ * drivers/mtd/nandids.c * * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) - * - * $Id: nand_ids.c,v 1.12 2005/02/16 09:33:27 gleixner Exp $ + * + * $Id: nand_ids.c,v 1.14 2005/06/23 09:38:50 gleixner Exp $ * * 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 @@ -56,15 +56,24 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, + {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0}, {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16}, {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, + {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16}, {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, /* These are the new chips with large page size. The pagesize * and the erasesize is determined from the extended id bytes */ + /*512 Megabit */ + {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, + {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, + {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, + {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, + /* 1 Gigabit */ {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, -- cgit v1.2.3 From 0edb586049e57c56e625536476931117a57671e9 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 22 Jun 2005 16:59:51 +0200 Subject: [PATCH] driver core: add bus_find_device & driver_find_device functions Add bus_find_device() and driver_find_device() which allow searching for a device in the bus's resp. the driver's klist and obtain a reference on it. Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 34 ++++++++++++++++++++++++++++++++++ drivers/base/driver.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index c3fac7fd555..2c64b792d07 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -177,6 +177,39 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start, return error; } +/** + * bus_find_device - device iterator for locating a particular device. + * @bus: bus type + * @start: Device to begin with + * @data: Data to pass to match function + * @match: Callback function to check device + * + * This is similar to the bus_for_each_dev() function above, but it + * returns a reference to a device that is 'found' for later use, as + * determined by the @match callback. + * + * The callback should return 0 if the device doesn't match and non-zero + * if it does. If the callback returns non-zero, this function will + * return to the caller and not iterate over any more devices. + */ +struct device * bus_find_device(struct bus_type *bus, + struct device *start, void *data, + int (*match)(struct device *, void *)) +{ + struct klist_iter i; + struct device *dev; + + if (!bus) + return NULL; + + klist_iter_init_node(&bus->klist_devices, &i, + (start ? &start->knode_bus : NULL)); + while ((dev = next_device(&i))) + if (match(dev, data) && get_device(dev)) + break; + klist_iter_exit(&i); + return dev; +} static struct device_driver * next_driver(struct klist_iter * i) @@ -557,6 +590,7 @@ int __init buses_init(void) EXPORT_SYMBOL_GPL(bus_for_each_dev); +EXPORT_SYMBOL_GPL(bus_find_device); EXPORT_SYMBOL_GPL(bus_for_each_drv); EXPORT_SYMBOL_GPL(bus_add_device); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 1b645886e9e..291c5954a3a 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -55,6 +55,41 @@ int driver_for_each_device(struct device_driver * drv, struct device * start, EXPORT_SYMBOL_GPL(driver_for_each_device); +/** + * driver_find_device - device iterator for locating a particular device. + * @driver: The device's driver + * @start: Device to begin with + * @data: Data to pass to match function + * @match: Callback function to check device + * + * This is similar to the driver_for_each_device() function above, but + * it returns a reference to a device that is 'found' for later use, as + * determined by the @match callback. + * + * The callback should return 0 if the device doesn't match and non-zero + * if it does. If the callback returns non-zero, this function will + * return to the caller and not iterate over any more devices. + */ +struct device * driver_find_device(struct device_driver *drv, + struct device * start, void * data, + int (*match)(struct device *, void *)) +{ + struct klist_iter i; + struct device *dev; + + if (!drv) + return NULL; + + klist_iter_init_node(&drv->klist_devices, &i, + (start ? &start->knode_driver : NULL)); + while ((dev = next_device(&i))) + if (match(dev, data) && get_device(dev)) + break; + klist_iter_exit(&i); + return dev; +} +EXPORT_SYMBOL_GPL(driver_find_device); + /** * driver_create_file - create sysfs file for driver. * @drv: driver. -- cgit v1.2.3 From 151ef38f7c0ec1b0420f04438b0316e3a30bf2e4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 22 Jun 2005 16:09:05 -0700 Subject: [PATCH] driver core: Add the ability to unbind drivers to devices from userspace This adds a single file, "unbind", to the sysfs directory of every device that is currently bound to a driver. To unbind the driver from the device, write anything to this file and they will be disconnected from each other. Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 2c64b792d07..fa41ee90a53 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -133,6 +133,34 @@ static struct kobj_type ktype_bus = { decl_subsys(bus, &ktype_bus, NULL); +/* Manually detach a device from it's associated driver. */ +static int driver_helper(struct device *dev, void *data) +{ + const char *name = data; + + if (strcmp(name, dev->bus_id) == 0) + return 1; + return 0; +} + +static ssize_t driver_unbind(struct device_driver *drv, + const char *buf, size_t count) +{ + struct bus_type *bus = get_bus(drv->bus); + struct device *dev; + int err = -ENODEV; + + dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); + if ((dev) && + (dev->driver == drv)) { + device_release_driver(dev); + err = count; + } + return err; +} +static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); + + static struct device * next_device(struct klist_iter * i) { struct klist_node * n = klist_next(i); @@ -396,6 +424,7 @@ int bus_add_driver(struct device_driver * drv) module_add_driver(drv->owner, drv); driver_add_attrs(bus, drv); + driver_create_file(drv, &driver_attr_unbind); } return error; } @@ -413,6 +442,7 @@ int bus_add_driver(struct device_driver * drv) void bus_remove_driver(struct device_driver * drv) { if (drv->bus) { + driver_remove_file(drv, &driver_attr_unbind); driver_remove_attrs(drv->bus, drv); klist_remove(&drv->knode_bus); pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); -- cgit v1.2.3 From afdce75f1eaebcf358b7594ba7969aade105c3b0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 22 Jun 2005 16:09:05 -0700 Subject: [PATCH] driver core: Add the ability to bind drivers to devices from userspace This adds a single file, "bind", to the sysfs directory of every driver registered with the driver core. To bind a device to a driver, write the bus id of the device you wish to bind to that specific driver to the "bind" file (remember to not add a trailing \n). If that bus id matches a device on that bus, and it does not currently have a driver bound to it, the probe sequence will be initiated with that driver and device. Note, this requires that the driver itself be willing and able to accept that device (usually through a device id type table). This patch does not make it possible to override the driver's id table. Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 1 + drivers/base/bus.c | 26 ++++++++++++++++++++++++++ drivers/base/dd.c | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/base.h b/drivers/base/base.h index 645f6269292..783752b68a9 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -5,6 +5,7 @@ extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); extern void driver_detach(struct device_driver * drv); +extern int driver_probe_device(struct device_driver *, struct device *); static inline struct class_device *to_class_dev(struct kobject *obj) { diff --git a/drivers/base/bus.c b/drivers/base/bus.c index fa41ee90a53..7e17488271a 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -160,6 +160,30 @@ static ssize_t driver_unbind(struct device_driver *drv, } static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); +/* + * Manually attach a device to a driver. + * Note: the driver must want to bind to the device, + * it is not possible to override the driver's id table. + */ +static ssize_t driver_bind(struct device_driver *drv, + const char *buf, size_t count) +{ + struct bus_type *bus = get_bus(drv->bus); + struct device *dev; + int err = -ENODEV; + + dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); + if ((dev) && + (dev->driver == NULL)) { + down(&dev->sem); + err = driver_probe_device(drv, dev); + up(&dev->sem); + put_device(dev); + } + return err; +} +static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); + static struct device * next_device(struct klist_iter * i) { @@ -425,6 +449,7 @@ int bus_add_driver(struct device_driver * drv) driver_add_attrs(bus, drv); driver_create_file(drv, &driver_attr_unbind); + driver_create_file(drv, &driver_attr_bind); } return error; } @@ -442,6 +467,7 @@ int bus_add_driver(struct device_driver * drv) void bus_remove_driver(struct device_driver * drv) { if (drv->bus) { + driver_remove_file(drv, &driver_attr_bind); driver_remove_file(drv, &driver_attr_unbind); driver_remove_attrs(drv->bus, drv); klist_remove(&drv->knode_bus); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 6db3a789c54..16323f9cbff 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -65,7 +65,7 @@ void device_bind_driver(struct device * dev) * * This function must be called with @dev->sem held. */ -static int driver_probe_device(struct device_driver * drv, struct device * dev) +int driver_probe_device(struct device_driver * drv, struct device * dev) { int ret = 0; -- cgit v1.2.3 From 23d3d602cb96addd3c1158424fb01a49ea5e81b1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 22 Jun 2005 16:09:05 -0700 Subject: [PATCH] driver core: change bus_rescan_devices to return void No one was looking at the return value of bus_rescan_devices, and it really wasn't anything that anyone in the kernel would ever care about. So change it which enabled some counting code to be removed also. Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 7e17488271a..96fe2f95675 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -483,31 +483,22 @@ void bus_remove_driver(struct device_driver * drv) /* Helper for bus_rescan_devices's iter */ static int bus_rescan_devices_helper(struct device *dev, void *data) { - int *count = data; - - if (!dev->driver && (device_attach(dev) > 0)) - (*count)++; - + if (!dev->driver) + device_attach(dev); return 0; } - /** - * bus_rescan_devices - rescan devices on the bus for possible drivers - * @bus: the bus to scan. + * bus_rescan_devices - rescan devices on the bus for possible drivers + * @bus: the bus to scan. * - * This function will look for devices on the bus with no driver - * attached and rescan it against existing drivers to see if it - * matches any. Calls device_attach(). Returns the number of devices - * that were sucessfully bound to a driver. + * This function will look for devices on the bus with no driver + * attached and rescan it against existing drivers to see if it matches + * any by calling device_attach() for the unbound devices. */ -int bus_rescan_devices(struct bus_type * bus) +void bus_rescan_devices(struct bus_type * bus) { - int count = 0; - - bus_for_each_dev(bus, NULL, &count, bus_rescan_devices_helper); - - return count; + bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper); } -- cgit v1.2.3 From d62c0f9fd2d3943a3eca85b490d86e1605000ccb Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Fri, 24 Jun 2005 08:39:33 -0700 Subject: [PATCH] Driver core: Use klist_del() instead of klist_remove(). Use klist_del() instead of klist_remove() when unregistering devices. This will prevent a deadlock when executing a recursive unregister using device_for_each_child(). Signed-off-by Patrick Mochel Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/core.c b/drivers/base/core.c index 86d79755fbf..efe03a024a5 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -333,7 +333,7 @@ void device_del(struct device * dev) struct device * parent = dev->parent; if (parent) - klist_remove(&dev->knode_parent); + klist_del(&dev->knode_parent); /* Notify the platform of the removal, in case they * need to do anything... -- cgit v1.2.3 From 41359dca9442b0c664336e3fcf3aaf70b6507b1d Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 30 Jun 2005 16:30:07 +0100 Subject: [PATCH] ARM: Acornfb: Don't claim IRQ fbcon for cursor The generic fbcon code tries to register and use the vsync IRQ for ARM platforms with acornfb, but forgets to disable its own cursor timer. The result is a flickering flashing cursor. Remove the code from the fbcon core to register this platform private interrupt. Signed-off-by: Russell King --- drivers/video/console/fbcon.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index b209adbd508..9dd0fbccf99 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -142,7 +142,6 @@ static int fbcon_set_origin(struct vc_data *); #define CURSOR_DRAW_DELAY (1) /* # VBL ints between cursor state changes */ -#define ARM_CURSOR_BLINK_RATE (10) #define ATARI_CURSOR_BLINK_RATE (42) #define MAC_CURSOR_BLINK_RATE (32) #define DEFAULT_CURSOR_BLINK_RATE (20) @@ -288,7 +287,7 @@ static void fb_flashcursor(void *private) release_console_sem(); } -#if (defined(__arm__) && defined(IRQ_VSYNCPULSE)) || defined(CONFIG_ATARI) || defined(CONFIG_MAC) +#if defined(CONFIG_ATARI) || defined(CONFIG_MAC) static int cursor_blink_rate; static irqreturn_t fb_vbl_handler(int irq, void *dev_id, struct pt_regs *fp) { @@ -878,11 +877,6 @@ static const char *fbcon_startup(void) } #endif /* CONFIG_MAC */ -#if defined(__arm__) && defined(IRQ_VSYNCPULSE) - cursor_blink_rate = ARM_CURSOR_BLINK_RATE; - irqres = request_irq(IRQ_VSYNCPULSE, fb_vbl_handler, SA_SHIRQ, - "framebuffer vbl", info); -#endif /* Initialize the work queue. If the driver provides its * own work queue this means it will use something besides * default timer to flash the cursor. */ -- cgit v1.2.3 From 3704511b2ee8b01475ca7c171d62c682342fa38e Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 30 Jun 2005 02:58:47 -0700 Subject: [PATCH] pcmcia: fix modalias attribute in sysfs Fix up PCMCIA modalias file in sysfs Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/ds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index cabddd49f6f..d5afd557fe3 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -847,7 +847,7 @@ pcmcia_device_stringattr(prod_id2, prod_id[1]); pcmcia_device_stringattr(prod_id3, prod_id[2]); pcmcia_device_stringattr(prod_id4, prod_id[3]); -static ssize_t modalias_show(struct device *dev, char *buf) +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); int i; -- cgit v1.2.3 From 9a936eb928c1a253c2e5d66b947688bdc55094a6 Mon Sep 17 00:00:00 2001 From: Kylene Jo Hall Date: Thu, 30 Jun 2005 02:58:50 -0700 Subject: [PATCH] tpm: fix bug introduced by the /proc/misc In fixing the /proc/misc problem that was reported last week where the tpm module name was being obfuscated in /proc/misc I introduced a bug in the module unloading code. This patch fixes the problem. Signed-off-by: Kylene Hall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 854475c54f0..049d128ae7f 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -464,7 +464,7 @@ void __devexit tpm_remove(struct pci_dev *pci_dev) pci_set_drvdata(pci_dev, NULL); misc_deregister(&chip->vendor->miscdev); - kfree(&chip->vendor->miscdev.name); + kfree(chip->vendor->miscdev.name); sysfs_remove_group(&pci_dev->dev.kobj, chip->vendor->attr_group); -- cgit v1.2.3 From 306e440daf5f40b195afd83d05dee89fa63189e7 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Thu, 30 Jun 2005 02:58:55 -0700 Subject: [PATCH] x86: i8253/i8259A lock cleanup Introduce proper declarations for i8253_lock and i8259A_lock. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/legacy/hd.c | 4 +++- drivers/input/gameport/gameport.c | 3 ++- drivers/input/joystick/analog.c | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c index e884cd4b22f..242029c9c0c 100644 --- a/drivers/ide/legacy/hd.c +++ b/drivers/ide/legacy/hd.c @@ -156,11 +156,13 @@ else \ #if (HD_DELAY > 0) + +#include + unsigned long last_req; unsigned long read_timer(void) { - extern spinlock_t i8253_lock; unsigned long t, flags; int i; diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 3e72c9b1461..ab09cf4093e 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -60,12 +60,13 @@ static void gameport_disconnect_port(struct gameport *gameport); #if defined(__i386__) +#include + #define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0)) #define GET_TIME(x) do { x = get_time_pit(); } while (0) static unsigned int get_time_pit(void) { - extern spinlock_t i8253_lock; unsigned long flags; unsigned int count; diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 504b7d55056..c3a5739030c 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -140,12 +140,14 @@ struct analog_port { */ #ifdef __i386__ + +#include + #define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0) #define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0))) #define TIME_NAME (cpu_has_tsc?"TSC":"PIT") static unsigned int get_time_pit(void) { - extern spinlock_t i8253_lock; unsigned long flags; unsigned int count; -- cgit v1.2.3 From 44454bcdb90532b372c74e3546043d8a3a468939 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 30 Jun 2005 22:41:22 +0100 Subject: [PATCH] Serial: Fix small CONFIG_SERIAL_8250_NR_UARTS If CONFIG_SERIAL_8250_NR_UARTS is smaller than the array size in asm/serial.h, we trampled on memory which wasn't ours. Take our big boots away by limiting the number of ports initialised to the smaller of ...NR_UARTS and the array size. Signed-off-by: Russell King --- drivers/serial/8250.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 9224fc3184e..7e8fc7c1d4c 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2061,7 +2061,8 @@ static void __init serial8250_isa_init_ports(void) up->port.ops = &serial8250_pops; } - for (i = 0, up = serial8250_ports; i < ARRAY_SIZE(old_serial_port); + for (i = 0, up = serial8250_ports; + i < ARRAY_SIZE(old_serial_port) && i < UART_NR; i++, up++) { up->port.iobase = old_serial_port[i].port; up->port.irq = irq_canonicalize(old_serial_port[i].irq); -- cgit v1.2.3 From 747aead34de65c25765da79825ce2c08d8257b10 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 30 Jun 2005 23:01:09 +0100 Subject: [PATCH] ARM: 2780/1: AFS partition length calculation fix Patch from Catalin Marinas This patch calculates the AFS partition length by expanding the image length information to the nearest erase block boundary. This eliminates the problems with JFFS2 erasing the footer. Signed-off-by: Catalin Marinas Signed-off-by: Russell King --- drivers/mtd/afs.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 801e6c7d089..7363e101eb0 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -219,7 +219,7 @@ static int parse_afs_partitions(struct mtd_info *mtd, */ for (idx = off = 0; off < mtd->size; off += mtd->erasesize) { struct image_info_struct iis; - u_int iis_ptr, img_ptr, size; + u_int iis_ptr, img_ptr; /* Read the footer. */ ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask); @@ -236,21 +236,9 @@ static int parse_afs_partitions(struct mtd_info *mtd, continue; strcpy(str, iis.name); - size = mtd->erasesize + off - img_ptr; - - /* - * In order to support JFFS2 partitions on this layout, - * we must lie to MTD about the real size of JFFS2 - * partitions; this ensures that the AFS flash footer - * won't be erased by JFFS2. Please ensure that your - * JFFS2 partitions are given image numbers between - * 1000 and 2000 inclusive. - */ - if (iis.imageNumber >= 1000 && iis.imageNumber < 2000) - size -= mtd->erasesize; parts[idx].name = str; - parts[idx].size = size; + parts[idx].size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1); parts[idx].offset = img_ptr; parts[idx].mask_flags = 0; -- cgit v1.2.3 From 9bc7b38731dd1cc1635ab12f8de48866f603b06e Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Thu, 30 Jun 2005 01:23:27 +0100 Subject: [MTD] mtdchar.c: Replace DEVFS by udev Switch from DEVFS to udev for dynamic creation of device nodes for mtd char devices. Creates a new LDM class "mtd" with writeable and read-only devices registered for each mtdchar device. From: Paolo Galtieri Signed-off-by: Todd Poynor Signed-off-by: Thomas Gleixner --- drivers/mtd/mtdchar.c | 52 ++++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index da3f1a8f756..b606f811eeb 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1,5 +1,5 @@ /* - * $Id: mtdchar.c,v 1.70 2005/04/01 15:36:11 nico Exp $ + * $Id: mtdchar.c,v 1.72 2005/06/30 00:23:24 tpoynor Exp $ * * Character-device access to raw MTD devices. * @@ -15,27 +15,30 @@ #include #include -#ifdef CONFIG_DEVFS_FS -#include +#include + +static struct class *mtd_class; static void mtd_notify_add(struct mtd_info* mtd) { if (!mtd) return; - devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2), - S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index); - - devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), - S_IFCHR | S_IRUGO, "mtd/%dro", mtd->index); + class_device_create(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), + NULL, "mtd%d", mtd->index); + + class_device_create(mtd_class, + MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), + NULL, "mtd%dro", mtd->index); } static void mtd_notify_remove(struct mtd_info* mtd) { if (!mtd) return; - devfs_remove("mtd/%d", mtd->index); - devfs_remove("mtd/%dro", mtd->index); + + class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2)); + class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1)); } static struct mtd_notifier notifier = { @@ -43,22 +46,6 @@ static struct mtd_notifier notifier = { .remove = mtd_notify_remove, }; -static inline void mtdchar_devfs_init(void) -{ - devfs_mk_dir("mtd"); - register_mtd_user(¬ifier); -} - -static inline void mtdchar_devfs_exit(void) -{ - unregister_mtd_user(¬ifier); - devfs_remove("mtd"); -} -#else /* !DEVFS */ -#define mtdchar_devfs_init() do { } while(0) -#define mtdchar_devfs_exit() do { } while(0) -#endif - /* * We use file->private_data to store a pointer to the MTDdevice. * Since alighment is at least 32 bits, we have 2 bits free for OTP @@ -657,13 +644,22 @@ static int __init init_mtdchar(void) return -EAGAIN; } - mtdchar_devfs_init(); + mtd_class = class_create(THIS_MODULE, "mtd"); + + if (IS_ERR(mtd_class)) { + printk(KERN_ERR "Error creating mtd class.\n"); + unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); + return 1; + } + + register_mtd_user(¬ifier); return 0; } static void __exit cleanup_mtdchar(void) { - mtdchar_devfs_exit(); + unregister_mtd_user(¬ifier); + class_destroy(mtd_class); unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); } -- cgit v1.2.3 From 7b09cdac5af1e13ab4b30421ae5c4b7953c26841 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 1 Jul 2005 12:02:59 +0100 Subject: [PATCH] MMC: Fix divdi3 reference in mmci.c Use do_div() instead. Signed-off-by: Russell King --- drivers/mmc/mmci.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 3a5f6ac5b36..7a42966d755 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -70,6 +71,7 @@ static void mmci_stop_data(struct mmci_host *host) static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) { unsigned int datactrl, timeout, irqmask; + unsigned long long clks; void __iomem *base; DBG(host, "blksz %04x blks %04x flags %08x\n", @@ -81,9 +83,10 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) mmci_init_sg(host, data); - timeout = data->timeout_clks + - ((unsigned long long)data->timeout_ns * host->cclk) / - 1000000000ULL; + clks = (unsigned long long)data->timeout_ns * host->cclk; + do_div(clks, 1000000000UL); + + timeout = data->timeout_clks + (unsigned int)clks; base = host->base; writel(timeout, base + MMCIDATATIMER); -- cgit v1.2.3 From 6e6293dd3d4372c114674266158053d049366a0d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 1 Jul 2005 12:13:55 +0100 Subject: [PATCH] MMC: wbsd delayed insertion Wait 0.5 seconds before scanning for cards after an insertion interrupt. The electrical connection needs this time to stabilise for some cards. Signed-off-by: Pierre Ossman Signed-off-by: Russell King --- drivers/mmc/wbsd.c | 51 +++++++++++++++++++++++++++++++++++++++++---------- drivers/mmc/wbsd.h | 2 ++ 2 files changed, 43 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index b7fbd30b49a..0bd9b53fa89 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1050,6 +1050,20 @@ static struct mmc_host_ops wbsd_ops = { * * \*****************************************************************************/ +/* + * Helper function for card detection + */ +static void wbsd_detect_card(unsigned long data) +{ + struct wbsd_host *host = (struct wbsd_host*)data; + + BUG_ON(host == NULL); + + DBG("Executing card detection\n"); + + mmc_detect_change(host->mmc); +} + /* * Tasklets */ @@ -1075,7 +1089,6 @@ static void wbsd_tasklet_card(unsigned long param) { struct wbsd_host* host = (struct wbsd_host*)param; u8 csr; - int change = 0; spin_lock(&host->lock); @@ -1094,14 +1107,20 @@ static void wbsd_tasklet_card(unsigned long param) { DBG("Card inserted\n"); host->flags |= WBSD_FCARD_PRESENT; - change = 1; + + /* + * Delay card detection to allow electrical connections + * to stabilise. + */ + mod_timer(&host->timer, jiffies + HZ/2); } + + spin_unlock(&host->lock); } else if (host->flags & WBSD_FCARD_PRESENT) { DBG("Card removed\n"); host->flags &= ~WBSD_FCARD_PRESENT; - change = 1; if (host->mrq) { @@ -1112,15 +1131,14 @@ static void wbsd_tasklet_card(unsigned long param) host->mrq->cmd->error = MMC_ERR_FAILED; tasklet_schedule(&host->finish_tasklet); } - } - - /* - * Unlock first since we might get a call back. - */ - spin_unlock(&host->lock); + + /* + * Unlock first since we might get a call back. + */ + spin_unlock(&host->lock); - if (change) mmc_detect_change(host->mmc); + } } static void wbsd_tasklet_fifo(unsigned long param) @@ -1324,6 +1342,13 @@ static int __devinit wbsd_alloc_mmc(struct device* dev) spin_lock_init(&host->lock); + /* + * Set up detection timer + */ + init_timer(&host->timer); + host->timer.data = (unsigned long)host; + host->timer.function = wbsd_detect_card; + /* * Maximum number of segments. Worst case is one sector per segment * so this will be 64kB/512. @@ -1351,11 +1376,17 @@ static int __devinit wbsd_alloc_mmc(struct device* dev) static void __devexit wbsd_free_mmc(struct device* dev) { struct mmc_host* mmc; + struct wbsd_host* host; mmc = dev_get_drvdata(dev); if (!mmc) return; + host = mmc_priv(mmc); + BUG_ON(host == NULL); + + del_timer_sync(&host->timer); + mmc_free_host(mmc); dev_set_drvdata(dev, NULL); diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h index 864f30828d0..9f5383e6e59 100644 --- a/drivers/mmc/wbsd.h +++ b/drivers/mmc/wbsd.h @@ -187,4 +187,6 @@ struct wbsd_host struct tasklet_struct timeout_tasklet; struct tasklet_struct finish_tasklet; struct tasklet_struct block_tasklet; + + struct timer_list timer; /* Card detection timer */ }; -- cgit v1.2.3 From 3eee0d03e33b0294eb3165c96f213a8c8ee461a8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 1 Jul 2005 13:07:37 +0100 Subject: [PATCH] MMC: wbsd cleanups This patch contains the following possible cleanups: - make some needlessly global code static - remove the unneeded global function DBG_REG Signed-off-by: Adrian Bunk Signed-off-by: Russell King --- drivers/mmc/wbsd.c | 29 +++++++---------------------- drivers/mmc/wbsd.h | 7 ------- 2 files changed, 7 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 0bd9b53fa89..0c41d4b41a6 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -54,28 +54,6 @@ #define DBGF(x...) do { } while (0) #endif -#ifdef CONFIG_MMC_DEBUG -void DBG_REG(int reg, u8 value) -{ - int i; - - printk(KERN_DEBUG "wbsd: Register %d: 0x%02X %3d '%c' ", - reg, (int)value, (int)value, (value < 0x20)?'.':value); - - for (i = 7;i >= 0;i--) - { - if (value & (1 << i)) - printk("x"); - else - printk("."); - } - - printk("\n"); -} -#else -#define DBG_REG(r, v) do {} while (0) -#endif - /* * Device resources */ @@ -92,6 +70,13 @@ MODULE_DEVICE_TABLE(pnp, pnp_dev_table); #endif /* CONFIG_PNP */ +static const int config_ports[] = { 0x2E, 0x4E }; +static const int unlock_codes[] = { 0x83, 0x87 }; + +static const int valid_ids[] = { + 0x7112, + }; + #ifdef CONFIG_PNP static unsigned int nopnp = 0; #else diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h index 9f5383e6e59..661a9f6a6e6 100644 --- a/drivers/mmc/wbsd.h +++ b/drivers/mmc/wbsd.h @@ -8,13 +8,6 @@ * published by the Free Software Foundation. */ -const int config_ports[] = { 0x2E, 0x4E }; -const int unlock_codes[] = { 0x83, 0x87 }; - -const int valid_ids[] = { - 0x7112, - }; - #define LOCK_CODE 0xAA #define WBSD_CONF_SWRST 0x02 -- cgit v1.2.3 From 26f674ae0e37190bf61c988e52911e4372fdb5f5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Jun 2005 15:41:48 -0700 Subject: [PATCH] PCI: Fix up PCI routing in parent bridge When the cardbus bridge is behind another bridge change the routing in the parent bridge for new cards. This fixes Cardbus on various AMD64 laptops. Signed-off-by: Andi Kleen Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6a0a82f0508..9392ff3fb80 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -398,6 +398,16 @@ static void pci_enable_crs(struct pci_dev *dev) pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl); } +static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) +{ + struct pci_bus *parent = child->parent; + while (parent->parent && parent->subordinate < max) { + parent->subordinate = max; + pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max); + parent = parent->parent; + } +} + unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus); /* @@ -499,7 +509,13 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max if (!is_cardbus) { child->bridge_ctl = PCI_BRIDGE_CTL_NO_ISA; - + /* + * Adjust subordinate busnr in parent buses. + * We do this before scanning for children because + * some devices may not be detected if the bios + * was lazy. + */ + pci_fixup_parent_subordinate_busnr(child, max); /* Now we can scan all subordinate buses... */ max = pci_scan_child_bus(child); } else { @@ -513,6 +529,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max max+i+1)) break; max += i; + pci_fixup_parent_subordinate_busnr(child, max); } /* * Set the subordinate bus number to its real value. -- cgit v1.2.3 From 90b54929b626c80056262d9d99b3f48522e404d0 Mon Sep 17 00:00:00 2001 From: Ivan Kokshaysky Date: Tue, 7 Jun 2005 04:07:02 +0400 Subject: [PATCH] PCI: handle subtractive decode pci-pci bridge better With the number of PCI bus resources increased to 8, we can handle the subtractive decode PCI-PCI bridge like a normal bridge, taking into account standard PCI-PCI bridge windows (resources 0-2). This helps to avoid problems with peer-to-peer DMA behind such bridges, poor performance for MMIO ranges outside bridge windows and prefetchable vs. non-prefetchable memory issues. To reflect the fact that such bridges do forward all addresses to the secondary bus (transparency), remaining bus resources 3-7 are linked to resources 0-4 of the primary bus. These resources will be used as fallback by resource management code if allocation from standard bridge windows fails for some reason. Signed-off-by: Ivan Kokshaysky Acked-by: Dominik Brodowski Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 9392ff3fb80..df3bdae2040 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -239,9 +239,8 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) if (dev->transparent) { printk(KERN_INFO "PCI: Transparent bridge - %s\n", pci_name(dev)); - for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++) - child->resource[i] = child->parent->resource[i]; - return; + for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++) + child->resource[i] = child->parent->resource[i - 3]; } for(i=0; i<3; i++) -- cgit v1.2.3 From 299de0343c7d18448a69c635378342e9214b14af Mon Sep 17 00:00:00 2001 From: Ivan Kokshaysky Date: Wed, 15 Jun 2005 18:59:27 +0400 Subject: [PATCH] PCI: pci_assign_unassigned_resources() on x86 - Add sanity check for io[port,mem]_resource in setup-bus.c. These resources look like "free" as they have no parents, but obviously we must not touch them. - In i386.c:pci_allocate_bus_resources(), if a bridge resource cannot be allocated for some reason, then clear its flags. This prevents any child allocations in this range, so the setup-bus code will work with a clean resource sub-tree. - i386.c:pcibios_enable_resources() doesn't enable bridges, as it checks only resources 0-5, which looks like a clear bug to me. I suspect it might break hotplug as well in some cases. From: Ivan Kokshaysky Signed-off-by: Greg Kroah-Hartman --- drivers/pci/setup-bus.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 6b628de948a..c1bdfb42465 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -273,6 +273,8 @@ find_free_bus_resource(struct pci_bus *bus, unsigned long type) for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { r = bus->resource[i]; + if (r == &ioport_resource || r == &iomem_resource) + continue; if (r && (r->flags & type_mask) == type && !r->parent) return r; } -- cgit v1.2.3 From 75865858971add95809c5c9cd35dc4cfba08e33b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 30 Jun 2005 02:18:12 -0700 Subject: [PATCH] PCI: clean up dynamic pci id logic The dynamic pci id logic has been bothering me for a while, and now that I started to look into how to move some of this to the driver core, I thought it was time to clean it all up. It ends up making the code smaller, and easier to follow, and fixes a few bugs at the same time (dynamic ids were not being matched everywhere, and so could be missed on some call paths for new devices, semaphore not needed to be grabbed when adding a new id and calling the driver core, etc.) I also renamed the function pci_match_device() to pci_match_id() as that's what it really does. Signed-off-by: Greg Kroah-Hartman --- drivers/char/hw_random.c | 2 +- drivers/char/watchdog/i8xx_tco.c | 2 +- drivers/ide/setup-pci.c | 2 +- drivers/parport/parport_pc.c | 2 +- drivers/pci/pci-driver.c | 196 ++++++++++++++------------------------- 5 files changed, 75 insertions(+), 129 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c index 7e6ac14c245..3480535a09c 100644 --- a/drivers/char/hw_random.c +++ b/drivers/char/hw_random.c @@ -579,7 +579,7 @@ static int __init rng_init (void) /* Probe for Intel, AMD RNGs */ for_each_pci_dev(pdev) { - ent = pci_match_device (rng_pci_tbl, pdev); + ent = pci_match_id(rng_pci_tbl, pdev); if (ent) { rng_ops = &rng_vendor_ops[ent->driver_data]; goto match; diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c index b14d642439e..5d07ee59679 100644 --- a/drivers/char/watchdog/i8xx_tco.c +++ b/drivers/char/watchdog/i8xx_tco.c @@ -401,7 +401,7 @@ static unsigned char __init i8xx_tco_getdevice (void) */ while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (pci_match_device(i8xx_tco_pci_tbl, dev)) { + if (pci_match_id(i8xx_tco_pci_tbl, dev)) { i8xx_tco_pci = dev; break; } diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index e501675ad72..77da827b289 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -847,7 +847,7 @@ static int __init ide_scan_pcidev(struct pci_dev *dev) d = list_entry(l, struct pci_driver, node); if(d->id_table) { - const struct pci_device_id *id = pci_match_device(d->id_table, dev); + const struct pci_device_id *id = pci_match_id(d->id_table, dev); if(id != NULL) { if(d->probe(dev, id) >= 0) diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 80edfa3abd2..4598c6a9212 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -3008,7 +3008,7 @@ static int __init parport_pc_init_superio (int autoirq, int autodma) int ret = 0; while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - id = pci_match_device (parport_pc_pci_tbl, pdev); + id = pci_match_id(parport_pc_pci_tbl, pdev); if (id == NULL || id->driver_data >= last_sio) continue; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index e65bf2b395a..aac6de9568e 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -7,7 +7,6 @@ #include #include #include -#include #include "pci.h" /* @@ -19,35 +18,11 @@ */ #ifdef CONFIG_HOTPLUG -/** - * pci_device_probe_dynamic() - * - * Walk the dynamic ID list looking for a match. - * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error. - */ -static int -pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev) -{ - int error = -ENODEV; - struct list_head *pos; - struct dynid *dynid; - spin_lock(&drv->dynids.lock); - list_for_each(pos, &drv->dynids.list) { - dynid = list_entry(pos, struct dynid, node); - if (pci_match_one_device(&dynid->id, pci_dev)) { - spin_unlock(&drv->dynids.lock); - error = drv->probe(pci_dev, &dynid->id); - if (error >= 0) { - pci_dev->driver = drv; - return 0; - } - return error; - } - } - spin_unlock(&drv->dynids.lock); - return error; -} +struct pci_dynid { + struct list_head node; + struct pci_device_id id; +}; /** * store_new_id @@ -58,8 +33,7 @@ pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev) static inline ssize_t store_new_id(struct device_driver *driver, const char *buf, size_t count) { - struct dynid *dynid; - struct bus_type * bus; + struct pci_dynid *dynid; struct pci_driver *pdrv = to_pci_driver(driver); __u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID, subdevice=PCI_ANY_ID, class=0, class_mask=0; @@ -91,37 +65,22 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) list_add_tail(&pdrv->dynids.list, &dynid->node); spin_unlock(&pdrv->dynids.lock); - bus = get_bus(pdrv->driver.bus); - if (bus) { - if (get_driver(&pdrv->driver)) { - down_write(&bus->subsys.rwsem); - driver_attach(&pdrv->driver); - up_write(&bus->subsys.rwsem); - put_driver(&pdrv->driver); - } - put_bus(bus); + if (get_driver(&pdrv->driver)) { + driver_attach(&pdrv->driver); + put_driver(&pdrv->driver); } return count; } - static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); -static inline void -pci_init_dynids(struct pci_dynids *dynids) -{ - spin_lock_init(&dynids->lock); - INIT_LIST_HEAD(&dynids->list); -} static void pci_free_dynids(struct pci_driver *drv) { - struct list_head *pos, *n; - struct dynid *dynid; + struct pci_dynid *dynid, *n; spin_lock(&drv->dynids.lock); - list_for_each_safe(pos, n, &drv->dynids.list) { - dynid = list_entry(pos, struct dynid, node); + list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { list_del(&dynid->node); kfree(dynid); } @@ -138,83 +97,70 @@ pci_create_newid_file(struct pci_driver *drv) return error; } -static int -pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv) -{ - struct list_head *pos; - struct dynid *dynid; - - spin_lock(&pci_drv->dynids.lock); - list_for_each(pos, &pci_drv->dynids.list) { - dynid = list_entry(pos, struct dynid, node); - if (pci_match_one_device(&dynid->id, pci_dev)) { - spin_unlock(&pci_drv->dynids.lock); - return 1; - } - } - spin_unlock(&pci_drv->dynids.lock); - return 0; -} - #else /* !CONFIG_HOTPLUG */ -static inline int pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev) -{ - return -ENODEV; -} -static inline void pci_init_dynids(struct pci_dynids *dynids) {} static inline void pci_free_dynids(struct pci_driver *drv) {} static inline int pci_create_newid_file(struct pci_driver *drv) { return 0; } -static inline int pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv) -{ - return 0; -} #endif /** - * pci_match_device - Tell if a PCI device structure has a matching - * PCI device id structure + * pci_match_id - See if a pci device matches a given pci_id table * @ids: array of PCI device id structures to search in - * @dev: the PCI device structure to match against - * + * @dev: the PCI device structure to match against. + * * Used by a driver to check whether a PCI device present in the - * system is in its list of supported devices.Returns the matching + * system is in its list of supported devices. Returns the matching * pci_device_id structure or %NULL if there is no match. + * + * Depreciated, don't use this as it will not catch any dynamic ids + * that a driver might want to check for. */ -const struct pci_device_id * -pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) +const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, + struct pci_dev *dev) { - while (ids->vendor || ids->subvendor || ids->class_mask) { - if (pci_match_one_device(ids, dev)) - return ids; - ids++; + if (ids) { + while (ids->vendor || ids->subvendor || ids->class_mask) { + if (pci_match_one_device(ids, dev)) + return ids; + ids++; + } } return NULL; } /** - * pci_device_probe_static() - * - * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error. + * pci_match_device - Tell if a PCI device structure has a matching + * PCI device id structure + * @ids: array of PCI device id structures to search in + * @dev: the PCI device structure to match against + * @drv: the PCI driver to match against + * + * Used by a driver to check whether a PCI device present in the + * system is in its list of supported devices. Returns the matching + * pci_device_id structure or %NULL if there is no match. */ -static int -pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev) -{ - int error = -ENODEV; +const struct pci_device_id *pci_match_device(struct pci_driver *drv, + struct pci_dev *dev) +{ const struct pci_device_id *id; + struct pci_dynid *dynid; - if (!drv->id_table) - return error; - id = pci_match_device(drv->id_table, pci_dev); + id = pci_match_id(drv->id_table, dev); if (id) - error = drv->probe(pci_dev, id); - if (error >= 0) { - pci_dev->driver = drv; - error = 0; + return id; + + /* static ids didn't match, lets look at the dynamic ones */ + spin_lock(&drv->dynids.lock); + list_for_each_entry(dynid, &drv->dynids.list, node) { + if (pci_match_one_device(&dynid->id, dev)) { + spin_unlock(&drv->dynids.lock); + return &dynid->id; + } } - return error; + spin_unlock(&drv->dynids.lock); + return NULL; } /** @@ -225,13 +171,20 @@ pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev) */ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) -{ +{ + const struct pci_device_id *id; int error = 0; if (!pci_dev->driver && drv->probe) { - error = pci_device_probe_static(drv, pci_dev); - if (error == -ENODEV) - error = pci_device_probe_dynamic(drv, pci_dev); + error = -ENODEV; + + id = pci_match_device(drv, pci_dev); + if (id) + error = drv->probe(pci_dev, id); + if (error >= 0) { + pci_dev->driver = drv; + error = 0; + } } return error; } @@ -371,12 +324,6 @@ static struct kobj_type pci_driver_kobj_type = { .sysfs_ops = &pci_driver_sysfs_ops, }; -static int -pci_populate_driver_dir(struct pci_driver *drv) -{ - return pci_create_newid_file(drv); -} - /** * pci_register_driver - register a new pci driver * @drv: the driver structure to register @@ -401,13 +348,15 @@ int pci_register_driver(struct pci_driver *drv) drv->driver.shutdown = pci_device_shutdown; drv->driver.owner = drv->owner; drv->driver.kobj.ktype = &pci_driver_kobj_type; - pci_init_dynids(&drv->dynids); + + spin_lock_init(&drv->dynids.lock); + INIT_LIST_HEAD(&drv->dynids.list); /* register with core */ error = driver_register(&drv->driver); if (!error) - pci_populate_driver_dir(drv); + error = pci_create_newid_file(drv); return error; } @@ -463,21 +412,17 @@ pci_dev_driver(const struct pci_dev *dev) * system is in its list of supported devices.Returns the matching * pci_device_id structure or %NULL if there is no match. */ -static int pci_bus_match(struct device * dev, struct device_driver * drv) +static int pci_bus_match(struct device *dev, struct device_driver *drv) { - const struct pci_dev * pci_dev = to_pci_dev(dev); - struct pci_driver * pci_drv = to_pci_driver(drv); - const struct pci_device_id * ids = pci_drv->id_table; + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *pci_drv = to_pci_driver(drv); const struct pci_device_id *found_id; - if (!ids) - return 0; - - found_id = pci_match_device(ids, pci_dev); + found_id = pci_match_device(pci_drv, pci_dev); if (found_id) return 1; - return pci_bus_match_dynids(pci_dev, pci_drv); + return 0; } /** @@ -536,6 +481,7 @@ static int __init pci_driver_init(void) postcore_initcall(pci_driver_init); +EXPORT_SYMBOL(pci_match_id); EXPORT_SYMBOL(pci_match_device); EXPORT_SYMBOL(pci_register_driver); EXPORT_SYMBOL(pci_unregister_driver); -- cgit v1.2.3 From a00db371624e2e3718e5ab7d73bf364681098106 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 29 Jun 2005 17:04:06 +0200 Subject: [PATCH] PCI: Add PCI quirk for SMBus on the Asus P4B-LX One more Asus motherboard requiring the SMBus quirk (P4B-LX). Original patch from Salah Coronya. Signed-off-by: Salah Coronya Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 968033fd29f..1521fd5d95c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -767,6 +767,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) { if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB) switch(dev->subsystem_device) { + case 0x8025: /* P4B-LX */ case 0x8070: /* P4B */ case 0x8088: /* P4B533 */ case 0x1626: /* L3C notebook */ -- cgit v1.2.3 From 5823d100ae260d022b4dd5ec9cc0b85f0bf0d646 Mon Sep 17 00:00:00 2001 From: long Date: Wed, 22 Jun 2005 09:09:54 -0700 Subject: [PATCH] PCI: acpi tg3 ethernet not coming back properly after S3 suspendon DellM70 This patch, is based on kernel 2.6.12, provides a fix for PCIe port bus driver suspend/resume. Signed-off-by: T. Long Nguyen Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pcie/portdrv.h | 5 +++ drivers/pci/pcie/portdrv_core.c | 8 +++++ drivers/pci/pcie/portdrv_pci.c | 79 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 91 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 537b372dc34..a63bd8f7260 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -27,6 +27,11 @@ #define get_descriptor_id(type, service) (((type - 4) << 4) | service) +struct pcie_port_device_ext { + int interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */ + unsigned int saved_msi_config_space[5]; +}; + extern struct bus_type pcie_port_bus_type; extern int pcie_port_device_probe(struct pci_dev *dev); extern int pcie_port_device_register(struct pci_dev *dev); diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index f5c5f10a3d2..4db69982876 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -275,10 +275,17 @@ int pcie_port_device_probe(struct pci_dev *dev) int pcie_port_device_register(struct pci_dev *dev) { + struct pcie_port_device_ext *p_ext; int status, type, capabilities, irq_mode, i; int vectors[PCIE_PORT_DEVICE_MAXSERVICES]; u16 reg16; + /* Allocate port device extension */ + if (!(p_ext = kmalloc(sizeof(struct pcie_port_device_ext), GFP_KERNEL))) + return -ENOMEM; + + pci_set_drvdata(dev, p_ext); + /* Get port type */ pci_read_config_word(dev, pci_find_capability(dev, PCI_CAP_ID_EXP) + @@ -288,6 +295,7 @@ int pcie_port_device_register(struct pci_dev *dev) /* Now get port services */ capabilities = get_port_device_capability(dev); irq_mode = assign_interrupt_mode(dev, vectors, capabilities); + p_ext->interrupt_mode = irq_mode; /* Allocate child services if any */ for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index e9095ee508e..30bac7ed7c1 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -29,6 +29,78 @@ MODULE_LICENSE("GPL"); /* global data */ static const char device_name[] = "pcieport-driver"; +static void pci_save_msi_state(struct pci_dev *dev) +{ + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); + int i = 0, pos; + u16 control; + + if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) + return; + + pci_read_config_dword(dev, pos, &p_ext->saved_msi_config_space[i++]); + control = p_ext->saved_msi_config_space[0] >> 16; + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, + &p_ext->saved_msi_config_space[i++]); + if (control & PCI_MSI_FLAGS_64BIT) { + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, + &p_ext->saved_msi_config_space[i++]); + pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, + &p_ext->saved_msi_config_space[i++]); + } else + pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, + &p_ext->saved_msi_config_space[i++]); + if (control & PCI_MSI_FLAGS_MASKBIT) + pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, + &p_ext->saved_msi_config_space[i++]); +} + +static void pci_restore_msi_state(struct pci_dev *dev) +{ + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); + int i = 0, pos; + u16 control; + + if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0) + return; + + control = p_ext->saved_msi_config_space[i++] >> 16; + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, + p_ext->saved_msi_config_space[i++]); + if (control & PCI_MSI_FLAGS_64BIT) { + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, + p_ext->saved_msi_config_space[i++]); + pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, + p_ext->saved_msi_config_space[i++]); + } else + pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, + p_ext->saved_msi_config_space[i++]); + if (control & PCI_MSI_FLAGS_MASKBIT) + pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, + p_ext->saved_msi_config_space[i++]); +} + +static void pcie_portdrv_save_config(struct pci_dev *dev) +{ + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); + + pci_save_state(dev); + if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) + pci_save_msi_state(dev); +} + +static void pcie_portdrv_restore_config(struct pci_dev *dev) +{ + struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev); + + pci_restore_state(dev); + if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE) + pci_restore_msi_state(dev); + pci_enable_device(dev); + pci_set_master(dev); +} + /* * pcie_portdrv_probe - Probe PCI-Express port devices * @dev: PCI-Express port device being probed @@ -64,16 +136,21 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev, static void pcie_portdrv_remove (struct pci_dev *dev) { pcie_port_device_remove(dev); + kfree(pci_get_drvdata(dev)); } #ifdef CONFIG_PM static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state) { - return pcie_port_device_suspend(dev, state); + int ret = pcie_port_device_suspend(dev, state); + + pcie_portdrv_save_config(dev); + return ret; } static int pcie_portdrv_resume (struct pci_dev *dev) { + pcie_portdrv_restore_config(dev); return pcie_port_device_resume(dev); } #endif -- cgit v1.2.3 From c6e21e1683c2508a2b23588e1fc2e7bf6fc2549e Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 28 Jun 2005 14:57:10 +0200 Subject: [PATCH] PCI: Remove newline from pci MODALIAS variable the pci core sends out a hotplug event variable MODALIAS with a trailing newline. This is inconsistent with all other event variables and breaks some hotplug tools. This patch removes the said newline. Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 3903f8c559b..b844bc97232 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -54,7 +54,7 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp, envp[i++] = scratch; length += scnprintf (scratch, buffer_size - length, - "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n", + "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device, (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), -- cgit v1.2.3 From 5848f23d811acc1cb6c19a12e1341e0640a85d0e Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 1 Jul 2005 14:07:28 -0400 Subject: [PATCH] pci: cleanup argument comments for pci_{save,restore}_state The buffer arguments have been removed from pci_{save,restore}_state. The comment blocks for those functions should reflect that. Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f04b9ffe415..d382bdb7b56 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -334,10 +334,6 @@ EXPORT_SYMBOL(pci_choose_state); /** * pci_save_state - save the PCI configuration space of a device before suspending * @dev: - PCI device that we're dealing with - * @buffer: - buffer to hold config space context - * - * @buffer must be large enough to hold the entire PCI 2.2 config space - * (>= 64 bytes). */ int pci_save_state(struct pci_dev *dev) @@ -352,8 +348,6 @@ pci_save_state(struct pci_dev *dev) /** * pci_restore_state - Restore the saved state of a PCI device * @dev: - PCI device that we're dealing with - * @buffer: - saved PCI config space - * */ int pci_restore_state(struct pci_dev *dev) -- cgit v1.2.3 From 43a6b76050aa137c51d00eec91d67ac43ac3846e Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Mon, 20 Jun 2005 14:29:25 -0700 Subject: [PATCH] gregkh-pci-pci-assign-unassigned-resources fix It seems that X86 architectures in general need the setup-bus.o not just those with HOTPLUG. This avoids the following error on X86_NUMAQ and x86_64: arch/i386/pci/built-in.o(.init.text+0x15a6): In function `pcibios_init': : undefined reference to `pci_assign_unassigned_resources' Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/pci/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 7dea494c0d7..3657f6199c4 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ # # Some architectures use the generic PCI setup functions # +obj-$(CONFIG_X86) += setup-bus.o obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o obj-$(CONFIG_PARISC) += setup-bus.o -- cgit v1.2.3 From 44f8e1a20cf3afe10a3744bd9317808a39a242bb Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 2 Jul 2005 10:35:33 -0700 Subject: If ACPI doesn't find an irq listed, don't accept 0 as a valid PCI irq. That zero just means that nothing else found any irq information either. --- drivers/acpi/pci_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 8dbf802ee7f..d1f42b97282 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -433,7 +433,7 @@ acpi_pci_irq_enable ( printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI", pci_name(dev), ('A' + pin)); /* Interrupt Line values above 0xF are forbidden */ - if (dev->irq >= 0 && (dev->irq <= 0xF)) { + if (dev->irq > 0 && (dev->irq <= 0xF)) { printk(" - using IRQ %d\n", dev->irq); acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); return_VALUE(0); -- cgit v1.2.3 From c2f12589bfc4119f2c331ecea8cca4945ed48497 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:06:13 +0200 Subject: [PATCH] ide: hotplug mark __devinit alim15x3.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. see the thread about the pci hotplug crash on a stratus box. http://marc.theaimsgroup.com/?l=linux-kernel&m=111930108613386&w=2 Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/alim15x3.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 67efb38a9f6..6cf49394a80 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -583,7 +583,7 @@ static int ali15x3_dma_setup(ide_drive_t *drive) * appropriate also sets up the 1533 southbridge. */ -static unsigned int __init init_chipset_ali15x3 (struct pci_dev *dev, const char *name) +static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const char *name) { unsigned long flags; u8 tmpbyte; @@ -677,7 +677,7 @@ static unsigned int __init init_chipset_ali15x3 (struct pci_dev *dev, const char * FIXME: frobs bits that are not defined on newer ALi devicea */ -static unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif) +static unsigned int __devinit ata66_ali15x3 (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; unsigned int ata66 = 0; @@ -748,7 +748,7 @@ static unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif) * Initialize the IDE structure side of the ALi 15x3 driver. */ -static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif) +static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif) { hwif->autodma = 0; hwif->tuneproc = &ali15x3_tune_drive; @@ -794,7 +794,7 @@ static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif) * Sparc systems */ -static void __init init_hwif_ali15x3 (ide_hwif_t *hwif) +static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif) { u8 ideic, inmir; s8 irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, @@ -847,7 +847,7 @@ static void __init init_hwif_ali15x3 (ide_hwif_t *hwif) * the actual work. */ -static void __init init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) +static void __devinit init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) { if (m5229_revision < 0x20) return; -- cgit v1.2.3 From e895f926cd8b6d50a42cc985d470bdc9a70caeed Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:15:41 +0200 Subject: [PATCH] ide: hotplug mark __devinit amd74xx.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/amd74xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 4e0f13d1d06..65eab9b63a7 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -309,7 +309,7 @@ static int amd74xx_ide_dma_check(ide_drive_t *drive) * and initialize its drive independent registers. */ -static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char *name) +static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const char *name) { unsigned char t; unsigned int u; @@ -413,7 +413,7 @@ static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char return dev->irq; } -static void __init init_hwif_amd74xx(ide_hwif_t *hwif) +static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) { int i; -- cgit v1.2.3 From 88de8e996f16b958721368ed9b4fd4e29cdb923e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:23:08 +0200 Subject: [PATCH] ide: hotplug mark __devinit cs5530.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/cs5530.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index 0381961db26..09269e574b3 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -217,7 +217,7 @@ static int cs5530_config_dma (ide_drive_t *drive) * Initialize the cs5530 bridge for reliable IDE DMA operation. */ -static unsigned int __init init_chipset_cs5530 (struct pci_dev *dev, const char *name) +static unsigned int __devinit init_chipset_cs5530 (struct pci_dev *dev, const char *name) { struct pci_dev *master_0 = NULL, *cs5530_0 = NULL; unsigned long flags; @@ -308,7 +308,7 @@ static unsigned int __init init_chipset_cs5530 (struct pci_dev *dev, const char * performs channel-specific pre-initialization before drive probing. */ -static void __init init_hwif_cs5530 (ide_hwif_t *hwif) +static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif) { unsigned long basereg; u32 d0_timings; -- cgit v1.2.3 From ddbc9fb47252f9b6966bfe9b0aa27bfeaa585cca Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:25:46 +0200 Subject: [PATCH] ide: hotplug mark __devinit cy82c693.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/cy82c693.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c index 80d67e99ccb..5a33513f3dd 100644 --- a/drivers/ide/pci/cy82c693.c +++ b/drivers/ide/pci/cy82c693.c @@ -391,7 +391,7 @@ static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio) /* * this function is called during init and is used to setup the cy82c693 chip */ -static unsigned int __init init_chipset_cy82c693(struct pci_dev *dev, const char *name) +static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const char *name) { if (PCI_FUNC(dev->devfn) != 1) return 0; @@ -443,7 +443,7 @@ static unsigned int __init init_chipset_cy82c693(struct pci_dev *dev, const char /* * the init function - called for each ide channel once */ -static void __init init_hwif_cy82c693(ide_hwif_t *hwif) +static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif) { hwif->autodma = 0; @@ -467,9 +467,9 @@ static void __init init_hwif_cy82c693(ide_hwif_t *hwif) hwif->drives[1].autodma = hwif->autodma; } -static __initdata ide_hwif_t *primary; +static __devinitdata ide_hwif_t *primary; -void __init init_iops_cy82c693(ide_hwif_t *hwif) +void __devinit init_iops_cy82c693(ide_hwif_t *hwif) { if (PCI_FUNC(hwif->pci_dev->devfn) == 1) primary = hwif; -- cgit v1.2.3 From a380a8849f90ba81a5ff0c325fd5d8125c70b3bb Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:28:44 +0200 Subject: [PATCH] ide: hotplug mark __devinit it8172.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/it8172.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c index 631927cf17d..93462926b9d 100644 --- a/drivers/ide/pci/it8172.c +++ b/drivers/ide/pci/it8172.c @@ -216,7 +216,7 @@ fast_ata_pio: return 0; } -static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char *name) +static unsigned int __devinit init_chipset_it8172 (struct pci_dev *dev, const char *name) { unsigned char progif; @@ -230,7 +230,7 @@ static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char } -static void __init init_hwif_it8172 (ide_hwif_t *hwif) +static void __devinit init_hwif_it8172 (ide_hwif_t *hwif) { struct pci_dev* dev = hwif->pci_dev; unsigned long cmdBase, ctrlBase; -- cgit v1.2.3 From c20530ed26e5b9e3b188b4088d0a5ab1d773a529 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:31:04 +0200 Subject: [PATCH] ide: hotplug mark __devinit ns87415.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/ns87415.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c index 205a32fbc2f..fcd5142f5cf 100644 --- a/drivers/ide/pci/ns87415.c +++ b/drivers/ide/pci/ns87415.c @@ -195,7 +195,7 @@ static int ns87415_ide_dma_check (ide_drive_t *drive) return __ide_dma_check(drive); } -static void __init init_hwif_ns87415 (ide_hwif_t *hwif) +static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; unsigned int ctrl, using_inta; -- cgit v1.2.3 From 9307145700e869dd410d565477f98377e93e9160 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:33:16 +0200 Subject: [PATCH] ide: hotplug mark __devinit opti621.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/opti621.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index cf4fd91d396..7a7c2ef78ac 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -326,7 +326,7 @@ static void opti621_tune_drive (ide_drive_t *drive, u8 pio) /* * init_hwif_opti621() is called once for each hwif found at boot. */ -static void __init init_hwif_opti621 (ide_hwif_t *hwif) +static void __devinit init_hwif_opti621 (ide_hwif_t *hwif) { hwif->autodma = 0; hwif->drives[0].drive_data = PIO_DONT_KNOW; -- cgit v1.2.3 From 6a6e1b1cf41b0bf35fffbf18787e8d8f865b66d6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:35:07 +0200 Subject: [PATCH] ide: hotplug mark __devinit sc1200.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/sc1200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 3bc3bf1be49..10592cec6c4 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -459,7 +459,7 @@ printk("%s: SC1200: resume\n", hwif->name); * This gets invoked by the IDE driver once for each channel, * and performs channel-specific pre-initialization before drive probing. */ -static void __init init_hwif_sc1200 (ide_hwif_t *hwif) +static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif) { if (hwif->mate) hwif->serialized = hwif->mate->serialized = 1; -- cgit v1.2.3 From 34a6224691e638dd36b393aa439d021a19578fcc Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:36:56 +0200 Subject: [PATCH] ide: hotplug mark __devinit sl82c105.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/sl82c105.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 1d970a0de21..ea0806c82be 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -386,7 +386,7 @@ static unsigned int sl82c105_bridge_revision(struct pci_dev *dev) * channel 0 here at least, but channel 1 has to be enabled by * firmware or arch code. We still set both to 16 bits mode. */ -static unsigned int __init init_chipset_sl82c105(struct pci_dev *dev, const char *msg) +static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const char *msg) { u32 val; @@ -399,7 +399,7 @@ static unsigned int __init init_chipset_sl82c105(struct pci_dev *dev, const char return dev->irq; } -static void __init init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base) +static void __devinit init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base) { unsigned int rev; u8 dma_state; @@ -431,7 +431,7 @@ static void __init init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base) * Initialise the chip */ -static void __init init_hwif_sl82c105(ide_hwif_t *hwif) +static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; u32 val; -- cgit v1.2.3 From 97319630b21c2022a55d51a6cfbf53cbb84a2f42 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:38:51 +0200 Subject: [PATCH] ide: hotplug mark __devinit slc90e66.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/slc90e66.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 7fbf36342f7..5112c726633 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -196,7 +196,7 @@ fast_ata_pio: } #endif /* CONFIG_BLK_DEV_IDEDMA */ -static void __init init_hwif_slc90e66 (ide_hwif_t *hwif) +static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif) { u8 reg47 = 0; u8 mask = hwif->channel ? 0x01 : 0x02; /* bit0:Primary */ -- cgit v1.2.3 From d6904ab66f74cb99793e3919fc589dd0163a7740 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:40:31 +0200 Subject: [PATCH] ide: hotplug mark __devinit triflex.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/triflex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index a1df2bfe363..f96b56838f3 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -130,7 +130,7 @@ static int triflex_config_drive_xfer_rate(ide_drive_t *drive) return hwif->ide_dma_off_quietly(drive); } -static void __init init_hwif_triflex(ide_hwif_t *hwif) +static void __devinit init_hwif_triflex(ide_hwif_t *hwif) { hwif->tuneproc = &triflex_tune_drive; hwif->speedproc = &triflex_tune_chipset; -- cgit v1.2.3 From f3718d3e135117f80de0ff219be91544baa75599 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 3 Jul 2005 16:42:18 +0200 Subject: [PATCH] ide: hotplug mark __devinit via82cxxx.c From: Herbert Xu mark the __init section __devinit. Splitted up from the Debian kernel patch. Signed-off-by: maximilian attems Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/via82cxxx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 069dbffe211..a4d099c937f 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -415,7 +415,7 @@ static int via82cxxx_ide_dma_check (ide_drive_t *drive) * and initialize its drive independent registers. */ -static unsigned int __init init_chipset_via82cxxx(struct pci_dev *dev, const char *name) +static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const char *name) { struct pci_dev *isa = NULL; u8 t, v; @@ -576,7 +576,7 @@ static unsigned int __init init_chipset_via82cxxx(struct pci_dev *dev, const cha return 0; } -static void __init init_hwif_via82cxxx(ide_hwif_t *hwif) +static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif) { int i; -- cgit v1.2.3 From 13bbbf28fb914da6707aad44a073651f5c9d13a5 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sun, 3 Jul 2005 17:09:13 +0200 Subject: [PATCH] ide: fix line break in ide messages From: Denis Vlasenko * printk("\n") is misplaced, resulting in stray empty line in kernel log * cleanups nerby: some back-to-back printks are combined, etc Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-lib.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 6806d407e9c..b09a6537c7a 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -487,8 +487,7 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat) u8 err = 0; local_irq_set(flags); - printk("%s: %s: status=0x%02x", drive->name, msg, stat); - printk(" { "); + printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); if (stat & BUSY_STAT) printk("Busy "); else { @@ -500,15 +499,13 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat) if (stat & INDEX_STAT) printk("Index "); if (stat & ERR_STAT) printk("Error "); } - printk("}"); - printk("\n"); + printk("}\n"); if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { err = hwif->INB(IDE_ERROR_REG); - printk("%s: %s: error=0x%02x", drive->name, msg, err); - printk(" { "); + printk("%s: %s: error=0x%02x { ", drive->name, msg, err); if (err & ABRT_ERR) printk("DriveStatusError "); if (err & ICRC_ERR) - printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector"); + printk((err & ABRT_ERR) ? "BadCRC " : "BadSector "); if (err & ECC_ERR) printk("UncorrectableError "); if (err & ID_ERR) printk("SectorIdNotFound "); if (err & TRK0_ERR) printk("TrackZeroNotFound "); @@ -546,8 +543,8 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat) printk(", sector=%llu", (unsigned long long)HWGROUP(drive)->rq->sector); } + printk("\n"); } - printk("\n"); ide_dump_opcode(drive); local_irq_restore(flags); return err; -- cgit v1.2.3 From 21e2c01dc3e38d466eda5871645878d2c3a33261 Mon Sep 17 00:00:00 2001 From: Rob Punkunus Date: Sun, 3 Jul 2005 17:37:18 +0200 Subject: [PATCH] amd74xx: support MCP55 device IDs From: Rob Punkunus Rob Punkunus recently submitted a patch to enable support for MCP51/MCP55 in the amd74xx driver. This patch was whitespace-corrupted and didn't apply to 2.6.12 since MCP51 support was merged in the 2.6.12-rc series. Gentoo would like to support this hardware for our upcoming release media, so I fixed the patch, and here it is :) Signed-off-by: Daniel Drake Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/amd74xx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 65eab9b63a7..844a6c9fb94 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -73,6 +73,7 @@ static struct amd_ide_chip { { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 }, + { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 }, { 0 } }; @@ -489,6 +490,7 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { /* 13 */ DECLARE_NV_DEV("NFORCE-CK804"), /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"), /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"), + /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"), }; static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) @@ -524,6 +526,7 @@ static struct pci_device_id amd74xx_pci_tbl[] = { { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); -- cgit v1.2.3 From 10e047b40aafefef1fdc8ea4ea7837b9557a9400 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 3 Jul 2005 17:44:10 +0200 Subject: [PATCH] drivers/ide/Makefile: kill dead CONFIG_BLK_DEV_IDE_TCQ entry This patch kills the dead CONFIG_BLK_DEV_IDE_TCQ entry. Signed-off-by: Adrian Bunk Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/Makefile | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 5be8ad6dc9e..cca9c075966 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -20,7 +20,6 @@ ide-core-$(CONFIG_BLK_DEV_CMD640) += pci/cmd640.o # Core IDE code - must come before legacy ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o -ide-core-$(CONFIG_BLK_DEV_IDE_TCQ) += ide-tcq.o ide-core-$(CONFIG_PROC_FS) += ide-proc.o ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o -- cgit v1.2.3 From 75f631dc45c7327df26b82b9aea69376a306409c Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 3 Jul 2005 17:44:40 +0100 Subject: [PATCH] ARM: 2785/1: S3C24XX - serial calls request_irq() with IRQs disabled Patch from Ben Dooks The request_irq() function is called by s3c24xx uart driver with the local IRQs disabled. The request_irq() function can allocate memory via kmalloc(), and this may sleep causing a warning about sleeping in an invalid context. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- drivers/serial/s3c2410.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 5c4678478b1..7365d4b50b9 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -522,14 +522,11 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) static int s3c24xx_serial_startup(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); - unsigned long flags; int ret; dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n", port->mapbase, port->membase); - local_irq_save(flags); - rx_enabled(port) = 1; ret = request_irq(RX_IRQ(port), @@ -563,12 +560,10 @@ static int s3c24xx_serial_startup(struct uart_port *port) /* the port reset code should have done the correct * register setup for the port controls */ - local_irq_restore(flags); return ret; err: s3c24xx_serial_shutdown(port); - local_irq_restore(flags); return ret; } -- cgit v1.2.3 From 976ecd12b8144d066a23fe97c6fbfc1ac8470af7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 3 Jul 2005 21:05:45 +0100 Subject: [PATCH] Serial: Fix console port spinlock initialisation Initialise the spinlock for port being used by the console early, but don't re-initialise it again later. Signed-off-by: Russell King --- drivers/serial/serial_core.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 139863a787f..54699c3a00a 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1808,6 +1808,12 @@ uart_set_options(struct uart_port *port, struct console *co, struct termios termios; int i; + /* + * Ensure that the serial console lock is initialised + * early. + */ + spin_lock_init(&port->lock); + memset(&termios, 0, sizeof(struct termios)); termios.c_cflag = CREAD | HUPCL | CLOCAL; @@ -2196,10 +2202,16 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) state->port = port; - spin_lock_init(&port->lock); port->cons = drv->cons; port->info = state->info; + /* + * If this port is a console, then the spinlock is already + * initialised. + */ + if (!uart_console(port)) + spin_lock_init(&port->lock); + uart_configure_port(drv, state, port); /* -- cgit v1.2.3 From 3a7a882420d378b59542a048075e40428c771a12 Mon Sep 17 00:00:00 2001 From: Coywolf Qi Hunt Date: Mon, 4 Jul 2005 12:15:28 -0500 Subject: [MTD] mtdchar: Return the real error code when create_class() failed Signed-off-by: Coywolf Qi Hunt Signed-off-by: Thomas Gleixner --- drivers/mtd/mtdchar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index b606f811eeb..1ed602a0f24 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1,5 +1,5 @@ /* - * $Id: mtdchar.c,v 1.72 2005/06/30 00:23:24 tpoynor Exp $ + * $Id: mtdchar.c,v 1.73 2005/07/04 17:36:41 gleixner Exp $ * * Character-device access to raw MTD devices. * @@ -649,7 +649,7 @@ static int __init init_mtdchar(void) if (IS_ERR(mtd_class)) { printk(KERN_ERR "Error creating mtd class.\n"); unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); - return 1; + return PTR_ERR(mtd_class); } register_mtd_user(¬ifier); -- cgit v1.2.3 From 06326e40b7c66477d4a460bfc23c951f7b39f191 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 13:24:14 -0700 Subject: [SPARC]: bpp: remove sleep_on usage Use schedule_timeout() instead of sleep_on + timer. Totally untested due to lack of hardware, but the changes are rather trivial. Signed-off-by: David S. Miller --- drivers/sbus/char/bpp.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c index 8f0f46907a8..87302fb1488 100644 --- a/drivers/sbus/char/bpp.c +++ b/drivers/sbus/char/bpp.c @@ -79,10 +79,6 @@ struct inst { unsigned char run_length; unsigned char repeat_byte; - - /* These members manage timeouts for programmed delays */ - wait_queue_head_t wait_queue; - struct timer_list timer_list; }; static struct inst instances[BPP_NO]; @@ -297,16 +293,10 @@ static unsigned short get_pins(unsigned minor) #endif /* __sparc__ */ -static void bpp_wake_up(unsigned long val) -{ wake_up(&instances[val].wait_queue); } - static void snooze(unsigned long snooze_time, unsigned minor) { - init_timer(&instances[minor].timer_list); - instances[minor].timer_list.expires = jiffies + snooze_time + 1; - instances[minor].timer_list.data = minor; - add_timer(&instances[minor].timer_list); - sleep_on (&instances[minor].wait_queue); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(snooze_time + 1); } static int wait_for(unsigned short set, unsigned short clr, @@ -880,11 +870,8 @@ static void probeLptPort(unsigned idx) instances[idx].enhanced = 0; instances[idx].direction = 0; instances[idx].mode = COMPATIBILITY; - instances[idx].wait_queue = 0; instances[idx].run_length = 0; instances[idx].run_flag = 0; - init_timer(&instances[idx].timer_list); - instances[idx].timer_list.function = bpp_wake_up; if (!request_region(lpAddr,3, dev_name)) return; /* @@ -977,11 +964,8 @@ static void probeLptPort(unsigned idx) instances[idx].enhanced = 0; instances[idx].direction = 0; instances[idx].mode = COMPATIBILITY; - init_waitqueue_head(&instances[idx].wait_queue); instances[idx].run_length = 0; instances[idx].run_flag = 0; - init_timer(&instances[idx].timer_list); - instances[idx].timer_list.function = bpp_wake_up; if (!rp) return; -- cgit v1.2.3 From f8eb321bee957b7464ae08839861a04cb0b51bbe Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 5 Jul 2005 01:03:06 +0200 Subject: [MTD] cfi_cmdset_0002: Remove bogus include Including asm/hardware.h has to be done in linux/mtd/xip.h. Otherwise it breaks allyes compiles. Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0002.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index e42eefbda0e..c76c30de48f 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -17,7 +17,7 @@ * * This code is GPL * - * $Id: cfi_cmdset_0002.c,v 1.117 2005/06/06 23:04:35 tpoynor Exp $ + * $Id: cfi_cmdset_0002.c,v 1.118 2005/07/04 22:34:29 gleixner Exp $ * */ @@ -581,7 +581,7 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad * didn't emit calls to its own support functions). Also configuring MTD CFI * support to a single buswidth and a single interleave is also recommended. */ -#include + static void xip_disable(struct map_info *map, struct flchip *chip, unsigned long adr) { -- cgit v1.2.3 From a31488ca4b8476a8dd301b21388631df52d05c5a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 5 Jul 2005 14:24:35 -0700 Subject: [SKGE]: Fix build on big-endian Missing PCI_REV_DESC define. Signed-off-by: David S. Miller --- drivers/net/skge.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 14d0cc01fb9..fced3d2bc07 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -7,6 +7,7 @@ /* PCI config registers */ #define PCI_DEV_REG1 0x40 #define PCI_DEV_REG2 0x44 +#define PCI_REV_DESC 0x4 #define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \ PCI_STATUS_SIG_SYSTEM_ERROR | \ -- cgit v1.2.3 From d244c892c8e23d6baba88af88f78f7201a224d39 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 5 Jul 2005 14:42:33 -0700 Subject: [TG3]: support for ethtool -C Add support for ethtool -C with verification of user parameters. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- drivers/net/tg3.h | 10 +++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7e371b1209a..7f84dc89bd7 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5117,7 +5117,7 @@ static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr, } static void __tg3_set_rx_mode(struct net_device *); -static void tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) +static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) { tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs); tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs); @@ -5460,7 +5460,7 @@ static int tg3_reset_hw(struct tg3 *tp) udelay(10); } - tg3_set_coalesce(tp, &tp->coal); + __tg3_set_coalesce(tp, &tp->coal); /* set status block DMA address */ tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, @@ -7821,6 +7821,60 @@ static int tg3_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) return 0; } +static int tg3_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec) +{ + struct tg3 *tp = netdev_priv(dev); + u32 max_rxcoal_tick_int = 0, max_txcoal_tick_int = 0; + u32 max_stat_coal_ticks = 0, min_stat_coal_ticks = 0; + + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { + max_rxcoal_tick_int = MAX_RXCOAL_TICK_INT; + max_txcoal_tick_int = MAX_TXCOAL_TICK_INT; + max_stat_coal_ticks = MAX_STAT_COAL_TICKS; + min_stat_coal_ticks = MIN_STAT_COAL_TICKS; + } + + if ((ec->rx_coalesce_usecs > MAX_RXCOL_TICKS) || + (ec->tx_coalesce_usecs > MAX_TXCOL_TICKS) || + (ec->rx_max_coalesced_frames > MAX_RXMAX_FRAMES) || + (ec->tx_max_coalesced_frames > MAX_TXMAX_FRAMES) || + (ec->rx_coalesce_usecs_irq > max_rxcoal_tick_int) || + (ec->tx_coalesce_usecs_irq > max_txcoal_tick_int) || + (ec->rx_max_coalesced_frames_irq > MAX_RXCOAL_MAXF_INT) || + (ec->tx_max_coalesced_frames_irq > MAX_TXCOAL_MAXF_INT) || + (ec->stats_block_coalesce_usecs > max_stat_coal_ticks) || + (ec->stats_block_coalesce_usecs < min_stat_coal_ticks)) + return -EINVAL; + + /* No rx interrupts will be generated if both are zero */ + if ((ec->rx_coalesce_usecs == 0) && + (ec->rx_max_coalesced_frames == 0)) + return -EINVAL; + + /* No tx interrupts will be generated if both are zero */ + if ((ec->tx_coalesce_usecs == 0) && + (ec->tx_max_coalesced_frames == 0)) + return -EINVAL; + + /* Only copy relevant parameters, ignore all others. */ + tp->coal.rx_coalesce_usecs = ec->rx_coalesce_usecs; + tp->coal.tx_coalesce_usecs = ec->tx_coalesce_usecs; + tp->coal.rx_max_coalesced_frames = ec->rx_max_coalesced_frames; + tp->coal.tx_max_coalesced_frames = ec->tx_max_coalesced_frames; + tp->coal.rx_coalesce_usecs_irq = ec->rx_coalesce_usecs_irq; + tp->coal.tx_coalesce_usecs_irq = ec->tx_coalesce_usecs_irq; + tp->coal.rx_max_coalesced_frames_irq = ec->rx_max_coalesced_frames_irq; + tp->coal.tx_max_coalesced_frames_irq = ec->tx_max_coalesced_frames_irq; + tp->coal.stats_block_coalesce_usecs = ec->stats_block_coalesce_usecs; + + if (netif_running(dev)) { + tg3_full_lock(tp, 0); + __tg3_set_coalesce(tp, &tp->coal); + tg3_full_unlock(tp); + } + return 0; +} + static struct ethtool_ops tg3_ethtool_ops = { .get_settings = tg3_get_settings, .set_settings = tg3_set_settings, @@ -7856,6 +7910,7 @@ static struct ethtool_ops tg3_ethtool_ops = { .get_stats_count = tg3_get_stats_count, .get_ethtool_stats = tg3_get_ethtool_stats, .get_coalesce = tg3_get_coalesce, + .set_coalesce = tg3_set_coalesce, }; static void __devinit tg3_get_eeprom_size(struct tg3 *tp) @@ -9800,6 +9855,12 @@ static void __devinit tg3_init_coal(struct tg3 *tp) ec->tx_coalesce_usecs = LOW_TXCOL_TICKS_CLRTCKS; ec->tx_coalesce_usecs_irq = DEFAULT_TXCOAL_TICK_INT_CLRTCKS; } + + if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + ec->rx_coalesce_usecs_irq = 0; + ec->tx_coalesce_usecs_irq = 0; + ec->stats_block_coalesce_usecs = 0; + } } static int __devinit tg3_init_one(struct pci_dev *pdev, diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 99c5f9675a5..70ad450733e 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -879,31 +879,41 @@ #define LOW_RXCOL_TICKS_CLRTCKS 0x00000014 #define DEFAULT_RXCOL_TICKS 0x00000048 #define HIGH_RXCOL_TICKS 0x00000096 +#define MAX_RXCOL_TICKS 0x000003ff #define HOSTCC_TXCOL_TICKS 0x00003c0c #define LOW_TXCOL_TICKS 0x00000096 #define LOW_TXCOL_TICKS_CLRTCKS 0x00000048 #define DEFAULT_TXCOL_TICKS 0x0000012c #define HIGH_TXCOL_TICKS 0x00000145 +#define MAX_TXCOL_TICKS 0x000003ff #define HOSTCC_RXMAX_FRAMES 0x00003c10 #define LOW_RXMAX_FRAMES 0x00000005 #define DEFAULT_RXMAX_FRAMES 0x00000008 #define HIGH_RXMAX_FRAMES 0x00000012 +#define MAX_RXMAX_FRAMES 0x000000ff #define HOSTCC_TXMAX_FRAMES 0x00003c14 #define LOW_TXMAX_FRAMES 0x00000035 #define DEFAULT_TXMAX_FRAMES 0x0000004b #define HIGH_TXMAX_FRAMES 0x00000052 +#define MAX_TXMAX_FRAMES 0x000000ff #define HOSTCC_RXCOAL_TICK_INT 0x00003c18 #define DEFAULT_RXCOAL_TICK_INT 0x00000019 #define DEFAULT_RXCOAL_TICK_INT_CLRTCKS 0x00000014 +#define MAX_RXCOAL_TICK_INT 0x000003ff #define HOSTCC_TXCOAL_TICK_INT 0x00003c1c #define DEFAULT_TXCOAL_TICK_INT 0x00000019 #define DEFAULT_TXCOAL_TICK_INT_CLRTCKS 0x00000014 +#define MAX_TXCOAL_TICK_INT 0x000003ff #define HOSTCC_RXCOAL_MAXF_INT 0x00003c20 #define DEFAULT_RXCOAL_MAXF_INT 0x00000005 +#define MAX_RXCOAL_MAXF_INT 0x000000ff #define HOSTCC_TXCOAL_MAXF_INT 0x00003c24 #define DEFAULT_TXCOAL_MAXF_INT 0x00000005 +#define MAX_TXCOAL_MAXF_INT 0x000000ff #define HOSTCC_STAT_COAL_TICKS 0x00003c28 #define DEFAULT_STAT_COAL_TICKS 0x000f4240 +#define MAX_STAT_COAL_TICKS 0xd693d400 +#define MIN_STAT_COAL_TICKS 0x00000064 /* 0x3c2c --> 0x3c30 unused */ #define HOSTCC_STATS_BLK_HOST_ADDR 0x00003c30 /* 64-bit */ #define HOSTCC_STATUS_BLK_HOST_ADDR 0x00003c38 /* 64-bit */ -- cgit v1.2.3 From 93e266f600f4048fe7a2e8803abb9f8baff84aa7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 5 Jul 2005 14:43:19 -0700 Subject: [TG3]: Update driver version and reldate. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7f84dc89bd7..54640686e98 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -66,8 +66,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.32" -#define DRV_MODULE_RELDATE "June 24, 2005" +#define DRV_MODULE_VERSION "3.33" +#define DRV_MODULE_RELDATE "July 5, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3 From bc971dee6ece1fd0d431948924becd9c50e7b778 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 5 Jul 2005 15:03:46 -0700 Subject: [SHAPER]: Switch to spinlocks. Dave, you were right and the sleeping locks in shaper were broken. Markus Kanet noticed this and also tested the patch below that switches locking to spinlocks. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- drivers/net/shaper.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 20edeb34579..3ad0b6751f6 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -135,10 +135,8 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct shaper *shaper = dev->priv; struct sk_buff *ptr; - - if (down_trylock(&shaper->sem)) - return -1; - + + spin_lock(&shaper->lock); ptr=shaper->sendq.prev; /* @@ -232,7 +230,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev) shaper->stats.collisions++; } shaper_kick(shaper); - up(&shaper->sem); + spin_unlock(&shaper->lock); return 0; } @@ -271,11 +269,9 @@ static void shaper_timer(unsigned long data) { struct shaper *shaper = (struct shaper *)data; - if (!down_trylock(&shaper->sem)) { - shaper_kick(shaper); - up(&shaper->sem); - } else - mod_timer(&shaper->timer, jiffies); + spin_lock(&shaper->lock); + shaper_kick(shaper); + spin_unlock(&shaper->lock); } /* @@ -331,21 +327,6 @@ static void shaper_kick(struct shaper *shaper) } -/* - * Flush the shaper queues on a closedown - */ - -static void shaper_flush(struct shaper *shaper) -{ - struct sk_buff *skb; - - down(&shaper->sem); - while((skb=skb_dequeue(&shaper->sendq))!=NULL) - dev_kfree_skb(skb); - shaper_kick(shaper); - up(&shaper->sem); -} - /* * Bring the interface up. We just disallow this until a * bind. @@ -375,7 +356,15 @@ static int shaper_open(struct net_device *dev) static int shaper_close(struct net_device *dev) { struct shaper *shaper=dev->priv; - shaper_flush(shaper); + struct sk_buff *skb; + + while ((skb = skb_dequeue(&shaper->sendq)) != NULL) + dev_kfree_skb(skb); + + spin_lock_bh(&shaper->lock); + shaper_kick(shaper); + spin_unlock_bh(&shaper->lock); + del_timer_sync(&shaper->timer); return 0; } @@ -576,6 +565,7 @@ static void shaper_init_priv(struct net_device *dev) init_timer(&sh->timer); sh->timer.function=shaper_timer; sh->timer.data=(unsigned long)sh; + spin_lock_init(&sh->lock); } /* -- cgit v1.2.3 From e6b6239f8e8e5bd9ba0192a854652abf14e28ce4 Mon Sep 17 00:00:00 2001 From: Andrei Konovalov Date: Tue, 5 Jul 2005 18:54:43 -0700 Subject: [PATCH] ppc32: add Freescale MPC885ADS board support This patch adds the Freescale MPC86xADS board support. The supported devices are SMC UART and 10Mbit ethernet on SCC1. The manual for the board says that it "is compatible with the MPC8xxFADS for software point of view". That's why this patch extends FADS instead of introducing a new platform. FEC is not supported as the "combined FCC/FEC ethernet driver" driver by Pantelis Antoniou should replace the current FEC driver. Signed-off-by: Gennadiy Kurtsman Signed-off-by: Andrei Konovalov Acked-by: Tom Rini Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/serial/cpm_uart/cpm_uart_cpm1.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index de26cf7b003..7911912f50c 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -94,12 +94,42 @@ void smc1_lineif(struct uart_cpm_port *pinfo) ((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits; } +#ifdef CONFIG_MPC885ADS + /* Enable SMC1 transceivers */ + { + volatile uint __iomem *bcsr1 = ioremap(BCSR1, 4); + uint tmp; + + tmp = in_be32(bcsr1); + tmp &= ~BCSR1_RS232EN_1; + out_be32(bcsr1, tmp); + iounmap(bcsr1); + } +#endif + pinfo->brg = 1; } void smc2_lineif(struct uart_cpm_port *pinfo) { - /* XXX SMC2: insert port configuration here */ +#ifdef CONFIG_MPC885ADS + volatile cpm8xx_t *cp = cpmp; + volatile uint __iomem *bcsr1; + uint tmp; + + cp->cp_pepar |= 0x00000c00; + cp->cp_pedir &= ~0x00000c00; + cp->cp_peso &= ~0x00000400; + cp->cp_peso |= 0x00000800; + + /* Enable SMC2 transceivers */ + bcsr1 = ioremap(BCSR1, 4); + tmp = in_be32(bcsr1); + tmp &= ~BCSR1_RS232EN_2; + out_be32(bcsr1, tmp); + iounmap(bcsr1); +#endif + pinfo->brg = 2; } -- cgit v1.2.3 From 0c80336e5e81846fcb028d5a677794f08201fa1c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 6 Jul 2005 11:28:27 +0200 Subject: [MTD] NAND: sharpsl.c set correct file permissions Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/sharpsl.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 drivers/mtd/nand/sharpsl.c (limited to 'drivers') diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c old mode 100755 new mode 100644 -- cgit v1.2.3 From ba9fb37ba07219fa251edbab1a50fdc7b33da5fa Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 6 Jul 2005 11:40:12 +0200 Subject: [MTD] NAND: Remove unmaintained tx49xx board drivers The drivers are unmaintained since long and reference include files which are not available in the kernel. Original author is not longer responsible and no new maintainer showed up within 3 month. Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/Kconfig | 14 -- drivers/mtd/nand/Makefile | 2 - drivers/mtd/nand/tx4925ndfmc.c | 416 ----------------------------------------- drivers/mtd/nand/tx4938ndfmc.c | 406 ---------------------------------------- 4 files changed, 838 deletions(-) delete mode 100644 drivers/mtd/nand/tx4925ndfmc.c delete mode 100644 drivers/mtd/nand/tx4938ndfmc.c (limited to 'drivers') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 94b1d0e3ec8..36d34e5e5a5 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -58,20 +58,6 @@ config MTD_NAND_TOTO config MTD_NAND_IDS tristate -config MTD_NAND_TX4925NDFMC - tristate "SmartMedia Card on Toshiba RBTX4925 reference board" - depends on TOSHIBA_RBTX4925 && MTD_NAND && TOSHIBA_RBTX4925_MPLEX_NAND - help - This enables the driver for the NAND flash device found on the - Toshiba RBTX4925 reference board, which is a SmartMediaCard. - -config MTD_NAND_TX4938NDFMC - tristate "NAND Flash device on Toshiba RBTX4938 reference board" - depends on TOSHIBA_RBTX4938 && MTD_NAND && TOSHIBA_RBTX4938_MPLEX_NAND - help - This enables the driver for the NAND flash device found on the - Toshiba RBTX4938 reference board. - config MTD_NAND_AU1550 tristate "Au1550 NAND support" depends on SOC_AU1550 && MTD_NAND diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index d9dc8cc2da8..41742026a52 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -10,8 +10,6 @@ obj-$(CONFIG_MTD_NAND_SPIA) += spia.o obj-$(CONFIG_MTD_NAND_TOTO) += toto.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o -obj-$(CONFIG_MTD_NAND_TX4925NDFMC) += tx4925ndfmc.o -obj-$(CONFIG_MTD_NAND_TX4938NDFMC) += tx4938ndfmc.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o diff --git a/drivers/mtd/nand/tx4925ndfmc.c b/drivers/mtd/nand/tx4925ndfmc.c deleted file mode 100644 index bba688830c9..00000000000 --- a/drivers/mtd/nand/tx4925ndfmc.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * drivers/mtd/tx4925ndfmc.c - * - * Overview: - * This is a device driver for the NAND flash device found on the - * Toshiba RBTX4925 reference board, which is a SmartMediaCard. It supports - * 16MiB, 32MiB and 64MiB cards. - * - * Author: MontaVista Software, Inc. source@mvista.com - * - * Derived from drivers/mtd/autcpu12.c - * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) - * - * $Id: tx4925ndfmc.c,v 1.5 2004/10/05 13:50:20 gleixner Exp $ - * - * Copyright (C) 2001 Toshiba Corporation - * - * 2003 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct nand_oobinfo jffs2_oobinfo; - -/* - * MTD structure for RBTX4925 board - */ -static struct mtd_info *tx4925ndfmc_mtd = NULL; - -/* - * Define partitions for flash devices - */ - -static struct mtd_partition partition_info16k[] = { - { .name = "RBTX4925 flash partition 1", - .offset = 0, - .size = 8 * 0x00100000 }, - { .name = "RBTX4925 flash partition 2", - .offset = 8 * 0x00100000, - .size = 8 * 0x00100000 }, -}; - -static struct mtd_partition partition_info32k[] = { - { .name = "RBTX4925 flash partition 1", - .offset = 0, - .size = 8 * 0x00100000 }, - { .name = "RBTX4925 flash partition 2", - .offset = 8 * 0x00100000, - .size = 24 * 0x00100000 }, -}; - -static struct mtd_partition partition_info64k[] = { - { .name = "User FS", - .offset = 0, - .size = 16 * 0x00100000 }, - { .name = "RBTX4925 flash partition 2", - .offset = 16 * 0x00100000, - .size = 48 * 0x00100000}, -}; - -static struct mtd_partition partition_info128k[] = { - { .name = "Skip bad section", - .offset = 0, - .size = 16 * 0x00100000 }, - { .name = "User FS", - .offset = 16 * 0x00100000, - .size = 112 * 0x00100000 }, -}; -#define NUM_PARTITIONS16K 2 -#define NUM_PARTITIONS32K 2 -#define NUM_PARTITIONS64K 2 -#define NUM_PARTITIONS128K 2 - -/* - * hardware specific access to control-lines -*/ -static void tx4925ndfmc_hwcontrol(struct mtd_info *mtd, int cmd) -{ - - switch(cmd){ - - case NAND_CTL_SETCLE: - tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CLE; - break; - case NAND_CTL_CLRCLE: - tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CLE; - break; - case NAND_CTL_SETALE: - tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ALE; - break; - case NAND_CTL_CLRALE: - tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ALE; - break; - case NAND_CTL_SETNCE: - tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CE; - break; - case NAND_CTL_CLRNCE: - tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CE; - break; - case NAND_CTL_SETWP: - tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_WE; - break; - case NAND_CTL_CLRWP: - tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_WE; - break; - } -} - -/* -* read device ready pin -*/ -static int tx4925ndfmc_device_ready(struct mtd_info *mtd) -{ - int ready; - ready = (tx4925_ndfmcptr->sr & TX4925_NDSFR_BUSY) ? 0 : 1; - return ready; -} -void tx4925ndfmc_enable_hwecc(struct mtd_info *mtd, int mode) -{ - /* reset first */ - tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_MASK; - tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK; - tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_ENAB; -} -static void tx4925ndfmc_disable_ecc(void) -{ - tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK; -} -static void tx4925ndfmc_enable_read_ecc(void) -{ - tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK; - tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_READ; -} -void tx4925ndfmc_readecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){ - int i; - u_char *ecc = ecc_code; - tx4925ndfmc_enable_read_ecc(); - for (i = 0;i < 6;i++,ecc++) - *ecc = tx4925_read_nfmc(&(tx4925_ndfmcptr->dtr)); - tx4925ndfmc_disable_ecc(); -} -void tx4925ndfmc_device_setup(void) -{ - - *(unsigned char *)0xbb005000 &= ~0x08; - - /* reset NDFMC */ - tx4925_ndfmcptr->rstr |= TX4925_NDFRSTR_RST; - while (tx4925_ndfmcptr->rstr & TX4925_NDFRSTR_RST); - - /* setup BusSeparete, Hold Time, Strobe Pulse Width */ - tx4925_ndfmcptr->mcr = TX4925_BSPRT ? TX4925_NDFMCR_BSPRT : 0; - tx4925_ndfmcptr->spr = TX4925_HOLD << 4 | TX4925_SPW; -} -static u_char tx4925ndfmc_nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - return tx4925_read_nfmc(this->IO_ADDR_R); -} - -static void tx4925ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte) -{ - struct nand_chip *this = mtd->priv; - tx4925_write_nfmc(byte, this->IO_ADDR_W); -} - -static void tx4925ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - struct nand_chip *this = mtd->priv; - - for (i=0; iIO_ADDR_W); -} - -static void tx4925ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - int i; - struct nand_chip *this = mtd->priv; - - for (i=0; iIO_ADDR_R); -} - -static int tx4925ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - struct nand_chip *this = mtd->priv; - - for (i=0; iIO_ADDR_R)) - return -EFAULT; - - return 0; -} - -/* - * Send command to NAND device - */ -static void tx4925ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) -{ - register struct nand_chip *this = mtd->priv; - - /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); - /* - * Write out the command to the device. - */ - if (command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->oobblock) { - /* OOB area */ - column -= mtd->oobblock; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - this->write_byte(mtd, readcmd); - } - this->write_byte(mtd, command); - - /* Set ALE and clear CLE to start address cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); - - if (column != -1 || page_addr != -1) { - this->hwcontrol(mtd, NAND_CTL_SETALE); - - /* Serially input address */ - if (column != -1) - this->write_byte(mtd, column); - if (page_addr != -1) { - this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); - this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); - /* One more address cycle for higher density devices */ - if (mtd->size & 0x0c000000) - this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); - } - /* Latch in address */ - this->hwcontrol(mtd, NAND_CTL_CLRALE); - } - - /* - * program and erase have their own busy handlers - * status and sequential in needs no delay - */ - switch (command) { - - case NAND_CMD_PAGEPROG: - /* Turn off WE */ - this->hwcontrol (mtd, NAND_CTL_CLRWP); - return; - - case NAND_CMD_SEQIN: - /* Turn on WE */ - this->hwcontrol (mtd, NAND_CTL_SETWP); - return; - - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_STATUS: - return; - - case NAND_CMD_RESET: - if (this->dev_ready) - break; - this->hwcontrol(mtd, NAND_CTL_SETCLE); - this->write_byte(mtd, NAND_CMD_STATUS); - this->hwcontrol(mtd, NAND_CTL_CLRCLE); - while ( !(this->read_byte(mtd) & 0x40)); - return; - - /* This applies to read commands */ - default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay - */ - if (!this->dev_ready) { - udelay (this->chip_delay); - return; - } - } - - /* wait until command is processed */ - while (!this->dev_ready(mtd)); -} - -#ifdef CONFIG_MTD_CMDLINE_PARTS -extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partitio -n **pparts, char *); -#endif - -/* - * Main initialization routine - */ -extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); -int __init tx4925ndfmc_init (void) -{ - struct nand_chip *this; - int err = 0; - - /* Allocate memory for MTD device structure and private data */ - tx4925ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), - GFP_KERNEL); - if (!tx4925ndfmc_mtd) { - printk ("Unable to allocate RBTX4925 NAND MTD device structure.\n"); - err = -ENOMEM; - goto out; - } - - tx4925ndfmc_device_setup(); - - /* io is indirect via a register so don't need to ioremap address */ - - /* Get pointer to private data */ - this = (struct nand_chip *) (&tx4925ndfmc_mtd[1]); - - /* Initialize structures */ - memset((char *) tx4925ndfmc_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); - - /* Link the private data with the MTD structure */ - tx4925ndfmc_mtd->priv = this; - - /* Set address of NAND IO lines */ - this->IO_ADDR_R = (void __iomem *)&(tx4925_ndfmcptr->dtr); - this->IO_ADDR_W = (void __iomem *)&(tx4925_ndfmcptr->dtr); - this->hwcontrol = tx4925ndfmc_hwcontrol; - this->enable_hwecc = tx4925ndfmc_enable_hwecc; - this->calculate_ecc = tx4925ndfmc_readecc; - this->correct_data = nand_correct_data; - this->eccmode = NAND_ECC_HW6_512; - this->dev_ready = tx4925ndfmc_device_ready; - /* 20 us command delay time */ - this->chip_delay = 20; - this->read_byte = tx4925ndfmc_nand_read_byte; - this->write_byte = tx4925ndfmc_nand_write_byte; - this->cmdfunc = tx4925ndfmc_nand_command; - this->write_buf = tx4925ndfmc_nand_write_buf; - this->read_buf = tx4925ndfmc_nand_read_buf; - this->verify_buf = tx4925ndfmc_nand_verify_buf; - - /* Scan to find existance of the device */ - if (nand_scan (tx4925ndfmc_mtd, 1)) { - err = -ENXIO; - goto out_ior; - } - - /* Register the partitions */ -#ifdef CONFIG_MTD_CMDLINE_PARTS - { - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = 0; - mtd_parts_nb = parse_cmdline_partitions(tx4925ndfmc_mtd, &mtd_parts, "tx4925ndfmc"); - if (mtd_parts_nb > 0) - add_mtd_partitions(tx4925ndfmc_mtd, mtd_parts, mtd_parts_nb); - else - add_mtd_device(tx4925ndfmc_mtd); - } -#else /* ifdef CONFIG_MTD_CMDLINE_PARTS */ - switch(tx4925ndfmc_mtd->size){ - case 0x01000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info16k, NUM_PARTITIONS16K); break; - case 0x02000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info32k, NUM_PARTITIONS32K); break; - case 0x04000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info64k, NUM_PARTITIONS64K); break; - case 0x08000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info128k, NUM_PARTITIONS128K); break; - default: { - printk ("Unsupported SmartMedia device\n"); - err = -ENXIO; - goto out_ior; - } - } -#endif /* ifdef CONFIG_MTD_CMDLINE_PARTS */ - goto out; - -out_ior: -out: - return err; -} - -module_init(tx4925ndfmc_init); - -/* - * Clean up routine - */ -#ifdef MODULE -static void __exit tx4925ndfmc_cleanup (void) -{ - /* Release resources, unregister device */ - nand_release (tx4925ndfmc_mtd); - - /* Free the MTD device structure */ - kfree (tx4925ndfmc_mtd); -} -module_exit(tx4925ndfmc_cleanup); -#endif - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Alice Hennessy "); -MODULE_DESCRIPTION("Glue layer for SmartMediaCard on Toshiba RBTX4925"); diff --git a/drivers/mtd/nand/tx4938ndfmc.c b/drivers/mtd/nand/tx4938ndfmc.c deleted file mode 100644 index df26e58820b..00000000000 --- a/drivers/mtd/nand/tx4938ndfmc.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - * drivers/mtd/nand/tx4938ndfmc.c - * - * Overview: - * This is a device driver for the NAND flash device connected to - * TX4938 internal NAND Memory Controller. - * TX4938 NDFMC is almost same as TX4925 NDFMC, but register size are 64 bit. - * - * Author: source@mvista.com - * - * Based on spia.c by Steven J. Hill - * - * $Id: tx4938ndfmc.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $ - * - * Copyright (C) 2000-2001 Toshiba Corporation - * - * 2003 (c) MontaVista Software, Inc. This file is licensed under the - * terms of the GNU General Public License version 2. This program is - * licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct nand_oobinfo jffs2_oobinfo; - -/* - * MTD structure for TX4938 NDFMC - */ -static struct mtd_info *tx4938ndfmc_mtd; - -/* - * Define partitions for flash device - */ -#define flush_wb() (void)tx4938_ndfmcptr->mcr; - -#define NUM_PARTITIONS 3 -#define NUMBER_OF_CIS_BLOCKS 24 -#define SIZE_OF_BLOCK 0x00004000 -#define NUMBER_OF_BLOCK_PER_ZONE 1024 -#define SIZE_OF_ZONE (NUMBER_OF_BLOCK_PER_ZONE * SIZE_OF_BLOCK) -#ifndef CONFIG_MTD_CMDLINE_PARTS -/* - * You can use the following sample of MTD partitions - * on the NAND Flash Memory 32MB or more. - * - * The following figure shows the image of the sample partition on - * the 32MB NAND Flash Memory. - * - * Block No. - * 0 +-----------------------------+ ------ - * | CIS | ^ - * 24 +-----------------------------+ | - * | kernel image | | Zone 0 - * | | | - * +-----------------------------+ | - * 1023 | unused area | v - * +-----------------------------+ ------ - * 1024 | JFFS2 | ^ - * | | | - * | | | Zone 1 - * | | | - * | | | - * | | v - * 2047 +-----------------------------+ ------ - * - */ -static struct mtd_partition partition_info[NUM_PARTITIONS] = { - { - .name = "RBTX4938 CIS Area", - .offset = 0, - .size = (NUMBER_OF_CIS_BLOCKS * SIZE_OF_BLOCK), - .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */ - }, - { - .name = "RBTX4938 kernel image", - .offset = MTDPART_OFS_APPEND, - .size = 8 * 0x00100000, /* 8MB (Depends on size of kernel image) */ - .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */ - }, - { - .name = "Root FS (JFFS2)", - .offset = (0 + SIZE_OF_ZONE), /* start address of next zone */ - .size = MTDPART_SIZ_FULL - }, -}; -#endif - -static void tx4938ndfmc_hwcontrol(struct mtd_info *mtd, int cmd) -{ - switch (cmd) { - case NAND_CTL_SETCLE: - tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CLE; - break; - case NAND_CTL_CLRCLE: - tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CLE; - break; - case NAND_CTL_SETALE: - tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_ALE; - break; - case NAND_CTL_CLRALE: - tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_ALE; - break; - /* TX4938_NDFMCR_CE bit is 0:high 1:low */ - case NAND_CTL_SETNCE: - tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CE; - break; - case NAND_CTL_CLRNCE: - tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CE; - break; - case NAND_CTL_SETWP: - tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_WE; - break; - case NAND_CTL_CLRWP: - tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_WE; - break; - } -} -static int tx4938ndfmc_dev_ready(struct mtd_info *mtd) -{ - flush_wb(); - return !(tx4938_ndfmcptr->sr & TX4938_NDFSR_BUSY); -} -static void tx4938ndfmc_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) -{ - u32 mcr = tx4938_ndfmcptr->mcr; - mcr &= ~TX4938_NDFMCR_ECC_ALL; - tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF; - tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_READ; - ecc_code[1] = tx4938_ndfmcptr->dtr; - ecc_code[0] = tx4938_ndfmcptr->dtr; - ecc_code[2] = tx4938_ndfmcptr->dtr; - tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF; -} -static void tx4938ndfmc_enable_hwecc(struct mtd_info *mtd, int mode) -{ - u32 mcr = tx4938_ndfmcptr->mcr; - mcr &= ~TX4938_NDFMCR_ECC_ALL; - tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_RESET; - tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF; - tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_ON; -} - -static u_char tx4938ndfmc_nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - return tx4938_read_nfmc(this->IO_ADDR_R); -} - -static void tx4938ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte) -{ - struct nand_chip *this = mtd->priv; - tx4938_write_nfmc(byte, this->IO_ADDR_W); -} - -static void tx4938ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - struct nand_chip *this = mtd->priv; - - for (i=0; iIO_ADDR_W); -} - -static void tx4938ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - int i; - struct nand_chip *this = mtd->priv; - - for (i=0; iIO_ADDR_R); -} - -static int tx4938ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - struct nand_chip *this = mtd->priv; - - for (i=0; iIO_ADDR_R)) - return -EFAULT; - - return 0; -} - -/* - * Send command to NAND device - */ -static void tx4938ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) -{ - register struct nand_chip *this = mtd->priv; - - /* Begin command latch cycle */ - this->hwcontrol(mtd, NAND_CTL_SETCLE); - /* - * Write out the command to the device. - */ - if (command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->oobblock) { - /* OOB area */ - column -= mtd->oobblock; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - this->write_byte(mtd, readcmd); - } - this->write_byte(mtd, command); - - /* Set ALE and clear CLE to start address cycle */ - this->hwcontrol(mtd, NAND_CTL_CLRCLE); - - if (column != -1 || page_addr != -1) { - this->hwcontrol(mtd, NAND_CTL_SETALE); - - /* Serially input address */ - if (column != -1) - this->write_byte(mtd, column); - if (page_addr != -1) { - this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); - this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); - /* One more address cycle for higher density devices */ - if (mtd->size & 0x0c000000) - this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); - } - /* Latch in address */ - this->hwcontrol(mtd, NAND_CTL_CLRALE); - } - - /* - * program and erase have their own busy handlers - * status and sequential in needs no delay - */ - switch (command) { - - case NAND_CMD_PAGEPROG: - /* Turn off WE */ - this->hwcontrol (mtd, NAND_CTL_CLRWP); - return; - - case NAND_CMD_SEQIN: - /* Turn on WE */ - this->hwcontrol (mtd, NAND_CTL_SETWP); - return; - - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_STATUS: - return; - - case NAND_CMD_RESET: - if (this->dev_ready) - break; - this->hwcontrol(mtd, NAND_CTL_SETCLE); - this->write_byte(mtd, NAND_CMD_STATUS); - this->hwcontrol(mtd, NAND_CTL_CLRCLE); - while ( !(this->read_byte(mtd) & 0x40)); - return; - - /* This applies to read commands */ - default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay - */ - if (!this->dev_ready) { - udelay (this->chip_delay); - return; - } - } - - /* wait until command is processed */ - while (!this->dev_ready(mtd)); -} - -#ifdef CONFIG_MTD_CMDLINE_PARTS -extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *); -#endif -/* - * Main initialization routine - */ -int __init tx4938ndfmc_init (void) -{ - struct nand_chip *this; - int bsprt = 0, hold = 0xf, spw = 0xf; - int protected = 0; - - if ((*rbtx4938_piosel_ptr & 0x0c) != 0x08) { - printk("TX4938 NDFMC: disabled by IOC PIOSEL\n"); - return -ENODEV; - } - bsprt = 1; - hold = 2; - spw = 9 - 1; /* 8 GBUSCLK = 80ns (@ GBUSCLK 100MHz) */ - - if ((tx4938_ccfgptr->pcfg & - (TX4938_PCFG_ATA_SEL|TX4938_PCFG_ISA_SEL|TX4938_PCFG_NDF_SEL)) - != TX4938_PCFG_NDF_SEL) { - printk("TX4938 NDFMC: disabled by PCFG.\n"); - return -ENODEV; - } - - /* reset NDFMC */ - tx4938_ndfmcptr->rstr |= TX4938_NDFRSTR_RST; - while (tx4938_ndfmcptr->rstr & TX4938_NDFRSTR_RST) - ; - /* setup BusSeparete, Hold Time, Strobe Pulse Width */ - tx4938_ndfmcptr->mcr = bsprt ? TX4938_NDFMCR_BSPRT : 0; - tx4938_ndfmcptr->spr = hold << 4 | spw; - - /* Allocate memory for MTD device structure and private data */ - tx4938ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), - GFP_KERNEL); - if (!tx4938ndfmc_mtd) { - printk ("Unable to allocate TX4938 NDFMC MTD device structure.\n"); - return -ENOMEM; - } - - /* Get pointer to private data */ - this = (struct nand_chip *) (&tx4938ndfmc_mtd[1]); - - /* Initialize structures */ - memset((char *) tx4938ndfmc_mtd, 0, sizeof(struct mtd_info)); - memset((char *) this, 0, sizeof(struct nand_chip)); - - /* Link the private data with the MTD structure */ - tx4938ndfmc_mtd->priv = this; - - /* Set address of NAND IO lines */ - this->IO_ADDR_R = (unsigned long)&tx4938_ndfmcptr->dtr; - this->IO_ADDR_W = (unsigned long)&tx4938_ndfmcptr->dtr; - this->hwcontrol = tx4938ndfmc_hwcontrol; - this->dev_ready = tx4938ndfmc_dev_ready; - this->calculate_ecc = tx4938ndfmc_calculate_ecc; - this->correct_data = nand_correct_data; - this->enable_hwecc = tx4938ndfmc_enable_hwecc; - this->eccmode = NAND_ECC_HW3_256; - this->chip_delay = 100; - this->read_byte = tx4938ndfmc_nand_read_byte; - this->write_byte = tx4938ndfmc_nand_write_byte; - this->cmdfunc = tx4938ndfmc_nand_command; - this->write_buf = tx4938ndfmc_nand_write_buf; - this->read_buf = tx4938ndfmc_nand_read_buf; - this->verify_buf = tx4938ndfmc_nand_verify_buf; - - /* Scan to find existance of the device */ - if (nand_scan (tx4938ndfmc_mtd, 1)) { - kfree (tx4938ndfmc_mtd); - return -ENXIO; - } - - if (protected) { - printk(KERN_INFO "TX4938 NDFMC: write protected.\n"); - tx4938ndfmc_mtd->flags &= ~(MTD_WRITEABLE | MTD_ERASEABLE); - } - -#ifdef CONFIG_MTD_CMDLINE_PARTS - { - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = 0; - mtd_parts_nb = parse_cmdline_partitions(tx4938ndfmc_mtd, &mtd_parts, "tx4938ndfmc"); - if (mtd_parts_nb > 0) - add_mtd_partitions(tx4938ndfmc_mtd, mtd_parts, mtd_parts_nb); - else - add_mtd_device(tx4938ndfmc_mtd); - } -#else - add_mtd_partitions(tx4938ndfmc_mtd, partition_info, NUM_PARTITIONS ); -#endif - - return 0; -} -module_init(tx4938ndfmc_init); - -/* - * Clean up routine - */ -static void __exit tx4938ndfmc_cleanup (void) -{ - /* Release resources, unregister device */ - nand_release (tx4938ndfmc_mtd); - - /* Free the MTD device structure */ - kfree (tx4938ndfmc_mtd); -} -module_exit(tx4938ndfmc_cleanup); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Alice Hennessy "); -MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on TX4938 NDFMC"); -- cgit v1.2.3 From cbec19aeb3a3bfafe1d38f6efbea6a7023d31cb9 Mon Sep 17 00:00:00 2001 From: Nico Pitre Date: Fri, 1 Jul 2005 23:55:24 +0100 Subject: [MTD] Add mapping driver for Intel PXA27x Mainstone board flash. From: Nicolas Pitre Signed-off-by: Todd Poynor Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/Kconfig | 10 ++- drivers/mtd/maps/Makefile | 3 +- drivers/mtd/maps/mainstone-flash.c | 178 +++++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 drivers/mtd/maps/mainstone-flash.c (limited to 'drivers') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 8d27dbf3fa8..dbe1716c972 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.51 2005/03/18 02:07:22 gleixner Exp $ +# $Id: Kconfig,v 1.54 2005/06/30 22:41:36 tpoynor Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -129,6 +129,14 @@ config MTD_LUBBOCK This provides a driver for the on-board flash of the Intel 'Lubbock' XScale evaluation board. +config MTD_MAINSTONE + tristate "CFI Flash device mapped on Intel Mainstone XScale eval board" + depends on MACH_MAINSTONE && MTD_CFI_INTELEXT + select MTD_PARTITIONS + help + This provides a driver for the on-board flash of the Intel + 'Mainstone PXA27x evaluation board. + config MTD_OCTAGON tristate "JEDEC Flash device mapped on Octagon 5066 SBC" depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 164cafc101c..789a4b76890 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile.common,v 1.26 2005/03/02 14:51:04 dvrabel Exp $ +# $Id: Makefile.common,v 1.29 2005/06/30 22:41:36 tpoynor Exp $ ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) obj-$(CONFIG_MTD) += map_funcs.o @@ -22,6 +22,7 @@ obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o +obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o obj-$(CONFIG_MTD_MBX860) += mbx860.o obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c new file mode 100644 index 00000000000..87e93fa6058 --- /dev/null +++ b/drivers/mtd/maps/mainstone-flash.c @@ -0,0 +1,178 @@ +/* + * $Id: $ + * + * Map driver for the Mainstone developer platform. + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define ROM_ADDR 0x00000000 +#define FLASH_ADDR 0x04000000 + +#define WINDOW_SIZE 0x04000000 + +static void mainstone_map_inval_cache(struct map_info *map, unsigned long from, + ssize_t len) +{ + consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE); +} + +static struct map_info mainstone_maps[2] = { { + .size = WINDOW_SIZE, + .phys = PXA_CS0_PHYS, + .inval_cache = mainstone_map_inval_cache, +}, { + .size = WINDOW_SIZE, + .phys = PXA_CS1_PHYS, + .inval_cache = mainstone_map_inval_cache, +} }; + +static struct mtd_partition mainstone_partitions[] = { + { + .name = "Bootloader", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_WRITEABLE /* force read-only */ + },{ + .name = "Kernel", + .size = 0x00400000, + .offset = 0x00040000, + },{ + .name = "Filesystem", + .size = MTDPART_SIZ_FULL, + .offset = 0x00440000 + } +}; + +static struct mtd_info *mymtds[2]; +static struct mtd_partition *parsed_parts[2]; +static int nr_parsed_parts[2]; + +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + +static int __init init_mainstone(void) +{ + int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */ + int ret = 0, i; + + mainstone_maps[0].bankwidth = (BOOT_DEF & 1) ? 2 : 4; + mainstone_maps[1].bankwidth = 4; + + /* Compensate for SW7 which swaps the flash banks */ + mainstone_maps[SW7].name = "processor flash"; + mainstone_maps[SW7 ^ 1].name = "main board flash"; + + printk(KERN_NOTICE "Mainstone configured to boot from %s\n", + mainstone_maps[0].name); + + for (i = 0; i < 2; i++) { + mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys, + WINDOW_SIZE); + if (!mainstone_maps[i].virt) { + printk(KERN_WARNING "Failed to ioremap %s\n", + mainstone_maps[i].name); + if (!ret) + ret = -ENOMEM; + continue; + } + mainstone_maps[i].cached = + ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE); + if (!mainstone_maps[i].cached) + printk(KERN_WARNING "Failed to ioremap cached %s\n", + mainstone_maps[i].name); + simple_map_init(&mainstone_maps[i]); + + printk(KERN_NOTICE + "Probing %s at physical address 0x%08lx" + " (%d-bit bankwidth)\n", + mainstone_maps[i].name, mainstone_maps[i].phys, + mainstone_maps[i].bankwidth * 8); + + mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]); + + if (!mymtds[i]) { + iounmap((void *)mainstone_maps[i].virt); + if (mainstone_maps[i].cached) + iounmap(mainstone_maps[i].cached); + if (!ret) + ret = -EIO; + continue; + } + mymtds[i]->owner = THIS_MODULE; + + ret = parse_mtd_partitions(mymtds[i], probes, + &parsed_parts[i], 0); + + if (ret > 0) + nr_parsed_parts[i] = ret; + } + + if (!mymtds[0] && !mymtds[1]) + return ret; + + for (i = 0; i < 2; i++) { + if (!mymtds[i]) { + printk(KERN_WARNING "%s is absent. Skipping\n", + mainstone_maps[i].name); + } else if (nr_parsed_parts[i]) { + add_mtd_partitions(mymtds[i], parsed_parts[i], + nr_parsed_parts[i]); + } else if (!i) { + printk("Using static partitions on %s\n", + mainstone_maps[i].name); + add_mtd_partitions(mymtds[i], mainstone_partitions, + ARRAY_SIZE(mainstone_partitions)); + } else { + printk("Registering %s as whole device\n", + mainstone_maps[i].name); + add_mtd_device(mymtds[i]); + } + } + return 0; +} + +static void __exit cleanup_mainstone(void) +{ + int i; + for (i = 0; i < 2; i++) { + if (!mymtds[i]) + continue; + + if (nr_parsed_parts[i] || !i) + del_mtd_partitions(mymtds[i]); + else + del_mtd_device(mymtds[i]); + + map_destroy(mymtds[i]); + iounmap((void *)mainstone_maps[i].virt); + if (mainstone_maps[i].cached) + iounmap(mainstone_maps[i].cached); + kfree(parsed_parts[i]); + } +} + +module_init(init_mainstone); +module_exit(cleanup_mainstone); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nicolas Pitre "); +MODULE_DESCRIPTION("MTD map driver for Intel Mainstone"); -- cgit v1.2.3 From 10c96f2ec37f5369a785cf8c5a065a15e323c743 Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Sat, 2 Jul 2005 02:53:28 +0100 Subject: [MTD] NOR flash map driver for TI OMAP boards. From: David Brownell, Jian Zhang , Tony Lindgren and others. Signed-off-by: Todd Poynor Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/Kconfig | 11 ++- drivers/mtd/maps/Makefile | 3 +- drivers/mtd/maps/omap_nor.c | 179 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 drivers/mtd/maps/omap_nor.c (limited to 'drivers') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index dbe1716c972..ac853d4d166 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.54 2005/06/30 22:41:36 tpoynor Exp $ +# $Id: Kconfig,v 1.55 2005/07/02 01:53:24 tpoynor Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -523,6 +523,15 @@ config MTD_MPC1211 This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02). If you have such a board, say 'Y'. +config MTD_OMAP_NOR + tristate "TI OMAP board mappings" + depends on MTD_CFI && ARCH_OMAP + help + This enables access to the NOR flash chips on TI OMAP-based + boards defining flash platform devices and flash platform data. + These boards include the Innovator, H2, H3, OSK, Perseus2, and + more. If you have such a board, say 'Y'. + # This needs CFI or JEDEC, depending on the cards found. config MTD_PCI tristate "PCI MTD driver" diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 789a4b76890..7bcbc49e329 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile.common,v 1.29 2005/06/30 22:41:36 tpoynor Exp $ +# $Id: Makefile.common,v 1.30 2005/07/02 01:53:24 tpoynor Exp $ ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) obj-$(CONFIG_MTD) += map_funcs.o @@ -69,3 +69,4 @@ obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o obj-$(CONFIG_MTD_DMV182) += dmv182.o obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o +obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c new file mode 100644 index 00000000000..8cc71409a32 --- /dev/null +++ b/drivers/mtd/maps/omap_nor.c @@ -0,0 +1,179 @@ +/* + * Flash memory support for various TI OMAP boards + * + * Copyright (C) 2001-2002 MontaVista Software Inc. + * Copyright (C) 2003-2004 Texas Instruments + * Copyright (C) 2004 Nokia Corporation + * + * Assembled using driver code copyright the companies above + * and written by David Brownell, Jian Zhang , + * Tony Lindgren and others. + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_MTD_PARTITIONS +static const char *part_probes[] = { /* "RedBoot", */ "cmdlinepart", NULL }; +#endif + +struct omapflash_info { + struct mtd_partition *parts; + struct mtd_info *mtd; + struct map_info map; +}; + +static void omap_set_vpp(struct map_info *map, int enable) +{ + static int count; + + if (enable) { + if (count++ == 0) + OMAP_EMIFS_CONFIG_REG |= OMAP_EMIFS_CONFIG_WP; + } else { + if (count && (--count == 0)) + OMAP_EMIFS_CONFIG_REG &= ~OMAP_EMIFS_CONFIG_WP; + } +} + +static int __devinit omapflash_probe(struct device *dev) +{ + int err; + struct omapflash_info *info; + struct platform_device *pdev = to_platform_device(dev); + struct flash_platform_data *pdata = pdev->dev.platform_data; + struct resource *res = pdev->resource; + unsigned long size = res->end - res->start + 1; + + info = kmalloc(sizeof(struct omapflash_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(info, 0, sizeof(struct omapflash_info)); + + if (!request_mem_region(res->start, size, "flash")) { + err = -EBUSY; + goto out_free_info; + } + + info->map.virt = ioremap(res->start, size); + if (!info->map.virt) { + err = -ENOMEM; + goto out_release_mem_region; + } + info->map.name = pdev->dev.bus_id; + info->map.phys = res->start; + info->map.size = size; + info->map.bankwidth = pdata->width; + info->map.set_vpp = omap_set_vpp; + + simple_map_init(&info->map); + info->mtd = do_map_probe(pdata->map_name, &info->map); + if (!info->mtd) { + err = -EIO; + goto out_iounmap; + } + info->mtd->owner = THIS_MODULE; + +#ifdef CONFIG_MTD_PARTITIONS + err = parse_mtd_partitions(info->mtd, part_probes, &info->parts, 0); + if (err > 0) + add_mtd_partitions(info->mtd, info->parts, err); + else if (err < 0 && pdata->parts) + add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts); + else +#endif + add_mtd_device(info->mtd); + + dev_set_drvdata(&pdev->dev, info); + + return 0; + +out_iounmap: + iounmap(info->map.virt); +out_release_mem_region: + release_mem_region(res->start, size); +out_free_info: + kfree(info); + + return err; +} + +static int __devexit omapflash_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omapflash_info *info = dev_get_drvdata(&pdev->dev); + + dev_set_drvdata(&pdev->dev, NULL); + + if (info) { + if (info->parts) { + del_mtd_partitions(info->mtd); + kfree(info->parts); + } else + del_mtd_device(info->mtd); + map_destroy(info->mtd); + release_mem_region(info->map.phys, info->map.size); + iounmap((void __iomem *) info->map.virt); + kfree(info); + } + + return 0; +} + +static struct device_driver omapflash_driver = { + .name = "omapflash", + .bus = &platform_bus_type, + .probe = omapflash_probe, + .remove = __devexit_p(omapflash_remove), +}; + +static int __init omapflash_init(void) +{ + return driver_register(&omapflash_driver); +} + +static void __exit omapflash_exit(void) +{ + driver_unregister(&omapflash_driver); +} + +module_init(omapflash_init); +module_exit(omapflash_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MTD NOR map driver for TI OMAP boards"); + -- cgit v1.2.3 From 3d3c2ae1101c1f2dff7e2f9d514769779dbd2737 Mon Sep 17 00:00:00 2001 From: Greg KH Date: Wed, 6 Jul 2005 09:09:38 -0700 Subject: [PATCH] PCI: fix !CONFIG_HOTPLUG pci build problem Here's a patch to fix the build issue when CONFIG_HOTPLUG is not enabled in 2.6.13-rc2. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/pci/pci-driver.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index aac6de9568e..e4115a0d5ba 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -17,13 +17,13 @@ * Dynamic device IDs are disabled for !CONFIG_HOTPLUG */ -#ifdef CONFIG_HOTPLUG - struct pci_dynid { struct list_head node; struct pci_device_id id; }; +#ifdef CONFIG_HOTPLUG + /** * store_new_id * -- cgit v1.2.3 From 5e6557722e69840506eb8bc5a1edcdb4e447a917 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Wed, 6 Jul 2005 15:44:41 -0400 Subject: [PATCH] openfirmware: generate device table for userspace This converts the usage of struct of_match to struct of_device_id, similar to pci_device_id. This allows a device table to be generated, which can be parsed by depmod(8) to generate a map file for module loading. In order for hotplug to work with macio devices, patches to module-init-tools and hotplug must be applied. Those patches are available at: ftp://ftp.suse.com/pub/people/jeffm/linux/macio-hotplug/ Signed-off-by: Jeff Mahoney Signed-off-by: Linus Torvalds --- drivers/i2c/busses/i2c-keywest.c | 7 +++---- drivers/ide/ppc/pmac.c | 12 ++---------- drivers/macintosh/macio_asic.c | 4 ++-- drivers/macintosh/mediabay.c | 7 ++----- drivers/macintosh/therm_pm72.c | 9 ++++----- drivers/macintosh/therm_windtunnel.c | 6 +++--- drivers/net/bmac.c | 7 ++----- drivers/net/mace.c | 6 ++---- drivers/net/wireless/airport.c | 8 ++++---- drivers/scsi/mac53c94.c | 7 +++---- drivers/scsi/mesh.c | 8 +++----- drivers/serial/pmac_zilog.c | 9 +++------ drivers/video/platinumfb.c | 6 ++---- 13 files changed, 35 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index 363e545fc01..94ae808314f 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -698,7 +698,7 @@ dispose_iface(struct device *dev) } static int -create_iface_macio(struct macio_dev* dev, const struct of_match *match) +create_iface_macio(struct macio_dev* dev, const struct of_device_id *match) { return create_iface(dev->ofdev.node, &dev->ofdev.dev); } @@ -710,7 +710,7 @@ dispose_iface_macio(struct macio_dev* dev) } static int -create_iface_of_platform(struct of_device* dev, const struct of_match *match) +create_iface_of_platform(struct of_device* dev, const struct of_device_id *match) { return create_iface(dev->node, &dev->dev); } @@ -721,10 +721,9 @@ dispose_iface_of_platform(struct of_device* dev) return dispose_iface(&dev->dev); } -static struct of_match i2c_keywest_match[] = +static struct of_device_id i2c_keywest_match[] = { { - .name = OF_ANY_MATCH, .type = "i2c", .compatible = "keywest" }, diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 818380b5fd2..be0fcc8f4b1 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1419,7 +1419,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) * Attach to a macio probed interface */ static int __devinit -pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_match *match) +pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) { void __iomem *base; unsigned long regbase; @@ -1637,27 +1637,19 @@ pmac_ide_pci_resume(struct pci_dev *pdev) return rc; } -static struct of_match pmac_ide_macio_match[] = +static struct of_device_id pmac_ide_macio_match[] = { { .name = "IDE", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH }, { .name = "ATA", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH }, { - .name = OF_ANY_MATCH, .type = "ide", - .compatible = OF_ANY_MATCH }, { - .name = OF_ANY_MATCH, .type = "ata", - .compatible = OF_ANY_MATCH }, {}, }; diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index d0bda7e3e6a..37b18ee08a2 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -33,7 +33,7 @@ static int macio_bus_match(struct device *dev, struct device_driver *drv) { struct macio_dev * macio_dev = to_macio_device(dev); struct macio_driver * macio_drv = to_macio_driver(drv); - const struct of_match * matches = macio_drv->match_table; + const struct of_device_id * matches = macio_drv->match_table; if (!matches) return 0; @@ -66,7 +66,7 @@ static int macio_device_probe(struct device *dev) int error = -ENODEV; struct macio_driver *drv; struct macio_dev *macio_dev; - const struct of_match *match; + const struct of_device_id *match; drv = to_macio_driver(dev->driver); macio_dev = to_macio_device(dev); diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 4be709e13ee..7c16c25fc5d 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -642,7 +642,7 @@ static int __pmac media_bay_task(void *x) } } -static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_match *match) +static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_device_id *match) { struct media_bay_info* bay; u32 __iomem *regbase; @@ -797,23 +797,20 @@ static struct mb_ops keylargo_mb_ops __pmacdata = { * Therefore we do it all by polling the media bay once each tick. */ -static struct of_match media_bay_match[] = +static struct of_device_id media_bay_match[] = { { .name = "media-bay", - .type = OF_ANY_MATCH, .compatible = "keylargo-media-bay", .data = &keylargo_mb_ops, }, { .name = "media-bay", - .type = OF_ANY_MATCH, .compatible = "heathrow-media-bay", .data = &heathrow_mb_ops, }, { .name = "media-bay", - .type = OF_ANY_MATCH, .compatible = "ohare-media-bay", .data = &ohare_mb_ops, }, diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index feb4e241385..703e3197331 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -120,6 +120,7 @@ #include #include #include +#include #include "therm_pm72.h" @@ -1986,7 +1987,7 @@ static void fcu_lookup_fans(struct device_node *fcu_node) } } -static int fcu_of_probe(struct of_device* dev, const struct of_match *match) +static int fcu_of_probe(struct of_device* dev, const struct of_device_id *match) { int rc; @@ -2009,12 +2010,10 @@ static int fcu_of_remove(struct of_device* dev) return 0; } -static struct of_match fcu_of_match[] = +static struct of_device_id fcu_match[] = { { - .name = OF_ANY_MATCH, .type = "fcu", - .compatible = OF_ANY_MATCH }, {}, }; @@ -2022,7 +2021,7 @@ static struct of_match fcu_of_match[] = static struct of_platform_driver fcu_of_platform_driver = { .name = "temperature", - .match_table = fcu_of_match, + .match_table = fcu_match, .probe = fcu_of_probe, .remove = fcu_of_remove }; diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 61400f04015..cbb72eb0426 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -43,6 +43,7 @@ #include #include #include +#include #define LOG_TEMP 0 /* continously log temperature */ @@ -450,7 +451,7 @@ do_probe( struct i2c_adapter *adapter, int addr, int kind ) /************************************************************************/ static int -therm_of_probe( struct of_device *dev, const struct of_match *match ) +therm_of_probe( struct of_device *dev, const struct of_device_id *match ) { return i2c_add_driver( &g4fan_driver ); } @@ -461,9 +462,8 @@ therm_of_remove( struct of_device *dev ) return i2c_del_driver( &g4fan_driver ); } -static struct of_match therm_of_match[] = {{ +static struct of_device_id therm_of_match[] = {{ .name = "fan", - .type = OF_ANY_MATCH, .compatible = "adm1030" }, {} }; diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 00e5257b176..8dc657fc8af 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -1261,7 +1261,7 @@ static void bmac_reset_and_enable(struct net_device *dev) spin_unlock_irqrestore(&bp->lock, flags); } -static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_match *match) +static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_id *match) { int j, rev, ret; struct bmac_data *bp; @@ -1645,16 +1645,13 @@ static int __devexit bmac_remove(struct macio_dev *mdev) return 0; } -static struct of_match bmac_match[] = +static struct of_device_id bmac_match[] = { { .name = "bmac", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH, .data = (void *)0, }, { - .name = OF_ANY_MATCH, .type = "network", .compatible = "bmac+", .data = (void *)1, diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 6ed2d7dbd44..81d0a26e4f4 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -109,7 +109,7 @@ bitrev(int b) } -static int __devinit mace_probe(struct macio_dev *mdev, const struct of_match *match) +static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match) { struct device_node *mace = macio_get_of_node(mdev); struct net_device *dev; @@ -1009,12 +1009,10 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static struct of_match mace_match[] = +static struct of_device_id mace_match[] = { { .name = "mace", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH }, {}, }; diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index b4f4bd7956a..9d496703c46 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c @@ -184,7 +184,7 @@ static int airport_hard_reset(struct orinoco_private *priv) } static int -airport_attach(struct macio_dev *mdev, const struct of_match *match) +airport_attach(struct macio_dev *mdev, const struct of_device_id *match) { struct orinoco_private *priv; struct net_device *dev; @@ -266,16 +266,16 @@ MODULE_AUTHOR("Benjamin Herrenschmidt "); MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); MODULE_LICENSE("Dual MPL/GPL"); -static struct of_match airport_match[] = +static struct of_device_id airport_match[] = { { .name = "radio", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH }, {}, }; +MODULE_DEVICE_TABLE (of, airport_match); + static struct macio_driver airport_driver = { .name = DRIVER_NAME, diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index edd47d1f0b1..932dcf0366e 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -424,7 +424,7 @@ static struct scsi_host_template mac53c94_template = { .use_clustering = DISABLE_CLUSTERING, }; -static int mac53c94_probe(struct macio_dev *mdev, const struct of_match *match) +static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *match) { struct device_node *node = macio_get_of_node(mdev); struct pci_dev *pdev = macio_get_pci_dev(mdev); @@ -544,15 +544,14 @@ static int mac53c94_remove(struct macio_dev *mdev) } -static struct of_match mac53c94_match[] = +static struct of_device_id mac53c94_match[] = { { .name = "53c94", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH }, {}, }; +MODULE_DEVICE_TABLE (of, mac53c94_match); static struct macio_driver mac53c94_driver = { diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index b05737ae5ef..ff1933298da 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1847,7 +1847,7 @@ static struct scsi_host_template mesh_template = { .use_clustering = DISABLE_CLUSTERING, }; -static int mesh_probe(struct macio_dev *mdev, const struct of_match *match) +static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match) { struct device_node *mesh = macio_get_of_node(mdev); struct pci_dev* pdev = macio_get_pci_dev(mdev); @@ -2012,20 +2012,18 @@ static int mesh_remove(struct macio_dev *mdev) } -static struct of_match mesh_match[] = +static struct of_device_id mesh_match[] = { { .name = "mesh", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH }, { - .name = OF_ANY_MATCH, .type = "scsi", .compatible = "chrp,mesh0" }, {}, }; +MODULE_DEVICE_TABLE (of, mesh_match); static struct macio_driver mesh_driver = { diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 1c9f7161712..7db2f37532c 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -1545,7 +1545,7 @@ static void pmz_dispose_port(struct uart_pmac_port *uap) /* * Called upon match with an escc node in the devive-tree. */ -static int pmz_attach(struct macio_dev *mdev, const struct of_match *match) +static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match) { int i; @@ -1850,20 +1850,17 @@ err_out: return rc; } -static struct of_match pmz_match[] = +static struct of_device_id pmz_match[] = { { .name = "ch-a", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH }, { .name = "ch-b", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH }, {}, }; +MODULE_DEVICE_TABLE (of, pmz_match); static struct macio_driver pmz_driver = { diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index 3dd1de1539d..b00887e9851 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -523,7 +523,7 @@ int __init platinumfb_setup(char *options) #define invalidate_cache(addr) #endif -static int __devinit platinumfb_probe(struct of_device* odev, const struct of_match *match) +static int __devinit platinumfb_probe(struct of_device* odev, const struct of_device_id *match) { struct device_node *dp = odev->node; struct fb_info *info; @@ -647,12 +647,10 @@ static int __devexit platinumfb_remove(struct of_device* odev) return 0; } -static struct of_match platinumfb_match[] = +static struct of_device_id platinumfb_match[] = { { .name = "platinum", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH, }, {}, }; -- cgit v1.2.3 From b5bf5b6786ccfc9e0c8801291f463d92c8e0b423 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Wed, 6 Jul 2005 15:26:27 -0400 Subject: [PATCH] openfirmware: add sysfs nodes for open firmware devices This adds sysfs nodes that the hotplug userspace can use to load the appropriate modules. In order for hotplug to work with macio devices, patches to module-init-tools and hotplug must be applied. Those patches are available at: ftp://ftp.suse.com/pub/people/jeffm/linux/macio-hotplug/ Changes: The previous versions were built on 2.6.12. 2.6.13-rcX introduced a device_attribute parameter to the show functions. Since that parameter was treated as the output buffer, memory corruption would result, causing Oopsen very quickly. Signed-off-by: Jeff Mahoney Signed-off-by: Linus Torvalds --- drivers/macintosh/Makefile | 2 +- drivers/macintosh/macio_asic.c | 3 +++ drivers/macintosh/macio_sysfs.c | 50 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 drivers/macintosh/macio_sysfs.c (limited to 'drivers') diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index f5ae171dbfe..236291bd48a 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -4,7 +4,7 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_PPC_PMAC) += macio_asic.o +obj-$(CONFIG_PPC_PMAC) += macio_asic.o macio_sysfs.o obj-$(CONFIG_PMAC_MEDIABAY) += mediabay.o obj-$(CONFIG_MAC_EMUMOUSEBTN) += mac_hid.o diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 37b18ee08a2..7fa369cfcce 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -126,11 +126,14 @@ static int macio_device_resume(struct device * dev) return 0; } +extern struct device_attribute macio_dev_attrs[]; + struct bus_type macio_bus_type = { .name = "macio", .match = macio_bus_match, .suspend = macio_device_suspend, .resume = macio_device_resume, + .dev_attrs = macio_dev_attrs, }; static int __init macio_bus_driver_init(void) diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c new file mode 100644 index 00000000000..97d22bb4516 --- /dev/null +++ b/drivers/macintosh/macio_sysfs.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include + + +#define macio_config_of_attr(field, format_string) \ +static ssize_t \ +field##_show (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct macio_dev *mdev = to_macio_device (dev); \ + return sprintf (buf, format_string, mdev->ofdev.node->field); \ +} + +static ssize_t +compatible_show (struct device *dev, struct device_attribute *attr, char *buf) +{ + struct of_device *of; + char *compat; + int cplen; + int length = 0; + + of = &to_macio_device (dev)->ofdev; + compat = (char *) get_property(of->node, "compatible", &cplen); + if (!compat) { + *buf = '\0'; + return 0; + } + while (cplen > 0) { + int l; + length += sprintf (buf, "%s\n", compat); + buf += length; + l = strlen (compat) + 1; + compat += l; + cplen -= l; + } + + return length; +} + +macio_config_of_attr (name, "%s\n"); +macio_config_of_attr (type, "%s\n"); + +struct device_attribute macio_dev_attrs[] = { + __ATTR_RO(name), + __ATTR_RO(type), + __ATTR_RO(compatible), + __ATTR_NULL +}; -- cgit v1.2.3 From 184f6eb8c46afc2a4aa6cb7c51ebc423c36d9c9d Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Wed, 6 Jul 2005 15:45:09 -0400 Subject: [PATCH] openfirmware: implement hotplug for macio devices This adds the hotplug routine for generating hotplug events when devices are seen on the macio bus. It uses the attributed created by the sysfs nodes to generate the hotplug environment vars for userspace. Since the characters allowed inside the 'compatible' field are NUL terminated, they are exported as individual OF_COMPATIBLE_# variables, with OF_COMPATIBLE_N maintaining a count of how many there are. In order for hotplug to work with macio devices, patches to module-init-tools and hotplug must be applied. Those patches are available at: ftp://ftp.suse.com/pub/people/jeffm/linux/macio-hotplug/ Signed-off-by: Jeff Mahoney Signed-off-by: Linus Torvalds --- drivers/macintosh/macio_asic.c | 71 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'drivers') diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 7fa369cfcce..1ee00334692 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -126,11 +126,82 @@ static int macio_device_resume(struct device * dev) return 0; } +static int macio_hotplug (struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct macio_dev * macio_dev; + struct of_device * of; + char *scratch, *compat; + int i = 0; + int length = 0; + int cplen, seen = 0; + + if (!dev) + return -ENODEV; + + macio_dev = to_macio_device(dev); + if (!macio_dev) + return -ENODEV; + + of = &macio_dev->ofdev; + scratch = buffer; + + /* stuff we want to pass to /sbin/hotplug */ + envp[i++] = scratch; + length += scnprintf (scratch, buffer_size - length, "OF_NAME=%s", + of->node->name); + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + ++length; + scratch += length; + + envp[i++] = scratch; + length += scnprintf (scratch, buffer_size - length, "OF_TYPE=%s", + of->node->type); + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + ++length; + scratch += length; + + /* Since the compatible field can contain pretty much anything + * it's not really legal to split it out with commas. We split it + * up using a number of environment variables instead. */ + + compat = (char *) get_property(of->node, "compatible", &cplen); + while (compat && cplen > 0) { + int l; + envp[i++] = scratch; + length += scnprintf (scratch, buffer_size - length, + "OF_COMPATIBLE_%d=%s", seen, compat); + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + length++; + scratch += length; + l = strlen (compat) + 1; + compat += l; + cplen -= l; + seen++; + } + + envp[i++] = scratch; + length += scnprintf (scratch, buffer_size - length, + "OF_COMPATIBLE_N=%d", seen); + if ((buffer_size - length <= 0) || (i >= num_envp)) + return -ENOMEM; + ++length; + scratch += length; + + envp[i] = NULL; + + return 0; +} + extern struct device_attribute macio_dev_attrs[]; struct bus_type macio_bus_type = { .name = "macio", .match = macio_bus_match, + .hotplug = macio_hotplug, .suspend = macio_device_suspend, .resume = macio_device_resume, .dev_attrs = macio_dev_attrs, -- cgit v1.2.3 From 07bbeaf12310263d808b1958f8413b95f98786ea Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 6 Jul 2005 13:05:50 -0700 Subject: ieee1394: fix broken signed char assumption. "ack_code" is assigned (and tested against) negative numbers, but was declared as "char". Which only works if "char" is signed - which it necessarily isn't. So make that signedness assumption specific. --- drivers/ieee1394/ieee1394_core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index 73bd8efd2b6..0b31429d0a6 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h @@ -38,8 +38,8 @@ struct hpsb_packet { /* These are core internal. */ signed char tlabel; - char ack_code; - char tcode; + signed char ack_code; + unsigned char tcode; unsigned expect_response:1; unsigned no_waiter:1; -- cgit v1.2.3 From fb8d82a865b1ff601fad8293cd6a2a1b1908545b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 6 Jul 2005 21:05:10 +0100 Subject: [MTD] NAND s3c2410: Add missing NULL pointer check Fix OOPs if there was no platform set information passed Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/s3c2410.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 630a9c0edf3..891e3a1b911 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -16,8 +16,9 @@ * 02-May-2005 BJD Fixed s3c2440 support * 02-May-2005 BJD Reduced hwcontrol decode * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug + * 08-Jul-2005 BJD Fix OOPS when no platform data supplied * - * $Id: s3c2410.c,v 1.13 2005/06/20 11:48:21 bjd Exp $ + * $Id: s3c2410.c,v 1.14 2005/07/06 20:05:06 bjd Exp $ * * 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 @@ -232,7 +233,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) if (chip == -1) { cur |= bit; } else { - if (chip > nmtd->set->nr_chips) { + if (nmtd->set != NULL && chip > nmtd->set->nr_chips) { printk(KERN_ERR PFX "chip %d out of range\n", chip); return; } -- cgit v1.2.3 From 6789b2dc455b90efc9c88886c9366adc9abb7347 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 6 Jul 2005 13:52:27 -0700 Subject: [PADLOCK] Move fast path work into aes_set_key and upper layer Most of the work done aes_padlock can be done in aes_set_key. This means that we only have to do it once when the key changes rather than every time we perform an encryption or decryption. This patch also sets cra_alignmask to let the upper layer ensure that the buffers fed to us are aligned correctly. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/crypto/padlock-aes.c | 102 +++++++++++++++++-------------------------- drivers/crypto/padlock.h | 22 +++++----- 2 files changed, 52 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index ed708b4427b..5f28909d401 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include "padlock.h" @@ -59,8 +60,12 @@ #define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t)) struct aes_ctx { - uint32_t e_data[AES_EXTENDED_KEY_SIZE+4]; - uint32_t d_data[AES_EXTENDED_KEY_SIZE+4]; + uint32_t e_data[AES_EXTENDED_KEY_SIZE]; + uint32_t d_data[AES_EXTENDED_KEY_SIZE]; + struct { + struct cword encrypt; + struct cword decrypt; + } cword; uint32_t *E; uint32_t *D; int key_length; @@ -280,10 +285,15 @@ aes_hw_extkey_available(uint8_t key_len) return 0; } +static inline struct aes_ctx *aes_ctx(void *ctx) +{ + return (struct aes_ctx *)ALIGN((unsigned long)ctx, PADLOCK_ALIGNMENT); +} + static int aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t *flags) { - struct aes_ctx *ctx = ctx_arg; + struct aes_ctx *ctx = aes_ctx(ctx_arg); uint32_t i, t, u, v, w; uint32_t P[AES_EXTENDED_KEY_SIZE]; uint32_t rounds; @@ -295,25 +305,36 @@ aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t ctx->key_length = key_len; + /* + * If the hardware is capable of generating the extended key + * itself we must supply the plain key for both encryption + * and decryption. + */ ctx->E = ctx->e_data; - ctx->D = ctx->d_data; - - /* Ensure 16-Bytes alignmentation of keys for VIA PadLock. */ - if ((int)(ctx->e_data) & 0x0F) - ctx->E += 4 - (((int)(ctx->e_data) & 0x0F) / sizeof (ctx->e_data[0])); - - if ((int)(ctx->d_data) & 0x0F) - ctx->D += 4 - (((int)(ctx->d_data) & 0x0F) / sizeof (ctx->d_data[0])); + ctx->D = ctx->e_data; E_KEY[0] = uint32_t_in (in_key); E_KEY[1] = uint32_t_in (in_key + 4); E_KEY[2] = uint32_t_in (in_key + 8); E_KEY[3] = uint32_t_in (in_key + 12); + /* Prepare control words. */ + memset(&ctx->cword, 0, sizeof(ctx->cword)); + + ctx->cword.decrypt.encdec = 1; + ctx->cword.encrypt.rounds = 10 + (key_len - 16) / 4; + ctx->cword.decrypt.rounds = ctx->cword.encrypt.rounds; + ctx->cword.encrypt.ksize = (key_len - 16) / 8; + ctx->cword.decrypt.ksize = ctx->cword.encrypt.ksize; + /* Don't generate extended keys if the hardware can do it. */ if (aes_hw_extkey_available(key_len)) return 0; + ctx->D = ctx->d_data; + ctx->cword.encrypt.keygen = 1; + ctx->cword.decrypt.keygen = 1; + switch (key_len) { case 16: t = E_KEY[3]; @@ -370,9 +391,8 @@ aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t /* ====== Encryption/decryption routines ====== */ /* This is the real call to PadLock. */ -static inline void -padlock_xcrypt_ecb(uint8_t *input, uint8_t *output, uint8_t *key, - void *control_word, uint32_t count) +static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, + void *control_word, u32 count) { asm volatile ("pushfl; popfl"); /* enforce key reload. */ asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ @@ -380,67 +400,27 @@ padlock_xcrypt_ecb(uint8_t *input, uint8_t *output, uint8_t *key, : "d"(control_word), "b"(key), "c"(count)); } -static void -aes_padlock(void *ctx_arg, uint8_t *out_arg, const uint8_t *in_arg, int encdec) -{ - /* Don't blindly modify this structure - the items must - fit on 16-Bytes boundaries! */ - struct padlock_xcrypt_data { - uint8_t buf[AES_BLOCK_SIZE]; - union cword cword; - }; - - struct aes_ctx *ctx = ctx_arg; - char bigbuf[sizeof(struct padlock_xcrypt_data) + 16]; - struct padlock_xcrypt_data *data; - void *key; - - /* Place 'data' at the first 16-Bytes aligned address in 'bigbuf'. */ - if (((long)bigbuf) & 0x0F) - data = (void*)(bigbuf + 16 - ((long)bigbuf & 0x0F)); - else - data = (void*)bigbuf; - - /* Prepare Control word. */ - memset (data, 0, sizeof(struct padlock_xcrypt_data)); - data->cword.b.encdec = !encdec; /* in the rest of cryptoapi ENC=1/DEC=0 */ - data->cword.b.rounds = 10 + (ctx->key_length - 16) / 4; - data->cword.b.ksize = (ctx->key_length - 16) / 8; - - /* Is the hardware capable to generate the extended key? */ - if (!aes_hw_extkey_available(ctx->key_length)) - data->cword.b.keygen = 1; - - /* ctx->E starts with a plain key - if the hardware is capable - to generate the extended key itself we must supply - the plain key for both Encryption and Decryption. */ - if (encdec == CRYPTO_DIR_ENCRYPT || data->cword.b.keygen == 0) - key = ctx->E; - else - key = ctx->D; - - memcpy(data->buf, in_arg, AES_BLOCK_SIZE); - padlock_xcrypt_ecb(data->buf, data->buf, key, &data->cword, 1); - memcpy(out_arg, data->buf, AES_BLOCK_SIZE); -} - static void aes_encrypt(void *ctx_arg, uint8_t *out, const uint8_t *in) { - aes_padlock(ctx_arg, out, in, CRYPTO_DIR_ENCRYPT); + struct aes_ctx *ctx = aes_ctx(ctx_arg); + padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, 1); } static void aes_decrypt(void *ctx_arg, uint8_t *out, const uint8_t *in) { - aes_padlock(ctx_arg, out, in, CRYPTO_DIR_DECRYPT); + struct aes_ctx *ctx = aes_ctx(ctx_arg); + padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, 1); } static struct crypto_alg aes_alg = { .cra_name = "aes", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aes_ctx), + .cra_ctxsize = sizeof(struct aes_ctx) + + PADLOCK_ALIGNMENT, + .cra_alignmask = PADLOCK_ALIGNMENT - 1, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), .cra_u = { diff --git a/drivers/crypto/padlock.h b/drivers/crypto/padlock.h index 7a500605e44..3cf2b7a1234 100644 --- a/drivers/crypto/padlock.h +++ b/drivers/crypto/padlock.h @@ -13,18 +13,18 @@ #ifndef _CRYPTO_PADLOCK_H #define _CRYPTO_PADLOCK_H +#define PADLOCK_ALIGNMENT 16 + /* Control word. */ -union cword { - uint32_t cword[4]; - struct { - int rounds:4; - int algo:3; - int keygen:1; - int interm:1; - int encdec:1; - int ksize:2; - } b; -}; +struct cword { + int __attribute__ ((__packed__)) + rounds:4, + algo:3, + keygen:1, + interm:1, + encdec:1, + ksize:2; +} __attribute__ ((__aligned__(PADLOCK_ALIGNMENT))); #define PFX "padlock: " -- cgit v1.2.3 From 28e8c3ad9464de54a632f00ab3df88fa5f4652d1 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 6 Jul 2005 13:52:43 -0700 Subject: [PADLOCK] Implement multi-block operations By operating on multiple blocks at once, we expect to extract more performance out of the VIA Padlock. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/crypto/padlock-aes.c | 55 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 5f28909d401..d2745ff4699 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -390,7 +390,7 @@ aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t /* ====== Encryption/decryption routines ====== */ -/* This is the real call to PadLock. */ +/* These are the real call to PadLock. */ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, void *control_word, u32 count) { @@ -400,6 +400,17 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, : "d"(control_word), "b"(key), "c"(count)); } +static inline void padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, + u8 *iv, void *control_word, u32 count) +{ + /* Enforce key reload. */ + asm volatile ("pushfl; popfl"); + /* rep xcryptcbc */ + asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" + : "+S" (input), "+D" (output), "+a" (iv) + : "d" (control_word), "b" (key), "c" (count)); +} + static void aes_encrypt(void *ctx_arg, uint8_t *out, const uint8_t *in) { @@ -414,6 +425,42 @@ aes_decrypt(void *ctx_arg, uint8_t *out, const uint8_t *in) padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, 1); } +static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out, + const u8 *in, unsigned int nbytes) +{ + struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm)); + padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, + nbytes / AES_BLOCK_SIZE); + return nbytes & ~(AES_BLOCK_SIZE - 1); +} + +static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out, + const u8 *in, unsigned int nbytes) +{ + struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm)); + padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, + nbytes / AES_BLOCK_SIZE); + return nbytes & ~(AES_BLOCK_SIZE - 1); +} + +static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out, + const u8 *in, unsigned int nbytes) +{ + struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm)); + padlock_xcrypt_cbc(in, out, ctx->E, desc->info, &ctx->cword.encrypt, + nbytes / AES_BLOCK_SIZE); + return nbytes & ~(AES_BLOCK_SIZE - 1); +} + +static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out, + const u8 *in, unsigned int nbytes) +{ + struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm)); + padlock_xcrypt_cbc(in, out, ctx->D, desc->info, &ctx->cword.decrypt, + nbytes / AES_BLOCK_SIZE); + return nbytes & ~(AES_BLOCK_SIZE - 1); +} + static struct crypto_alg aes_alg = { .cra_name = "aes", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, @@ -429,7 +476,11 @@ static struct crypto_alg aes_alg = { .cia_max_keysize = AES_MAX_KEY_SIZE, .cia_setkey = aes_set_key, .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt + .cia_decrypt = aes_decrypt, + .cia_encrypt_ecb = aes_encrypt_ecb, + .cia_decrypt_ecb = aes_decrypt_ecb, + .cia_encrypt_cbc = aes_encrypt_cbc, + .cia_decrypt_cbc = aes_decrypt_cbc, } } }; -- cgit v1.2.3 From fbdae9f3e7fb57c07cb0d973f113eb25da2e8ff2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 6 Jul 2005 13:53:29 -0700 Subject: [CRYPTO] Ensure cit_iv is aligned correctly This patch ensures that cit_iv is aligned according to cra_alignmask by allocating it as part of the tfm structure. As a side effect the crypto layer will also guarantee that the tfm ctx area has enough space to be aligned by cra_alignmask. This allows us to remove the extra space reservation from the Padlock driver. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/crypto/padlock-aes.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index d2745ff4699..c5b58fae95f 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -465,8 +465,7 @@ static struct crypto_alg aes_alg = { .cra_name = "aes", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aes_ctx) + - PADLOCK_ALIGNMENT, + .cra_ctxsize = sizeof(struct aes_ctx), .cra_alignmask = PADLOCK_ALIGNMENT - 1, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), -- cgit v1.2.3 From 476df259cd577e20379b02a7f7ffd086ea925a83 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 6 Jul 2005 13:54:09 -0700 Subject: [CRYPTO] Update IV correctly for Padlock CBC encryption When the Padlock does CBC encryption, the memory pointed to by EAX is not updated at all. Instead, it updates the value of EAX by pointing it to the last block in the output. Therefore to maintain the correct semantics we need to copy the IV. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/crypto/padlock-aes.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index c5b58fae95f..71407c578af 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -400,8 +400,8 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, : "d"(control_word), "b"(key), "c"(count)); } -static inline void padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, - u8 *iv, void *control_word, u32 count) +static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, + u8 *iv, void *control_word, u32 count) { /* Enforce key reload. */ asm volatile ("pushfl; popfl"); @@ -409,6 +409,7 @@ static inline void padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" : "+S" (input), "+D" (output), "+a" (iv) : "d" (control_word), "b" (key), "c" (count)); + return iv; } static void @@ -447,8 +448,12 @@ static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out, const u8 *in, unsigned int nbytes) { struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm)); - padlock_xcrypt_cbc(in, out, ctx->E, desc->info, &ctx->cword.encrypt, - nbytes / AES_BLOCK_SIZE); + u8 *iv; + + iv = padlock_xcrypt_cbc(in, out, ctx->E, desc->info, + &ctx->cword.encrypt, nbytes / AES_BLOCK_SIZE); + memcpy(desc->info, iv, AES_BLOCK_SIZE); + return nbytes & ~(AES_BLOCK_SIZE - 1); } -- cgit v1.2.3 From e07d01e0aeba905aeca6e0ae612943417d396a0f Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Wed, 6 Jul 2005 15:28:40 -0700 Subject: [IA64] hotplug/ia64: SN Hotplug Driver - pci_find_next_bus export The pci_find_next_bus function is listed as being exported to drivers. It is not EXPORT_SYMBOL'd. Signed-off-by: Prarit Bhargava Signed-off-by: Tony Luck --- drivers/pci/search.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pci/search.c b/drivers/pci/search.c index a90a533eba0..05fa91a31c6 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -379,6 +379,7 @@ exit: EXPORT_SYMBOL(pci_dev_present); EXPORT_SYMBOL(pci_find_bus); +EXPORT_SYMBOL(pci_find_next_bus); EXPORT_SYMBOL(pci_find_device); EXPORT_SYMBOL(pci_find_device_reverse); EXPORT_SYMBOL(pci_find_slot); -- cgit v1.2.3 From 6f354b014b51716166f13f68b29212d3c44ed2c4 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Wed, 6 Jul 2005 15:29:53 -0700 Subject: [IA64] hotplug/ia64: SN Hotplug Driver - SN Hotplug Driver code This patch is the SGI hotplug driver and additional changes required for the driver. These modifications include changes to the SN io_init.c code for memory management, the inclusion of new SAL calls to enable and disable PCI slots, and a hotplug-style driver. Signed-off-by: Prarit Bhargava Signed-off-by: Tony Luck --- drivers/pci/hotplug/Kconfig | 5 +- drivers/pci/hotplug/Makefile | 1 + drivers/pci/hotplug/sgi_hotplug.c | 611 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 615 insertions(+), 2 deletions(-) create mode 100644 drivers/pci/hotplug/sgi_hotplug.c (limited to 'drivers') diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 1a4d4ca2a4d..9c4a39ee89b 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -187,9 +187,10 @@ config HOTPLUG_PCI_RPA_DLPAR config HOTPLUG_PCI_SGI tristate "SGI PCI Hotplug Support" - depends on HOTPLUG_PCI && IA64_SGI_SN2 + depends on HOTPLUG_PCI && (IA64_SGI_SN2 || IA64_GENERIC) help - Say Y here if you have an SGI IA64 Altix system. + Say Y here if you want to use the SGI Altix Hotplug + Driver for PCI devices. When in doubt, say N. diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 3e632ff8c71..31a307004b9 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o obj-$(CONFIG_HOTPLUG_PCI_SHPC) += shpchp.o obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o +obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o pci_hotplug-objs := pci_hotplug_core.o diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c new file mode 100644 index 00000000000..323041fd41d --- /dev/null +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -0,0 +1,611 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2005 Silicon Graphics, Inc. All rights reserved. + * + * This work was based on the 2.4/2.6 kernel development by Dick Reigner. + * Work to add BIOS PROM support was completed by Mike Habeck. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../pci.h" +#include "pci_hotplug.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); +MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver"); + +#define PCIIO_ASIC_TYPE_TIOCA 4 +#define PCI_SLOT_ALREADY_UP 2 /* slot already up */ +#define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */ +#define PCI_L1_ERR 7 /* L1 console command error */ +#define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */ +#define PCI_L1_QSIZE 128 /* our L1 message buffer size */ +#define SN_MAX_HP_SLOTS 32 /* max number of hotplug slots */ +#define SGI_HOTPLUG_PROM_REV 0x0420 /* Min. required PROM version */ + +/* internal list head */ +static struct list_head sn_hp_list; + +/* hotplug_slot struct's private pointer */ +struct slot { + int device_num; + struct pci_bus *pci_bus; + /* this struct for glue internal only */ + struct hotplug_slot *hotplug_slot; + struct list_head hp_list; +}; + +struct pcibr_slot_enable_resp { + int resp_sub_errno; + char resp_l1_msg[PCI_L1_QSIZE + 1]; +}; + +struct pcibr_slot_disable_resp { + int resp_sub_errno; + char resp_l1_msg[PCI_L1_QSIZE + 1]; +}; + +enum sn_pci_req_e { + PCI_REQ_SLOT_ELIGIBLE, + PCI_REQ_SLOT_DISABLE +}; + +static int enable_slot(struct hotplug_slot *slot); +static int disable_slot(struct hotplug_slot *slot); +static int get_power_status(struct hotplug_slot *slot, u8 *value); + +static struct hotplug_slot_ops sn_hotplug_slot_ops = { + .owner = THIS_MODULE, + .enable_slot = enable_slot, + .disable_slot = disable_slot, + .get_power_status = get_power_status, +}; + +static DECLARE_MUTEX(sn_hotplug_sem); + +static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) +{ + struct pcibus_info *pcibus_info; + int bricktype; + int bus_num; + + pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); + + /* Check to see if this is a valid slot on 'pci_bus' */ + if (!(pcibus_info->pbi_valid_devices & (1 << device))) + return -EPERM; + + bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); + bus_num = pcibus_info->pbi_buscommon.bs_persist_busnum & 0xf; + + /* Do not allow hotplug operations on base I/O cards */ + if ((bricktype == L1_BRICKTYPE_IX || bricktype == L1_BRICKTYPE_IA) && + (bus_num == 1 && device != 1)) + return -EPERM; + + return 1; +} + +static int sn_pci_bus_valid(struct pci_bus *pci_bus) +{ + struct pcibus_info *pcibus_info; + int asic_type; + int bricktype; + + pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); + + /* Don't register slots hanging off the TIOCA bus */ + asic_type = pcibus_info->pbi_buscommon.bs_asic_type; + if (asic_type == PCIIO_ASIC_TYPE_TIOCA) + return -EPERM; + + /* Only register slots in I/O Bricks that support hotplug */ + bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); + switch (bricktype) { + case L1_BRICKTYPE_IX: + case L1_BRICKTYPE_PX: + case L1_BRICKTYPE_IA: + case L1_BRICKTYPE_PA: + return 1; + break; + default: + return -EPERM; + break; + } + + return -EIO; +} + +static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, + struct pci_bus *pci_bus, int device) +{ + struct pcibus_info *pcibus_info; + struct slot *slot; + + pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); + + bss_hotplug_slot->private = kcalloc(1, sizeof(struct slot), + GFP_KERNEL); + if (!bss_hotplug_slot->private) + return -ENOMEM; + slot = (struct slot *)bss_hotplug_slot->private; + + bss_hotplug_slot->name = kmalloc(33, GFP_KERNEL); + if (!bss_hotplug_slot->name) { + kfree(bss_hotplug_slot->private); + return -ENOMEM; + } + + slot->device_num = device; + slot->pci_bus = pci_bus; + + sprintf(bss_hotplug_slot->name, "module_%c%c%c%c%.2d_b_%d_s_%d", + '0'+RACK_GET_CLASS(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), + '0'+RACK_GET_GROUP(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), + '0'+RACK_GET_NUM(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), + MODULE_GET_BTCHAR(pcibus_info->pbi_moduleid), + MODULE_GET_BPOS(pcibus_info->pbi_moduleid), + ((int)pcibus_info->pbi_buscommon.bs_persist_busnum) & 0xf, + device + 1); + + slot->hotplug_slot = bss_hotplug_slot; + list_add(&slot->hp_list, &sn_hp_list); + + return 0; +} + +static struct hotplug_slot * sn_hp_destroy(void) +{ + struct slot *slot; + struct list_head *list; + struct hotplug_slot *bss_hotplug_slot = NULL; + + list_for_each(list, &sn_hp_list) { + slot = list_entry(list, struct slot, hp_list); + bss_hotplug_slot = slot->hotplug_slot; + list_del(&((struct slot *)bss_hotplug_slot->private)-> + hp_list); + break; + } + return bss_hotplug_slot; +} + +static void sn_bus_alloc_data(struct pci_dev *dev) +{ + struct list_head *node; + struct pci_bus *subordinate_bus; + struct pci_dev *child; + + sn_pci_fixup_slot(dev); + + /* Recursively sets up the sn_irq_info structs */ + if (dev->subordinate) { + subordinate_bus = dev->subordinate; + list_for_each(node, &subordinate_bus->devices) { + child = list_entry(node, struct pci_dev, bus_list); + sn_bus_alloc_data(child); + } + } +} + +static void sn_bus_free_data(struct pci_dev *dev) +{ + struct list_head *node; + struct pci_bus *subordinate_bus; + struct pci_dev *child; + + /* Recursively clean up sn_irq_info structs */ + if (dev->subordinate) { + subordinate_bus = dev->subordinate; + list_for_each(node, &subordinate_bus->devices) { + child = list_entry(node, struct pci_dev, bus_list); + sn_bus_free_data(child); + } + } + sn_pci_unfixup_slot(dev); +} + +static u8 sn_power_status_get(struct hotplug_slot *bss_hotplug_slot) +{ + struct slot *slot = (struct slot *)bss_hotplug_slot->private; + struct pcibus_info *pcibus_info; + u8 retval; + + pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); + retval = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); + + return retval ? 1 : 0; +} + +static void sn_slot_mark_enable(struct hotplug_slot *bss_hotplug_slot, + int device_num) +{ + struct slot *slot = (struct slot *)bss_hotplug_slot->private; + struct pcibus_info *pcibus_info; + + pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); + pcibus_info->pbi_enabled_devices |= (1 << device_num); +} + +static void sn_slot_mark_disable(struct hotplug_slot *bss_hotplug_slot, + int device_num) +{ + struct slot *slot = (struct slot *)bss_hotplug_slot->private; + struct pcibus_info *pcibus_info; + + pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); + pcibus_info->pbi_enabled_devices &= ~(1 << device_num); +} + +static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, + int device_num) +{ + struct slot *slot = (struct slot *)bss_hotplug_slot->private; + struct pcibus_info *pcibus_info; + struct pcibr_slot_enable_resp resp; + int rc; + + pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); + + /* + * Power-on and initialize the slot in the SN + * PCI infrastructure. + */ + rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp); + + if (rc == PCI_SLOT_ALREADY_UP) { + dev_dbg(slot->pci_bus->self, "is already active\n"); + return -EPERM; + } + + if (rc == PCI_L1_ERR) { + dev_dbg(slot->pci_bus->self, + "L1 failure %d with message: %s", + resp.resp_sub_errno, resp.resp_l1_msg); + return -EPERM; + } + + if (rc) { + dev_dbg(slot->pci_bus->self, + "insert failed with error %d sub-error %d\n", + rc, resp.resp_sub_errno); + return -EIO; + } + + sn_slot_mark_enable(bss_hotplug_slot, device_num); + + return 0; +} + +static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, + int device_num, int action) +{ + struct slot *slot = (struct slot *)bss_hotplug_slot->private; + struct pcibus_info *pcibus_info; + struct pcibr_slot_disable_resp resp; + int rc; + + pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); + + rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp); + + if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_SLOT_ALREADY_DOWN) { + dev_dbg(slot->pci_bus->self, "Slot %s already inactive\n"); + return -ENODEV; + } + + if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_EMPTY_33MHZ) { + dev_dbg(slot->pci_bus->self, + "Cannot remove last 33MHz card\n"); + return -EPERM; + } + + if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_L1_ERR) { + dev_dbg(slot->pci_bus->self, + "L1 failure %d with message \n%s\n", + resp.resp_sub_errno, resp.resp_l1_msg); + return -EPERM; + } + + if (action == PCI_REQ_SLOT_ELIGIBLE && rc) { + dev_dbg(slot->pci_bus->self, + "remove failed with error %d sub-error %d\n", + rc, resp.resp_sub_errno); + return -EIO; + } + + if (action == PCI_REQ_SLOT_ELIGIBLE && !rc) + return 0; + + if (action == PCI_REQ_SLOT_DISABLE && !rc) { + sn_slot_mark_disable(bss_hotplug_slot, device_num); + dev_dbg(slot->pci_bus->self, "remove successful\n"); + return 0; + } + + if (action == PCI_REQ_SLOT_DISABLE && rc) { + dev_dbg(slot->pci_bus->self,"remove failed rc = %d\n", rc); + return rc; + } + + return rc; +} + +static int enable_slot(struct hotplug_slot *bss_hotplug_slot) +{ + struct slot *slot = (struct slot *)bss_hotplug_slot->private; + struct pci_bus *new_bus = NULL; + struct pci_dev *dev; + int func, num_funcs; + int new_ppb = 0; + int rc; + + /* Serialize the Linux PCI infrastructure */ + down(&sn_hotplug_sem); + + /* + * Power-on and initialize the slot in the SN + * PCI infrastructure. + */ + rc = sn_slot_enable(bss_hotplug_slot, slot->device_num); + if (rc) { + up(&sn_hotplug_sem); + return rc; + } + + num_funcs = pci_scan_slot(slot->pci_bus, PCI_DEVFN(slot->device_num+1, + PCI_FUNC(0))); + if (!num_funcs) { + dev_dbg(slot->pci_bus->self, "no device in slot\n"); + up(&sn_hotplug_sem); + return -ENODEV; + } + + sn_pci_controller_fixup(pci_domain_nr(slot->pci_bus), + slot->pci_bus->number, + slot->pci_bus); + /* + * Map SN resources for all functions on the card + * to the Linux PCI interface and tell the drivers + * about them. + */ + for (func = 0; func < num_funcs; func++) { + dev = pci_get_slot(slot->pci_bus, + PCI_DEVFN(slot->device_num + 1, + PCI_FUNC(func))); + + + if (dev) { + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + unsigned char sec_bus; + pci_read_config_byte(dev, PCI_SECONDARY_BUS, + &sec_bus); + new_bus = pci_add_new_bus(dev->bus, dev, + sec_bus); + pci_scan_child_bus(new_bus); + sn_pci_controller_fixup(pci_domain_nr(new_bus), + new_bus->number, + new_bus); + new_ppb = 1; + } + sn_bus_alloc_data(dev); + pci_dev_put(dev); + } + } + + /* Call the driver for the new device */ + pci_bus_add_devices(slot->pci_bus); + /* Call the drivers for the new devices subordinate to PPB */ + if (new_ppb) + pci_bus_add_devices(new_bus); + + up(&sn_hotplug_sem); + + if (rc == 0) + dev_dbg(slot->pci_bus->self, + "insert operation successful\n"); + else + dev_dbg(slot->pci_bus->self, + "insert operation failed rc = %d\n", rc); + + return rc; +} + +static int disable_slot(struct hotplug_slot *bss_hotplug_slot) +{ + struct slot *slot = (struct slot *)bss_hotplug_slot->private; + struct pci_dev *dev; + int func; + int rc; + + /* Acquire update access to the bus */ + down(&sn_hotplug_sem); + + /* is it okay to bring this slot down? */ + rc = sn_slot_disable(bss_hotplug_slot, slot->device_num, + PCI_REQ_SLOT_ELIGIBLE); + if (rc) + goto leaving; + + /* Free the SN resources assigned to the Linux device.*/ + for (func = 0; func < 8; func++) { + dev = pci_get_slot(slot->pci_bus, + PCI_DEVFN(slot->device_num+1, + PCI_FUNC(func))); + if (dev) { + /* + * Some drivers may use dma accesses during the + * driver remove function. We release the sysdata + * areas after the driver remove functions have + * been called. + */ + sn_bus_store_sysdata(dev); + sn_bus_free_data(dev); + pci_remove_bus_device(dev); + pci_dev_put(dev); + } + } + + /* free the collected sysdata pointers */ + sn_bus_free_sysdata(); + + /* Deactivate slot */ + rc = sn_slot_disable(bss_hotplug_slot, slot->device_num, + PCI_REQ_SLOT_DISABLE); + leaving: + /* Release the bus lock */ + up(&sn_hotplug_sem); + + return rc; +} + +static int get_power_status(struct hotplug_slot *bss_hotplug_slot, u8 *value) +{ + down(&sn_hotplug_sem); + *value = sn_power_status_get(bss_hotplug_slot); + up(&sn_hotplug_sem); + return 0; +} + +static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) +{ + kfree(bss_hotplug_slot->info); + kfree(bss_hotplug_slot->name); + kfree(bss_hotplug_slot->private); + kfree(bss_hotplug_slot); +} + +static int sn_hotplug_slot_register(struct pci_bus *pci_bus) +{ + int device; + struct hotplug_slot *bss_hotplug_slot; + int rc = 0; + + /* + * Currently only four devices are supported, + * in the future there maybe more -- up to 32. + */ + + for (device = 0; device < SN_MAX_HP_SLOTS ; device++) { + if (sn_pci_slot_valid(pci_bus, device) != 1) + continue; + + bss_hotplug_slot = kcalloc(1,sizeof(struct hotplug_slot), + GFP_KERNEL); + if (!bss_hotplug_slot) { + rc = -ENOMEM; + goto alloc_err; + } + + bss_hotplug_slot->info = + kcalloc(1,sizeof(struct hotplug_slot_info), + GFP_KERNEL); + if (!bss_hotplug_slot->info) { + rc = -ENOMEM; + goto alloc_err; + } + + if (sn_hp_slot_private_alloc(bss_hotplug_slot, + pci_bus, device)) { + rc = -ENOMEM; + goto alloc_err; + } + + bss_hotplug_slot->ops = &sn_hotplug_slot_ops; + bss_hotplug_slot->release = &sn_release_slot; + + rc = pci_hp_register(bss_hotplug_slot); + if (rc) + goto register_err; + } + dev_dbg(pci_bus->self, "Registered bus with hotplug\n"); + return rc; + +register_err: + dev_dbg(pci_bus->self, "bus failed to register with err = %d\n", + rc); + +alloc_err: + if (rc == -ENOMEM) + dev_dbg(pci_bus->self, "Memory allocation error\n"); + + /* destroy THIS element */ + if (bss_hotplug_slot) + sn_release_slot(bss_hotplug_slot); + + /* destroy anything else on the list */ + while ((bss_hotplug_slot = sn_hp_destroy())) + pci_hp_deregister(bss_hotplug_slot); + + return rc; +} + +static int sn_pci_hotplug_init(void) +{ + struct pci_bus *pci_bus = NULL; + int rc; + int registered = 0; + + INIT_LIST_HEAD(&sn_hp_list); + + if (sn_sal_rev() < SGI_HOTPLUG_PROM_REV) { + printk(KERN_ERR "%s: PROM version must be greater than 4.05\n", + __FUNCTION__); + return -EPERM; + } + + while ((pci_bus = pci_find_next_bus(pci_bus))) { + if (!pci_bus->sysdata) + continue; + + rc = sn_pci_bus_valid(pci_bus); + if (rc != 1) { + dev_dbg(pci_bus->self, "not a valid hotplug bus\n"); + continue; + } + dev_dbg(pci_bus->self, "valid hotplug bus\n"); + + rc = sn_hotplug_slot_register(pci_bus); + if (!rc) + registered = 1; + else { + registered = 0; + break; + } + } + + return registered == 1 ? 0 : -ENODEV; +} + +static void sn_pci_hotplug_exit(void) +{ + struct hotplug_slot *bss_hotplug_slot; + + while ((bss_hotplug_slot = sn_hp_destroy())) { + pci_hp_deregister(bss_hotplug_slot); + } + + if (!list_empty(&sn_hp_list)) + printk(KERN_ERR "%s: internal list is not empty\n", __FILE__); +} + +module_init(sn_pci_hotplug_init); +module_exit(sn_pci_hotplug_exit); -- cgit v1.2.3 From 9d7495330be2fd88ab939fa5080d3ca9f64368c2 Mon Sep 17 00:00:00 2001 From: "Eddie C. Dost" Date: Wed, 6 Jul 2005 15:41:17 -0700 Subject: [DVB]: Do not include from drivers. Signed-off-by: David S. Miller --- drivers/media/dvb/frontends/tda80xx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c index 032d348dafb..88e125079ca 100644 --- a/drivers/media/dvb/frontends/tda80xx.c +++ b/drivers/media/dvb/frontends/tda80xx.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 960b8466548c9bc6f718b5f470c1a58000fab09d Mon Sep 17 00:00:00 2001 From: Ivan Kokshaysky Date: Thu, 7 Jul 2005 03:07:56 +0400 Subject: [PATCH] yet another fix for setup-bus.c/x86 merge There is a slight disagreement between setup-bus.c code and traditional x86 PCI setup wrt which recourses are invalid vs resources that are free for further allocations. In particular, in the setup-bus.c, if we failed to allocate some resource, we nullify "start" and "flags" fields, but *not* the "end" one. But x86 pcibios_enable_resources() does the following check: if (!r->start && r->end) { printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev)); return -EINVAL; which means that the device owning the offending resource cannot be enabled. In particular, this breaks cardbus behind the normal decode p2p bridge - the cardbus code from setup-bus.c requests rather large IO and MEM windows, and if it fails, the socket is completely unavailable. Which is wrong, as the yenta code is capable to allocate smaller windows. Signed-off-by: Ivan Kokshaysky Signed-off-by: Linus Torvalds --- drivers/pci/setup-bus.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index c1bdfb42465..9fe48f712be 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -74,6 +74,7 @@ pbus_assign_resources_sorted(struct pci_bus *bus) idx = res - &list->dev->resource[0]; if (pci_assign_resource(list->dev, idx)) { res->start = 0; + res->end = 0; res->flags = 0; } tmp = list; -- cgit v1.2.3 From 0c7b525c344bc29a760c37053f8d5c80292ee1be Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 7 Jul 2005 20:16:08 +1000 Subject: drm: fix minor issues caused by core conversion The conversion to core/driver got this check in-correct. Signed-off-by: Dave Airlie --- drivers/char/drm/drm_fops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index 906794247ae..7f9b00c6d24 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -251,7 +251,7 @@ int drm_release( struct inode *inode, struct file *filp ) } } - if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && !dev->driver->release) { dev->driver->reclaim_buffers(dev, filp); } -- cgit v1.2.3 From f650130803c4c0b5e5d76eff24faae722e3a69e2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 7 Jul 2005 20:17:42 +1000 Subject: drm: ctx release can happen before dev->ctxlist is allocated From: Jon Smirl Signed-off-by: Dave Airlie --- drivers/char/drm/drm_fops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index 7f9b00c6d24..a53322d8c22 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -259,7 +259,7 @@ int drm_release( struct inode *inode, struct file *filp ) drm_fasync( -1, filp, 0 ); down( &dev->ctxlist_sem ); - if ( !list_empty( &dev->ctxlist->head ) ) { + if ( dev->ctxlist && (!list_empty(&dev->ctxlist->head))) { drm_ctx_list_t *pos, *n; list_for_each_entry_safe( pos, n, &dev->ctxlist->head, head ) { -- cgit v1.2.3 From b9523249de59c49e7c2cc83dfa73fb011a489a45 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 7 Jul 2005 20:33:26 +1000 Subject: drm: use kcalloc now that it is available.. Make the DRM drm_calloc call kcalloc now. Signed-off-by: Dave Airlie --- drivers/char/drm/drmP.h | 8 +++++++- drivers/char/drm/drm_memory.c | 13 ------------- 2 files changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index b04ddf12a0f..2c7b1fc3bb2 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -806,7 +806,6 @@ extern ssize_t drm_read(struct file *filp, char __user *buf, size_t count, extern void drm_mem_init(void); extern int drm_mem_info(char *buf, char **start, off_t offset, int request, int *eof, void *data); -extern void *drm_calloc(size_t nmemb, size_t size, int area); extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area); extern unsigned long drm_alloc_pages(int order, int area); @@ -1064,9 +1063,16 @@ static __inline__ void drm_free(void *pt, size_t size, int area) { kfree(pt); } + +/** Wrapper around kcalloc() */ +static __inline__ void *drm_calloc(size_t nmemb, size_t size, int area) +{ + return kcalloc(nmemb, size, GFP_KERNEL); +} #else extern void *drm_alloc(size_t size, int area); extern void drm_free(void *pt, size_t size, int area); +extern void *drm_calloc(size_t nmemb, size_t size, int area); #endif /*@}*/ diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c index 7f53f756c05..ace3d42f440 100644 --- a/drivers/char/drm/drm_memory.c +++ b/drivers/char/drm/drm_memory.c @@ -65,19 +65,6 @@ int drm_mem_info(char *buf, char **start, off_t offset, return 0; } -/** Wrapper around kmalloc() */ -void *drm_calloc(size_t nmemb, size_t size, int area) -{ - void *addr; - - addr = kmalloc(size * nmemb, GFP_KERNEL); - if (addr != NULL) - memset((void *)addr, 0, size * nmemb); - - return addr; -} -EXPORT_SYMBOL(drm_calloc); - /** Wrapper around kmalloc() and kfree() */ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area) { -- cgit v1.2.3 From c94f70298529d99ac6e1ee7709f61eab00adeb39 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 7 Jul 2005 21:03:38 +1000 Subject: drm: misc cleanup This patch contains the following cleanups: - make needlessly global functions static - remove the following unused global functions: - drm_fops.c: drm_read - i915_dma.c: i915_do_cleanup_pageflip Signed-off-by: Adrian Bunk Signed-off-by: Dave Airlie --- drivers/char/drm/ati_pcigart.c | 2 +- drivers/char/drm/drmP.h | 22 ---------- drivers/char/drm/drm_auth.c | 4 +- drivers/char/drm/drm_bufs.c | 12 +++--- drivers/char/drm/drm_context.c | 4 +- drivers/char/drm/drm_drv.c | 9 +++-- drivers/char/drm/drm_fops.c | 10 ++--- drivers/char/drm/drm_irq.c | 2 +- drivers/char/drm/drm_lock.c | 12 ++++-- drivers/char/drm/drm_proc.c | 2 +- drivers/char/drm/drm_stub.c | 92 +++++++++++++++++++++--------------------- drivers/char/drm/drm_vm.c | 10 +++-- drivers/char/drm/i810_dma.c | 24 +++++------ drivers/char/drm/i810_drv.h | 1 - drivers/char/drm/i830_dma.c | 20 ++++----- drivers/char/drm/i830_drv.c | 2 +- drivers/char/drm/i830_drv.h | 2 - drivers/char/drm/i830_irq.c | 5 +-- drivers/char/drm/i915_dma.c | 60 +++++++++++---------------- drivers/char/drm/i915_drv.c | 2 +- drivers/char/drm/i915_drv.h | 10 ----- drivers/char/drm/i915_irq.c | 4 +- drivers/char/drm/r128_state.c | 2 +- 23 files changed, 135 insertions(+), 178 deletions(-) (limited to 'drivers') diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c index fdca1876ecd..0aec5ef481b 100644 --- a/drivers/char/drm/ati_pcigart.c +++ b/drivers/char/drm/ati_pcigart.c @@ -52,7 +52,7 @@ # define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */ # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ -unsigned long drm_ati_alloc_pcigart_table( void ) +static unsigned long drm_ati_alloc_pcigart_table( void ) { unsigned long address; struct page *page; diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 2c7b1fc3bb2..5df09cc8c6d 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -774,8 +774,6 @@ extern int drm_cpu_valid( void ); /* Driver support (drm_drv.h) */ extern int drm_init(struct drm_driver *driver); extern void drm_exit(struct drm_driver *driver); -extern int drm_version(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); extern int drm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern long drm_compat_ioctl(struct file *filp, @@ -785,21 +783,13 @@ extern int drm_takedown(drm_device_t * dev); /* Device support (drm_fops.h) */ extern int drm_open(struct inode *inode, struct file *filp); extern int drm_stub_open(struct inode *inode, struct file *filp); -extern int drm_open_helper(struct inode *inode, struct file *filp, - drm_device_t *dev); extern int drm_flush(struct file *filp); extern int drm_fasync(int fd, struct file *filp, int on); extern int drm_release(struct inode *inode, struct file *filp); /* Mapping support (drm_vm.h) */ -extern void drm_vm_open(struct vm_area_struct *vma); -extern void drm_vm_close(struct vm_area_struct *vma); -extern void drm_vm_shm_close(struct vm_area_struct *vma); -extern int drm_mmap_dma(struct file *filp, - struct vm_area_struct *vma); extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); -extern ssize_t drm_read(struct file *filp, char __user *buf, size_t count, loff_t *off); /* Memory management support (drm_memory.h) */ #include "drm_memory.h" @@ -853,9 +843,6 @@ extern int drm_newctx( struct inode *inode, struct file *filp, extern int drm_rmctx( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); -extern int drm_context_switch(drm_device_t *dev, int old, int new); -extern int drm_context_switch_complete(drm_device_t *dev, int new); - extern int drm_ctxbitmap_init( drm_device_t *dev ); extern void drm_ctxbitmap_cleanup( drm_device_t *dev ); extern void drm_ctxbitmap_free( drm_device_t *dev, int ctx_handle ); @@ -873,9 +860,6 @@ extern int drm_rmdraw(struct inode *inode, struct file *filp, /* Authentication IOCTL support (drm_auth.h) */ -extern int drm_add_magic(drm_device_t *dev, drm_file_t *priv, - drm_magic_t magic); -extern int drm_remove_magic(drm_device_t *dev, drm_magic_t magic); extern int drm_getmagic(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_authmagic(struct inode *inode, struct file *filp, @@ -892,13 +876,9 @@ extern int drm_unlock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context); -extern int drm_lock_transfer(drm_device_t *dev, - __volatile__ unsigned int *lock, - unsigned int context); extern int drm_lock_free(drm_device_t *dev, __volatile__ unsigned int *lock, unsigned int context); -extern int drm_notifier(void *priv); /* Buffer management support (drm_bufs.h) */ extern int drm_order( unsigned long size ); @@ -926,7 +906,6 @@ extern void drm_core_reclaim_buffers(drm_device_t *dev, struct file *filp); /* IRQ support (drm_irq.h) */ extern int drm_control( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); -extern int drm_irq_install( drm_device_t *dev ); extern int drm_irq_uninstall( drm_device_t *dev ); extern irqreturn_t drm_irq_handler( DRM_IRQ_ARGS ); extern void drm_driver_irq_preinstall( drm_device_t *dev ); @@ -966,7 +945,6 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM *handle); extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); extern int drm_put_dev(drm_device_t * dev); -extern int drm_get_head(drm_device_t * dev, drm_head_t *head); extern int drm_put_head(drm_head_t * head); extern unsigned int drm_debug; extern unsigned int drm_cards_limit; diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c index b428761c4e9..dd140bca8f7 100644 --- a/drivers/char/drm/drm_auth.c +++ b/drivers/char/drm/drm_auth.c @@ -87,7 +87,7 @@ static drm_file_t *drm_find_file(drm_device_t *dev, drm_magic_t magic) * associated the magic number hash key in drm_device::magiclist, while holding * the drm_device::struct_sem lock. */ -int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic) +static int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic) { int hash; drm_magic_entry_t *entry; @@ -124,7 +124,7 @@ int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic) * Searches and unlinks the entry in drm_device::magiclist with the magic * number hash key, while holding the drm_device::struct_sem lock. */ -int drm_remove_magic(drm_device_t *dev, drm_magic_t magic) +static int drm_remove_magic(drm_device_t *dev, drm_magic_t magic) { drm_magic_entry_t *prev = NULL; drm_magic_entry_t *pt; diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 3407380b865..4c6191d231b 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -356,8 +356,8 @@ static void drm_cleanup_buf_error(drm_device_t *dev, drm_buf_entry_t *entry) * reallocates the buffer list of the same size order to accommodate the new * buffers. */ -int drm_addbufs_agp( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +static int drm_addbufs_agp( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; @@ -521,8 +521,8 @@ int drm_addbufs_agp( struct inode *inode, struct file *filp, } #endif /* __OS_HAS_AGP */ -int drm_addbufs_pci( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +static int drm_addbufs_pci( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; @@ -751,8 +751,8 @@ int drm_addbufs_pci( struct inode *inode, struct file *filp, } -int drm_addbufs_sg( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +static int drm_addbufs_sg( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c index fdf661f234e..a7cfabd1ca2 100644 --- a/drivers/char/drm/drm_context.c +++ b/drivers/char/drm/drm_context.c @@ -84,7 +84,7 @@ failed: * drm_device::context_sareas to accommodate the new entry while holding the * drm_device::struct_sem lock. */ -int drm_ctxbitmap_next( drm_device_t *dev ) +static int drm_ctxbitmap_next( drm_device_t *dev ) { int bit; @@ -326,7 +326,7 @@ int drm_context_switch( drm_device_t *dev, int old, int new ) * hardware lock is held, clears the drm_device::context_flag and wakes up * drm_device::context_wait. */ -int drm_context_switch_complete( drm_device_t *dev, int new ) +static int drm_context_switch_complete( drm_device_t *dev, int new ) { dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ dev->last_switch = jiffies; diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index 1e37ed0c6b8..3333c250c4d 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -51,8 +51,11 @@ #include "drmP.h" #include "drm_core.h" +static int drm_version(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + /** Ioctl table */ -drm_ioctl_desc_t drm_ioctls[] = { +static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { drm_version, 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 }, @@ -447,8 +450,8 @@ module_exit( drm_core_exit ); * * Fills in the version information in \p arg. */ -int drm_version( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +static int drm_version( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c index a53322d8c22..10e64fde8d7 100644 --- a/drivers/char/drm/drm_fops.c +++ b/drivers/char/drm/drm_fops.c @@ -37,6 +37,8 @@ #include "drmP.h" #include +static int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev); + static int drm_setup( drm_device_t *dev ) { int i; @@ -341,7 +343,7 @@ EXPORT_SYMBOL(drm_release); * Creates and initializes a drm_file structure for the file private data in \p * filp and add it into the double linked list in \p dev. */ -int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev) +static int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev) { int minor = iminor(inode); drm_file_t *priv; @@ -443,9 +445,3 @@ unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) } EXPORT_SYMBOL(drm_poll); - -/** No-op. */ -ssize_t drm_read(struct file *filp, char __user *buf, size_t count, loff_t *off) -{ - return 0; -} diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c index 2e236ebcf27..cdd4aecd25e 100644 --- a/drivers/char/drm/drm_irq.c +++ b/drivers/char/drm/drm_irq.c @@ -89,7 +89,7 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp, * \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions * before and after the installation. */ -int drm_irq_install( drm_device_t *dev ) +static int drm_irq_install( drm_device_t *dev ) { int ret; unsigned long sh_flags=0; diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c index d0d6fc66162..4702d863bcc 100644 --- a/drivers/char/drm/drm_lock.c +++ b/drivers/char/drm/drm_lock.c @@ -35,6 +35,11 @@ #include "drmP.h" +static int drm_lock_transfer(drm_device_t *dev, + __volatile__ unsigned int *lock, + unsigned int context); +static int drm_notifier(void *priv); + /** * Lock ioctl. * @@ -225,8 +230,9 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) * Resets the lock file pointer. * Marks the lock as held by the given context, via the \p cmpxchg instruction. */ -int drm_lock_transfer(drm_device_t *dev, - __volatile__ unsigned int *lock, unsigned int context) +static int drm_lock_transfer(drm_device_t *dev, + __volatile__ unsigned int *lock, + unsigned int context) { unsigned int old, new, prev; @@ -282,7 +288,7 @@ int drm_lock_free(drm_device_t *dev, * \return one if the signal should be delivered normally, or zero if the * signal should be blocked. */ -int drm_notifier(void *priv) +static int drm_notifier(void *priv) { drm_sigdata_t *s = (drm_sigdata_t *)priv; unsigned int old, new, prev; diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c index 6e06e8c6a51..4774087d2e9 100644 --- a/drivers/char/drm/drm_proc.c +++ b/drivers/char/drm/drm_proc.c @@ -57,7 +57,7 @@ static int drm_vma_info(char *buf, char **start, off_t offset, /** * Proc file list. */ -struct drm_proc_list { +static struct drm_proc_list { const char *name; /**< file name */ int (*f)(char *, char **, off_t, int, int *, void *); /**< proc callback*/ } drm_proc_list[] = { diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c index 8ccbdef7bb3..48829a1a086 100644 --- a/drivers/char/drm/drm_stub.c +++ b/drivers/char/drm/drm_stub.c @@ -157,52 +157,6 @@ int drm_stub_open(struct inode *inode, struct file *filp) return err; } - -/** - * Register. - * - * \param pdev - PCI device structure - * \param ent entry from the PCI ID table with device type flags - * \return zero on success or a negative number on failure. - * - * Attempt to gets inter module "drm" information. If we are first - * then register the character device and inter module information. - * Try and register, if we fail to register, backout previous work. - */ -int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, - struct drm_driver *driver) -{ - drm_device_t *dev; - int ret; - - DRM_DEBUG("\n"); - - dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB); - if (!dev) - return -ENOMEM; - - pci_enable_device(pdev); - - if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) { - printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); - goto err_g1; - } - if ((ret = drm_get_head(dev, &dev->primary))) - goto err_g1; - - /* postinit is a required function to display the signon banner */ - /* drivers add secondary heads here if needed */ - if ((ret = dev->driver->postinit(dev, ent->driver_data))) - goto err_g1; - - return 0; - -err_g1: - drm_free(dev, sizeof(*dev), DRM_MEM_STUB); - return ret; -} -EXPORT_SYMBOL(drm_get_dev); - /** * Get a secondary minor number. * @@ -214,7 +168,7 @@ EXPORT_SYMBOL(drm_get_dev); * create the proc init entry via proc_init(). This routines assigns * minor numbers to secondary heads of multi-headed cards */ -int drm_get_head(drm_device_t *dev, drm_head_t *head) +static int drm_get_head(drm_device_t *dev, drm_head_t *head) { drm_head_t **heads = drm_heads; int ret; @@ -262,6 +216,50 @@ err_g1: return ret; } +/** + * Register. + * + * \param pdev - PCI device structure + * \param ent entry from the PCI ID table with device type flags + * \return zero on success or a negative number on failure. + * + * Attempt to gets inter module "drm" information. If we are first + * then register the character device and inter module information. + * Try and register, if we fail to register, backout previous work. + */ +int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, + struct drm_driver *driver) +{ + drm_device_t *dev; + int ret; + + DRM_DEBUG("\n"); + + dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB); + if (!dev) + return -ENOMEM; + + pci_enable_device(pdev); + + if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) { + printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); + goto err_g1; + } + if ((ret = drm_get_head(dev, &dev->primary))) + goto err_g1; + + /* postinit is a required function to display the signon banner */ + /* drivers add secondary heads here if needed */ + if ((ret = dev->driver->postinit(dev, ent->driver_data))) + goto err_g1; + + return 0; + +err_g1: + drm_free(dev, sizeof(*dev), DRM_MEM_STUB); + return ret; +} +EXPORT_SYMBOL(drm_get_dev); /** * Put a device minor number. diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index fc72f30f312..621220f3f37 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c @@ -38,6 +38,8 @@ #include #endif +static void drm_vm_open(struct vm_area_struct *vma); +static void drm_vm_close(struct vm_area_struct *vma); /** * \c nopage method for AGP virtual memory. @@ -163,7 +165,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, * Deletes map information if we are the last * person to close a mapping and it's not in the global maplist. */ -void drm_vm_shm_close(struct vm_area_struct *vma) +static void drm_vm_shm_close(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->head->dev; @@ -399,7 +401,7 @@ static struct vm_operations_struct drm_vm_sg_ops = { * Create a new drm_vma_entry structure as the \p vma private data entry and * add it to drm_device::vmalist. */ -void drm_vm_open(struct vm_area_struct *vma) +static void drm_vm_open(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->head->dev; @@ -428,7 +430,7 @@ void drm_vm_open(struct vm_area_struct *vma) * Search the \p vma private data entry in drm_device::vmalist, unlink it, and * free it. */ -void drm_vm_close(struct vm_area_struct *vma) +static void drm_vm_close(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->head->dev; @@ -463,7 +465,7 @@ void drm_vm_close(struct vm_area_struct *vma) * Sets the virtual memory area operations structure to vm_dma_ops, the file * pointer, and calls vm_open(). */ -int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) +static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) { drm_file_t *priv = filp->private_data; drm_device_t *dev; diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index 24857cc6c23..18e0b762289 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -90,16 +90,7 @@ static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf) return 0; } -static struct file_operations i810_buffer_fops = { - .open = drm_open, - .flush = drm_flush, - .release = drm_release, - .ioctl = drm_ioctl, - .mmap = i810_mmap_buffers, - .fasync = drm_fasync, -}; - -int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) +static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) { drm_file_t *priv = filp->private_data; drm_device_t *dev; @@ -126,6 +117,15 @@ int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) return 0; } +static struct file_operations i810_buffer_fops = { + .open = drm_open, + .flush = drm_flush, + .release = drm_release, + .ioctl = drm_ioctl, + .mmap = i810_mmap_buffers, + .fasync = drm_fasync, +}; + static int i810_map_buffer(drm_buf_t *buf, struct file *filp) { drm_file_t *priv = filp->private_data; @@ -1003,8 +1003,8 @@ void i810_reclaim_buffers(drm_device_t *dev, struct file *filp) } } -int i810_flush_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static int i810_flush_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h index fa23ca454e5..1b40538d172 100644 --- a/drivers/char/drm/i810_drv.h +++ b/drivers/char/drm/i810_drv.h @@ -115,7 +115,6 @@ typedef struct drm_i810_private { /* i810_dma.c */ extern void i810_reclaim_buffers(drm_device_t *dev, struct file *filp); -extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma); extern int i810_driver_dma_quiescent(drm_device_t *dev); extern void i810_driver_release(drm_device_t *dev, struct file *filp); diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index 98adccf8e43..dc773303586 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -92,16 +92,7 @@ static int i830_freelist_put(drm_device_t *dev, drm_buf_t *buf) return 0; } -static struct file_operations i830_buffer_fops = { - .open = drm_open, - .flush = drm_flush, - .release = drm_release, - .ioctl = drm_ioctl, - .mmap = i830_mmap_buffers, - .fasync = drm_fasync, -}; - -int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma) +static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma) { drm_file_t *priv = filp->private_data; drm_device_t *dev; @@ -128,6 +119,15 @@ int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma) return 0; } +static struct file_operations i830_buffer_fops = { + .open = drm_open, + .flush = drm_flush, + .release = drm_release, + .ioctl = drm_ioctl, + .mmap = i830_mmap_buffers, + .fasync = drm_fasync, +}; + static int i830_map_buffer(drm_buf_t *buf, struct file *filp) { drm_file_t *priv = filp->private_data; diff --git a/drivers/char/drm/i830_drv.c b/drivers/char/drm/i830_drv.c index aa80ad6a5ee..bc36be76b8b 100644 --- a/drivers/char/drm/i830_drv.c +++ b/drivers/char/drm/i830_drv.c @@ -40,7 +40,7 @@ #include "drm_pciids.h" -int postinit( struct drm_device *dev, unsigned long flags ) +static int postinit( struct drm_device *dev, unsigned long flags ) { dev->counters += 4; dev->types[6] = _DRM_STAT_IRQ; diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h index d4b2d093d6a..df7746131de 100644 --- a/drivers/char/drm/i830_drv.h +++ b/drivers/char/drm/i830_drv.h @@ -123,8 +123,6 @@ typedef struct drm_i830_private { /* i830_dma.c */ extern void i830_reclaim_buffers(drm_device_t *dev, struct file *filp); -extern int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma); - /* i830_irq.c */ extern int i830_irq_emit( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c index 6d7729ffe2d..a5923e5d0a7 100644 --- a/drivers/char/drm/i830_irq.c +++ b/drivers/char/drm/i830_irq.c @@ -54,8 +54,7 @@ irqreturn_t i830_driver_irq_handler( DRM_IRQ_ARGS ) return IRQ_HANDLED; } - -int i830_emit_irq(drm_device_t *dev) +static int i830_emit_irq(drm_device_t *dev) { drm_i830_private_t *dev_priv = dev->dev_private; RING_LOCALS; @@ -73,7 +72,7 @@ int i830_emit_irq(drm_device_t *dev) } -int i830_wait_irq(drm_device_t *dev, int irq_nr) +static int i830_wait_irq(drm_device_t *dev, int irq_nr) { drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index b5903f9f142..acf9e52a950 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -32,23 +32,6 @@ #include "i915_drm.h" #include "i915_drv.h" -drm_ioctl_desc_t i915_ioctls[] = { - [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, 1, 1}, - [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, 1, 1}, - [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, 1, 0}, - [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, 1, 1}, - [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, 1, 0} -}; - -int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); - /* Really want an OS-independent resettable timer. Would like to have * this loop run for (eg) 3 sec, but have the timer reset every time * the head pointer changes, so that EBUSY only happens if the ring @@ -95,7 +78,7 @@ void i915_kernel_lost_context(drm_device_t * dev) dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; } -int i915_dma_cleanup(drm_device_t * dev) +static int i915_dma_cleanup(drm_device_t * dev) { /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private @@ -247,7 +230,7 @@ static int i915_resume(drm_device_t * dev) return 0; } -int i915_dma_init(DRM_IOCTL_ARGS) +static int i915_dma_init(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_i915_private_t *dev_priv; @@ -558,7 +541,7 @@ static int i915_quiescent(drm_device_t * dev) return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); } -int i915_flush_ioctl(DRM_IOCTL_ARGS) +static int i915_flush_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -567,7 +550,7 @@ int i915_flush_ioctl(DRM_IOCTL_ARGS) return i915_quiescent(dev); } -int i915_batchbuffer(DRM_IOCTL_ARGS) +static int i915_batchbuffer(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -601,7 +584,7 @@ int i915_batchbuffer(DRM_IOCTL_ARGS) return ret; } -int i915_cmdbuffer(DRM_IOCTL_ARGS) +static int i915_cmdbuffer(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -637,18 +620,7 @@ int i915_cmdbuffer(DRM_IOCTL_ARGS) return 0; } -int i915_do_cleanup_pageflip(drm_device_t * dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - DRM_DEBUG("%s\n", __FUNCTION__); - if (dev_priv->current_page != 0) - i915_dispatch_flip(dev); - - return 0; -} - -int i915_flip_bufs(DRM_IOCTL_ARGS) +static int i915_flip_bufs(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -659,7 +631,7 @@ int i915_flip_bufs(DRM_IOCTL_ARGS) return i915_dispatch_flip(dev); } -int i915_getparam(DRM_IOCTL_ARGS) +static int i915_getparam(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; @@ -694,7 +666,7 @@ int i915_getparam(DRM_IOCTL_ARGS) return 0; } -int i915_setparam(DRM_IOCTL_ARGS) +static int i915_setparam(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_i915_private_t *dev_priv = dev->dev_private; @@ -743,3 +715,19 @@ void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp) } } +drm_ioctl_desc_t i915_ioctls[] = { + [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, 1, 1}, + [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, 1, 0}, + [DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, 1, 0}, + [DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, 1, 0}, + [DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, 1, 0}, + [DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, 1, 0}, + [DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, 1, 0}, + [DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, 1, 1}, + [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, 1, 0}, + [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, 1, 0}, + [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, 1, 1}, + [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, 1, 0} +}; + +int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index e6a9e1d1d28..f0a0c5bd7c5 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -34,7 +34,7 @@ #include "drm_pciids.h" -int postinit( struct drm_device *dev, unsigned long flags ) +static int postinit( struct drm_device *dev, unsigned long flags ) { dev->counters += 4; dev->types[6] = _DRM_STAT_IRQ; diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index fa940d64b85..68c329965dd 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -99,14 +99,6 @@ typedef struct drm_i915_private { } drm_i915_private_t; /* i915_dma.c */ -extern int i915_dma_init(DRM_IOCTL_ARGS); -extern int i915_dma_cleanup(drm_device_t * dev); -extern int i915_flush_ioctl(DRM_IOCTL_ARGS); -extern int i915_batchbuffer(DRM_IOCTL_ARGS); -extern int i915_flip_bufs(DRM_IOCTL_ARGS); -extern int i915_getparam(DRM_IOCTL_ARGS); -extern int i915_setparam(DRM_IOCTL_ARGS); -extern int i915_cmdbuffer(DRM_IOCTL_ARGS); extern void i915_kernel_lost_context(drm_device_t * dev); extern void i915_driver_pretakedown(drm_device_t *dev); extern void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp); @@ -114,8 +106,6 @@ extern void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp); /* i915_irq.c */ extern int i915_irq_emit(DRM_IOCTL_ARGS); extern int i915_irq_wait(DRM_IOCTL_ARGS); -extern int i915_wait_irq(drm_device_t * dev, int irq_nr); -extern int i915_emit_irq(drm_device_t * dev); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(drm_device_t *dev); diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index a101cc9cfd7..4fa448ee846 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -56,7 +56,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_HANDLED; } -int i915_emit_irq(drm_device_t * dev) +static int i915_emit_irq(drm_device_t * dev) { drm_i915_private_t *dev_priv = dev->dev_private; u32 ret; @@ -76,7 +76,7 @@ int i915_emit_irq(drm_device_t * dev) return ret; } -int i915_wait_irq(drm_device_t * dev, int irq_nr) +static int i915_wait_irq(drm_device_t * dev, int irq_nr) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = 0; diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c index 53af6916282..426a71c049d 100644 --- a/drivers/char/drm/r128_state.c +++ b/drivers/char/drm/r128_state.c @@ -1307,7 +1307,7 @@ static int r128_do_init_pageflip( drm_device_t *dev ) return 0; } -int r128_do_cleanup_pageflip( drm_device_t *dev ) +static int r128_do_cleanup_pageflip( drm_device_t *dev ) { drm_r128_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); -- cgit v1.2.3 From 850eb83a6a21b086624b227653ce90ad927ba423 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 7 Jul 2005 21:09:14 +1000 Subject: drm: wrap config.h include in a ifdef KERNEL This file can be included from userspace so wrap the config.h include. Signed-off-by: David Airlie --- drivers/char/drm/drm.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h index 587305282ea..e8371dd87fb 100644 --- a/drivers/char/drm/drm.h +++ b/drivers/char/drm/drm.h @@ -38,7 +38,9 @@ #define _DRM_H_ #if defined(__linux__) +#if defined(__KERNEL__) #include +#endif #include /* For _IO* macros */ #define DRM_IOCTL_NR(n) _IOC_NR(n) #define DRM_IOC_VOID _IOC_NONE -- cgit v1.2.3 From 8ca7c1df08210fd35fccf1559837c92baaa4da8f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 7 Jul 2005 21:51:26 +1000 Subject: drm: add 32/64 support for MGA/R128/i915 This adds compatiblity ioctls for mga/r128 and i915 DRM drivers. From: Paul Mackerras, David Airlie, Alan Hourihane, Egbert Eich. Signed-off-by: David Airlie --- drivers/char/drm/Makefile | 3 + drivers/char/drm/i915_drv.c | 3 + drivers/char/drm/i915_drv.h | 4 + drivers/char/drm/i915_ioc32.c | 221 ++++++++++++++++++++++++++++++++++++++++++ drivers/char/drm/mga_drv.c | 3 + drivers/char/drm/mga_drv.h | 2 + drivers/char/drm/mga_ioc32.c | 167 +++++++++++++++++++++++++++++++ drivers/char/drm/r128_drv.c | 3 + drivers/char/drm/r128_drv.h | 3 + drivers/char/drm/r128_ioc32.c | 219 +++++++++++++++++++++++++++++++++++++++++ 10 files changed, 628 insertions(+) create mode 100644 drivers/char/drm/i915_ioc32.c create mode 100644 drivers/char/drm/mga_ioc32.c create mode 100644 drivers/char/drm/r128_ioc32.c (limited to 'drivers') diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index 7444dec40b9..b36b0158582 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile @@ -22,6 +22,9 @@ sis-objs := sis_drv.o sis_ds.o sis_mm.o ifeq ($(CONFIG_COMPAT),y) drm-objs += drm_ioc32.o radeon-objs += radeon_ioc32.o +mga-objs += mga_ioc32.o +r128-objs += r128_ioc32.o +i915-objs += i915_ioc32.o endif obj-$(CONFIG_DRM) += drm.o diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c index e6a9e1d1d28..6a6cc3c0c4c 100644 --- a/drivers/char/drm/i915_drv.c +++ b/drivers/char/drm/i915_drv.c @@ -97,6 +97,9 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, +#ifdef CONFIG_COMPAT + .compat_ioctl = i915_compat_ioctl, +#endif }, .pci_driver = { .name = DRIVER_NAME, diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index fa940d64b85..3a21223267c 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -130,6 +130,10 @@ extern void i915_mem_takedown(struct mem_block **heap); extern void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap); +extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) + + #define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, reg) #define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, reg, val) #define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg) diff --git a/drivers/char/drm/i915_ioc32.c b/drivers/char/drm/i915_ioc32.c new file mode 100644 index 00000000000..fe009e1b3a3 --- /dev/null +++ b/drivers/char/drm/i915_ioc32.c @@ -0,0 +1,221 @@ +/** + * \file i915_ioc32.c + * + * 32-bit ioctl compatibility routines for the i915 DRM. + * + * \author Alan Hourihane + * + * + * Copyright (C) Paul Mackerras 2005 + * Copyright (C) Alan Hourihane 2005 + * 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, sublicense, + * 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 NONINFRINGEMENT. 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 +#include + +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" + +typedef struct _drm_i915_batchbuffer32 { + int start; /* agp offset */ + int used; /* nr bytes in use */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + u32 cliprects; /* pointer to userspace cliprects */ +} drm_i915_batchbuffer32_t; + +static int compat_i915_batchbuffer(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_i915_batchbuffer32_t batchbuffer32; + drm_i915_batchbuffer_t __user *batchbuffer; + + if (copy_from_user(&batchbuffer32, (void __user *)arg, sizeof(batchbuffer32))) + return -EFAULT; + + batchbuffer = compat_alloc_user_space(sizeof(*batchbuffer)); + if (!access_ok(VERIFY_WRITE, batchbuffer, sizeof(*batchbuffer)) + || __put_user(batchbuffer32.start, &batchbuffer->start) + || __put_user(batchbuffer32.used, &batchbuffer->used) + || __put_user(batchbuffer32.DR1, &batchbuffer->DR1) + || __put_user(batchbuffer32.DR4, &batchbuffer->DR4) + || __put_user(batchbuffer32.num_cliprects, &batchbuffer->num_cliprects) + || __put_user((int __user *)(unsigned long)batchbuffer32.cliprects, + &batchbuffer->cliprects)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_I915_BATCHBUFFER, (unsigned long) batchbuffer); +} + +typedef struct _drm_i915_cmdbuffer32 { + u32 buf; /* pointer to userspace command buffer */ + int sz; /* nr bytes in buf */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + u32 cliprects; /* pointer to userspace cliprects */ +} drm_i915_cmdbuffer32_t; + +static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_i915_cmdbuffer32_t cmdbuffer32; + drm_i915_cmdbuffer_t __user *cmdbuffer; + + if (copy_from_user(&cmdbuffer32, (void __user *)arg, sizeof(cmdbuffer32))) + return -EFAULT; + + cmdbuffer = compat_alloc_user_space(sizeof(*cmdbuffer)); + if (!access_ok(VERIFY_WRITE, cmdbuffer, sizeof(*cmdbuffer)) + || __put_user((int __user *)(unsigned long)cmdbuffer32.buf, + &cmdbuffer->buf) + || __put_user(cmdbuffer32.sz, &cmdbuffer->sz) + || __put_user(cmdbuffer32.DR1, &cmdbuffer->DR1) + || __put_user(cmdbuffer32.DR4, &cmdbuffer->DR4) + || __put_user(cmdbuffer32.num_cliprects, &cmdbuffer->num_cliprects) + || __put_user((int __user *)(unsigned long)cmdbuffer32.cliprects, + &cmdbuffer->cliprects)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_I915_CMDBUFFER, (unsigned long) cmdbuffer); +} + +typedef struct drm_i915_irq_emit32 { + u32 irq_seq; +} drm_i915_irq_emit32_t; + +static int compat_i915_irq_emit(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_i915_irq_emit32_t req32; + drm_i915_irq_emit_t __user *request; + + if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user((int __user *)(unsigned long)req32.irq_seq, + &request->irq_seq)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_I915_IRQ_EMIT, (unsigned long) request); +} +typedef struct drm_i915_getparam32 { + int param; + u32 value; +} drm_i915_getparam32_t; + +static int compat_i915_getparam(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_i915_getparam32_t req32; + drm_i915_getparam_t __user *request; + + if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.param, &request->param) + || __put_user((void __user *)(unsigned long)req32.value, + &request->value)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_I915_GETPARAM, (unsigned long) request); +} + +typedef struct drm_i915_mem_alloc32 { + int region; + int alignment; + int size; + u32 region_offset; /* offset from start of fb or agp */ +} drm_i915_mem_alloc32_t; + +static int compat_i915_alloc(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_i915_mem_alloc32_t req32; + drm_i915_mem_alloc_t __user *request; + + if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) + return -EFAULT; + + request = compat_alloc_user_space(sizeof(*request)); + if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + || __put_user(req32.region, &request->region) + || __put_user(req32.alignment, &request->alignment) + || __put_user(req32.size, &request->size) + || __put_user((void __user *)(unsigned long)req32.region_offset, + &request->region_offset)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_I915_ALLOC, (unsigned long) request); +} + + +drm_ioctl_compat_t *i915_compat_ioctls[] = { + [DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer, + [DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer, + [DRM_I915_GETPARAM] = compat_i915_getparam, + [DRM_I915_IRQ_EMIT] = compat_i915_irq_emit, + [DRM_I915_ALLOC] = compat_i915_alloc +}; + +/** + * Called whenever a 32-bit process running under a 64-bit kernel + * performs an ioctl on /dev/dri/card. + * + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or negative number on failure. + */ +long i915_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + unsigned int nr = DRM_IOCTL_NR(cmd); + drm_ioctl_compat_t *fn = NULL; + int ret; + + if (nr < DRM_COMMAND_BASE) + return drm_compat_ioctl(filp, cmd, arg); + + if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(i915_compat_ioctls)) + fn = i915_compat_ioctls[nr - DRM_COMMAND_BASE]; + + lock_kernel(); /* XXX for now */ + if (fn != NULL) + ret = (*fn)(filp, cmd, arg); + else + ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); + unlock_kernel(); + + return ret; +} diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c index 22dab3e9d92..844cca9cb29 100644 --- a/drivers/char/drm/mga_drv.c +++ b/drivers/char/drm/mga_drv.c @@ -101,6 +101,9 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, +#ifdef CONFIG_COMPAT + .compat_ioctl = mga_compat_ioctl, +#endif }, .pci_driver = { .name = DRIVER_NAME, diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h index 1d84a1eb34d..9412e2816eb 100644 --- a/drivers/char/drm/mga_drv.h +++ b/drivers/char/drm/mga_drv.h @@ -137,6 +137,8 @@ extern irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS ); extern void mga_driver_irq_preinstall( drm_device_t *dev ); extern void mga_driver_irq_postinstall( drm_device_t *dev ); extern void mga_driver_irq_uninstall( drm_device_t *dev ); +extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); #define mga_flush_write_combine() DRM_WRITEMEMORYBARRIER() diff --git a/drivers/char/drm/mga_ioc32.c b/drivers/char/drm/mga_ioc32.c new file mode 100644 index 00000000000..bc745cfa209 --- /dev/null +++ b/drivers/char/drm/mga_ioc32.c @@ -0,0 +1,167 @@ +/** + * \file mga_ioc32.c + * + * 32-bit ioctl compatibility routines for the MGA DRM. + * + * \author Dave Airlie with code from patches by Egbert Eich + * + * + * Copyright (C) Paul Mackerras 2005 + * Copyright (C) Egbert Eich 2003,2004 + * Copyright (C) Dave Airlie 2005 + * 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, sublicense, + * 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 NONINFRINGEMENT. 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 +#include + +#include "drmP.h" +#include "drm.h" +#include "mga_drm.h" + +typedef struct drm32_mga_init { + int func; + u32 sarea_priv_offset; + int chipset; + int sgram; + unsigned int maccess; + unsigned int fb_cpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + unsigned int depth_cpp; + unsigned int depth_offset, depth_pitch; + unsigned int texture_offset[MGA_NR_TEX_HEAPS]; + unsigned int texture_size[MGA_NR_TEX_HEAPS]; + u32 fb_offset; + u32 mmio_offset; + u32 status_offset; + u32 warp_offset; + u32 primary_offset; + u32 buffers_offset; +} drm_mga_init32_t; + +static int compat_mga_init(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_mga_init32_t init32; + drm_mga_init_t __user *init; + int err = 0, i; + + if (copy_from_user(&init32, (void __user *)arg, sizeof(init32))) + return -EFAULT; + + init = compat_alloc_user_space(sizeof(*init)); + if (!access_ok(VERIFY_WRITE, init, sizeof(*init)) + || __put_user(init32.func, &init->func) + || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset) + || __put_user(init32.chipset, &init->chipset) + || __put_user(init32.sgram, &init->sgram) + || __put_user(init32.maccess, &init->maccess) + || __put_user(init32.fb_cpp, &init->fb_cpp) + || __put_user(init32.front_offset, &init->front_offset) + || __put_user(init32.front_pitch, &init->front_pitch) + || __put_user(init32.back_offset, &init->back_offset) + || __put_user(init32.back_pitch, &init->back_pitch) + || __put_user(init32.depth_cpp, &init->depth_cpp) + || __put_user(init32.depth_offset, &init->depth_offset) + || __put_user(init32.depth_pitch, &init->depth_pitch) + || __put_user(init32.fb_offset, &init->fb_offset) + || __put_user(init32.mmio_offset, &init->mmio_offset) + || __put_user(init32.status_offset, &init->status_offset) + || __put_user(init32.warp_offset, &init->warp_offset) + || __put_user(init32.primary_offset, &init->primary_offset) + || __put_user(init32.buffers_offset, &init->buffers_offset)) + return -EFAULT; + + for (i=0; itexture_offset[i]); + err |= __put_user(init32.texture_size[i], &init->texture_size[i]); + } + if (err) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_MGA_INIT, (unsigned long) init); +} + + +typedef struct drm_mga_getparam32 { + int param; + u32 value; +} drm_mga_getparam32_t; + + +static int compat_mga_getparam(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_mga_getparam32_t getparam32; + drm_mga_getparam_t __user *getparam; + + if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32))) + return -EFAULT; + + getparam = compat_alloc_user_space(sizeof(*getparam)); + if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam)) + || __put_user(getparam32.param, &getparam->param) + || __put_user((void __user *)(unsigned long)getparam32.value, &getparam->value)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam); +} + +drm_ioctl_compat_t *mga_compat_ioctls[] = { + [DRM_MGA_INIT] = compat_mga_init, + [DRM_MGA_GETPARAM] = compat_mga_getparam, +}; + +/** + * Called whenever a 32-bit process running under a 64-bit kernel + * performs an ioctl on /dev/dri/card. + * + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or negative number on failure. + */ +long mga_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + unsigned int nr = DRM_IOCTL_NR(cmd); + drm_ioctl_compat_t *fn = NULL; + int ret; + + if (nr < DRM_COMMAND_BASE) + return drm_compat_ioctl(filp, cmd, arg); + + if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(mga_compat_ioctls)) + fn = mga_compat_ioctls[nr - DRM_COMMAND_BASE]; + + lock_kernel(); /* XXX for now */ + if (fn != NULL) + ret = (*fn)(filp, cmd, arg); + else + ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); + unlock_kernel(); + + return ret; +} diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c index ced63810237..bc446da1b21 100644 --- a/drivers/char/drm/r128_drv.c +++ b/drivers/char/drm/r128_drv.c @@ -96,6 +96,9 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, +#ifdef CONFIG_COMPAT + .compat_ioctl = r128_compat_ioctl, +#endif }, .pci_driver = { .name = DRIVER_NAME, diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h index cf1aa5df459..0fb687c9505 100644 --- a/drivers/char/drm/r128_drv.h +++ b/drivers/char/drm/r128_drv.h @@ -156,6 +156,9 @@ extern void r128_driver_irq_uninstall( drm_device_t *dev ); extern void r128_driver_pretakedown(drm_device_t *dev); extern void r128_driver_prerelease(drm_device_t *dev, DRMFILE filp); +extern long r128_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); + /* Register definitions, register access macros and drmAddMap constants * for Rage 128 kernel driver. */ diff --git a/drivers/char/drm/r128_ioc32.c b/drivers/char/drm/r128_ioc32.c new file mode 100644 index 00000000000..60598ef9475 --- /dev/null +++ b/drivers/char/drm/r128_ioc32.c @@ -0,0 +1,219 @@ +/** + * \file r128_ioc32.c + * + * 32-bit ioctl compatibility routines for the R128 DRM. + * + * \author Dave Airlie with code from patches by Egbert Eich + * + * Copyright (C) Paul Mackerras 2005 + * Copyright (C) Egbert Eich 2003,2004 + * Copyright (C) Dave Airlie 2005 + * 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, sublicense, + * 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 NONINFRINGEMENT. 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 +#include + +#include "drmP.h" +#include "drm.h" +#include "r128_drm.h" + +typedef struct drm_r128_init32 { + int func; + unsigned int sarea_priv_offset; + int is_pci; + int cce_mode; + int cce_secure; + int ring_size; + int usec_timeout; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + unsigned int span_offset; + + unsigned int fb_offset; + unsigned int mmio_offset; + unsigned int ring_offset; + unsigned int ring_rptr_offset; + unsigned int buffers_offset; + unsigned int agp_textures_offset; +} drm_r128_init32_t; + +static int compat_r128_init(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_r128_init32_t init32; + drm_r128_init_t __user *init; + + if (copy_from_user(&init32, (void __user *)arg, sizeof(init32))) + return -EFAULT; + + init = compat_alloc_user_space(sizeof(*init)); + if (!access_ok(VERIFY_WRITE, init, sizeof(*init)) + || __put_user(init32.func, &init->func) + || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset) + || __put_user(init32.is_pci, &init->is_pci) + || __put_user(init32.cce_mode, &init->cce_mode) + || __put_user(init32.cce_secure, &init->cce_secure) + || __put_user(init32.ring_size, &init->ring_size) + || __put_user(init32.usec_timeout, &init->usec_timeout) + || __put_user(init32.fb_bpp, &init->fb_bpp) + || __put_user(init32.front_offset, &init->front_offset) + || __put_user(init32.front_pitch, &init->front_pitch) + || __put_user(init32.back_offset, &init->back_offset) + || __put_user(init32.back_pitch, &init->back_pitch) + || __put_user(init32.depth_bpp, &init->depth_bpp) + || __put_user(init32.depth_offset, &init->depth_offset) + || __put_user(init32.depth_pitch, &init->depth_pitch) + || __put_user(init32.span_offset, &init->span_offset) + || __put_user(init32.fb_offset, &init->fb_offset) + || __put_user(init32.mmio_offset, &init->mmio_offset) + || __put_user(init32.ring_offset, &init->ring_offset) + || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset) + || __put_user(init32.buffers_offset, &init->buffers_offset) + || __put_user(init32.agp_textures_offset, &init->agp_textures_offset)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_R128_INIT, (unsigned long)init); +} + + +typedef struct drm_r128_depth32 { + int func; + int n; + u32 x; + u32 y; + u32 buffer; + u32 mask; +} drm_r128_depth32_t; + +static int compat_r128_depth(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_r128_depth32_t depth32; + drm_r128_depth_t __user *depth; + + if (copy_from_user(&depth32, (void __user *)arg, sizeof(depth32))) + return -EFAULT; + + depth = compat_alloc_user_space(sizeof(*depth)); + if (!access_ok(VERIFY_WRITE, depth, sizeof(*depth)) + || __put_user(depth32.func, &depth->func) + || __put_user(depth32.n, &depth->n) + || __put_user((int __user *)(unsigned long)depth32.x, &depth->x) + || __put_user((int __user *)(unsigned long)depth32.y, &depth->y) + || __put_user((unsigned int __user *)(unsigned long)depth32.buffer, &depth->buffer) + || __put_user((unsigned char __user *)(unsigned long)depth32.mask, &depth->mask)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_R128_DEPTH, (unsigned long)depth); + +} + +typedef struct drm_r128_stipple32 { + u32 mask; +} drm_r128_stipple32_t; + +static int compat_r128_stipple(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_r128_stipple32_t stipple32; + drm_r128_stipple_t __user *stipple; + + if (copy_from_user(&stipple32, (void __user *)arg, sizeof(stipple32))) + return -EFAULT; + + stipple = compat_alloc_user_space(sizeof(*stipple)); + if (!access_ok(VERIFY_WRITE, stipple, sizeof(*stipple)) + || __put_user((unsigned int __user *)(unsigned long)stipple32.mask, &stipple->mask)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple); +} + +typedef struct drm_r128_getparam32 { + int param; + u32 value; +} drm_r128_getparam32_t; + +static int compat_r128_getparam(struct file *file, unsigned int cmd, + unsigned long arg) +{ + drm_r128_getparam32_t getparam32; + drm_r128_getparam_t __user *getparam; + + if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32))) + return -EFAULT; + + getparam = compat_alloc_user_space(sizeof(*getparam)); + if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam)) + || __put_user(getparam32.param, &getparam->param) + || __put_user((void __user *)(unsigned long)getparam32.value, &getparam->value)) + return -EFAULT; + + return drm_ioctl(file->f_dentry->d_inode, file, + DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam); +} + +drm_ioctl_compat_t *r128_compat_ioctls[] = { + [DRM_R128_INIT] = compat_r128_init, + [DRM_R128_DEPTH] = compat_r128_depth, + [DRM_R128_STIPPLE] = compat_r128_stipple, + [DRM_R128_GETPARAM] = compat_r128_getparam, +}; + +/** + * Called whenever a 32-bit process running under a 64-bit kernel + * performs an ioctl on /dev/dri/card. + * + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or negative number on failure. + */ +long r128_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + unsigned int nr = DRM_IOCTL_NR(cmd); + drm_ioctl_compat_t *fn = NULL; + int ret; + + if (nr < DRM_COMMAND_BASE) + return drm_compat_ioctl(filp, cmd, arg); + + if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(r128_compat_ioctls)) + fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE]; + + lock_kernel(); /* XXX for now */ + if (fn != NULL) + ret = (*fn)(filp, cmd, arg); + else + ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); + unlock_kernel(); + + return ret; +} -- cgit v1.2.3 From b9c86d595d2a11009c58c84a9a8792aeb4a8f278 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 7 Jul 2005 11:26:24 +0100 Subject: [MTD] Remove MODULE_DEVICE_TABLE() for ICHx flash driver This prevents it from automatically getting loaded by hotplug because we happen to notice you have this chipset. Let's stick with having to load the drivers which let you overwrite your BIOS _manually_ Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/ichxrom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index 1800ceedf38..e505207cd48 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -2,7 +2,7 @@ * ichxrom.c * * Normal mappings of chips in physical memory - * $Id: ichxrom.c,v 1.17 2005/03/18 14:04:35 gleixner Exp $ + * $Id: ichxrom.c,v 1.18 2005/07/07 10:26:20 dwmw2 Exp $ */ #include @@ -338,9 +338,9 @@ static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = { { 0, }, }; +#if 0 MODULE_DEVICE_TABLE(pci, ichxrom_pci_tbl); -#if 0 static struct pci_driver ichxrom_driver = { .name = MOD_NAME, .id_table = ichxrom_pci_tbl, -- cgit v1.2.3 From 97f927a4d7dbccde0a854a62c3ea54d90bae8679 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 7 Jul 2005 16:50:16 +0200 Subject: [MTD] XIP cleanup Move the architecture dependend code into include/asm/mtd-xip.h Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 2 +- drivers/mtd/chips/cfi_cmdset_0002.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 8b1304531d8..0cfcd88468e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -845,7 +845,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, chip->state = FL_READY; } (void) map_read(map, adr); - asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */ + xip_iprefetch(); local_irq_enable(); } diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index c76c30de48f..8505f118f2d 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -600,7 +600,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, chip->state = FL_READY; } (void) map_read(map, adr); - asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */ + xip_iprefetch(); local_irq_enable(); } -- cgit v1.2.3 From ca3f5a95b7d04eef0f88464f8d3299c1c01e8e13 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 7 Jul 2005 17:56:02 -0700 Subject: [PATCH] i2o: config-osm build fix Various stuff missing on alpha: drivers/message/i2o/config-osm.c:35: error: field `fops' has incomplete type drivers/message/i2o/config-osm.c: In function `sysfs_create_fops_file': drivers/message/i2o/config-osm.c:71: error: storage size of `tmp' isn't known drivers/message/i2o/config-osm.c:78: error: dereferencing pointer to incomplete type drivers/message/i2o/config-osm.c:81: error: dereferencing pointer to incomplete type Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/message/i2o/config-osm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/message/i2o/config-osm.c b/drivers/message/i2o/config-osm.c index d0267609a94..fe2e7afc9ea 100644 --- a/drivers/message/i2o/config-osm.c +++ b/drivers/message/i2o/config-osm.c @@ -15,7 +15,9 @@ #include #include +#include #include +#include #include -- cgit v1.2.3 From 79b9ce311e192e9a31fd9f3cf1ee4a4edf9e2650 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Thu, 7 Jul 2005 17:56:04 -0700 Subject: [PATCH] print order information when OOM killing Dump the current allocation order when OOM killing. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/sysrq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index af79805b557..12d563c648f 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -228,7 +228,7 @@ static struct sysrq_key_op sysrq_term_op = { static void moom_callback(void *ignored) { - out_of_memory(GFP_KERNEL); + out_of_memory(GFP_KERNEL, 0); } static DECLARE_WORK(moom_work, moom_callback, NULL); -- cgit v1.2.3 From 3c326fe9cb7ae022f7589a6f5781e49ceab82e64 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 7 Jul 2005 17:56:09 -0700 Subject: [PATCH] ppc64: Add new PHY to sungem This patch adds support for some new PHY models to sungem as used on some recent Apple iMac G5 models. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/sungem.c | 4 ++- drivers/net/sungem_phy.c | 69 +++++++++++++++++++++++++++++++++++------------- drivers/net/sungem_phy.h | 3 ++- 3 files changed, 56 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 1f5655655c4..2608e7a3d21 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -3079,7 +3079,9 @@ static int __devinit gem_init_one(struct pci_dev *pdev, gp->phy_mii.dev = dev; gp->phy_mii.mdio_read = _phy_read; gp->phy_mii.mdio_write = _phy_write; - +#ifdef CONFIG_PPC_PMAC + gp->phy_mii.platform_data = gp->of_node; +#endif /* By default, we start with autoneg */ gp->want_autoneg = 1; diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c index 0fca414d365..d3ddb41d6e5 100644 --- a/drivers/net/sungem_phy.c +++ b/drivers/net/sungem_phy.c @@ -32,6 +32,10 @@ #include #include +#ifdef CONFIG_PPC_PMAC +#include +#endif + #include "sungem_phy.h" /* Link modes of the BCM5400 PHY */ @@ -281,10 +285,12 @@ static int bcm5411_suspend(struct mii_phy* phy) static int bcm5421_init(struct mii_phy* phy) { u16 data; - int rev; + unsigned int id; - rev = phy_read(phy, MII_PHYSID2) & 0x000f; - if (rev == 0) { + id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2)); + + /* Revision 0 of 5421 needs some fixups */ + if (id == 0x002060e0) { /* This is borrowed from MacOS */ phy_write(phy, 0x18, 0x1007); @@ -297,21 +303,28 @@ static int bcm5421_init(struct mii_phy* phy) data = phy_read(phy, 0x15); phy_write(phy, 0x15, data | 0x0200); } -#if 0 - /* This has to be verified before I enable it */ - /* Enable automatic low-power */ - phy_write(phy, 0x1c, 0x9002); - phy_write(phy, 0x1c, 0xa821); - phy_write(phy, 0x1c, 0x941d); -#endif - return 0; -} -static int bcm5421k2_init(struct mii_phy* phy) -{ - /* Init code borrowed from OF */ - phy_write(phy, 4, 0x01e1); - phy_write(phy, 9, 0x0300); + /* Pick up some init code from OF for K2 version */ + if ((id & 0xfffffff0) == 0x002062e0) { + phy_write(phy, 4, 0x01e1); + phy_write(phy, 9, 0x0300); + } + + /* Check if we can enable automatic low power */ +#ifdef CONFIG_PPC_PMAC + if (phy->platform_data) { + struct device_node *np = of_get_parent(phy->platform_data); + int can_low_power = 1; + if (np == NULL || get_property(np, "no-autolowpower", NULL)) + can_low_power = 0; + if (can_low_power) { + /* Enable automatic low-power */ + phy_write(phy, 0x1c, 0x9002); + phy_write(phy, 0x1c, 0xa821); + phy_write(phy, 0x1c, 0x941d); + } + } +#endif /* CONFIG_PPC_PMAC */ return 0; } @@ -762,7 +775,7 @@ static struct mii_phy_def bcm5421_phy_def = { /* Broadcom BCM 5421 built-in K2 */ static struct mii_phy_ops bcm5421k2_phy_ops = { - .init = bcm5421k2_init, + .init = bcm5421_init, .suspend = bcm5411_suspend, .setup_aneg = bcm54xx_setup_aneg, .setup_forced = bcm54xx_setup_forced, @@ -779,6 +792,25 @@ static struct mii_phy_def bcm5421k2_phy_def = { .ops = &bcm5421k2_phy_ops }; +/* Broadcom BCM 5462 built-in Vesta */ +static struct mii_phy_ops bcm5462V_phy_ops = { + .init = bcm5421_init, + .suspend = bcm5411_suspend, + .setup_aneg = bcm54xx_setup_aneg, + .setup_forced = bcm54xx_setup_forced, + .poll_link = genmii_poll_link, + .read_link = bcm54xx_read_link, +}; + +static struct mii_phy_def bcm5462V_phy_def = { + .phy_id = 0x002060d0, + .phy_id_mask = 0xfffffff0, + .name = "BCM5462-Vesta", + .features = MII_GBIT_FEATURES, + .magic_aneg = 1, + .ops = &bcm5462V_phy_ops +}; + /* Marvell 88E1101 (Apple seem to deal with 2 different revs, * I masked out the 8 last bits to get both, but some specs * would be useful here) --BenH. @@ -824,6 +856,7 @@ static struct mii_phy_def* mii_phy_table[] = { &bcm5411_phy_def, &bcm5421_phy_def, &bcm5421k2_phy_def, + &bcm5462V_phy_def, &marvell_phy_def, &genmii_phy_def, NULL diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h index 822cb58174e..430544496c5 100644 --- a/drivers/net/sungem_phy.h +++ b/drivers/net/sungem_phy.h @@ -43,9 +43,10 @@ struct mii_phy int pause; /* Provided by host chip */ - struct net_device* dev; + struct net_device *dev; int (*mdio_read) (struct net_device *dev, int mii_id, int reg); void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val); + void *platform_data; }; /* Pass in a struct mii_phy with dev, mdio_read and mdio_write -- cgit v1.2.3 From 837dcfaf46d147f1d2c64cbbecb832dd9075c39d Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 7 Jul 2005 17:56:16 -0700 Subject: [PATCH] hvc_console: Rearrange code Milton Miller has done a lot of work to clean up our hvc_console code. One of the important things the following patch series does is separate the VIO layer from the hvc_console code. With the VIO specific code removed any ppc64 platform, or even any architecture, can use hvc_console as a generic polling console. You simply have to supply a get_chars and put_chars method and hvc_console does the rest of the work. You can even use it for an interrupt driven console. This patch: Rearrange the code in drivers/char/hvc_console.c to make future patches smaller. No actual code changes, just ordering of the functions in the file. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 284 ++++++++++++++++++++++----------------------- 1 file changed, 142 insertions(+), 142 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 88cd858f74d..f0a1456a597 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -61,16 +61,21 @@ */ #define HVC_ALLOC_TTY_ADAPTERS 8 -static struct tty_driver *hvc_driver; -#ifdef CONFIG_MAGIC_SYSRQ -static int sysrq_pressed; -#endif - #define N_OUTBUF 16 #define N_INBUF 16 #define __ALIGNED__ __attribute__((__aligned__(8))) +static struct tty_driver *hvc_driver; +static struct task_struct *hvc_task; + +/* Picks up late kicks after list walk but before schedule() */ +static int hvc_kicked; + +#ifdef CONFIG_MAGIC_SYSRQ +static int sysrq_pressed; +#endif + struct hvc_struct { spinlock_t lock; int index; @@ -96,6 +101,41 @@ static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs); */ static DEFINE_SPINLOCK(hvc_structs_lock); +/* + * This value is used to associate a tty->index value to a hvc_struct based + * upon order of exposure via hvc_probe(). + */ +static int hvc_count = -1; + +/* + * Do not call this function with either the hvc_strucst_lock or the hvc_struct + * lock held. If successful, this function increments the kobject reference + * count against the target hvc_struct so it should be released when finished. + */ +struct hvc_struct *hvc_get_by_index(int index) +{ + struct hvc_struct *hp; + unsigned long flags; + + spin_lock(&hvc_structs_lock); + + list_for_each_entry(hp, &hvc_structs, next) { + spin_lock_irqsave(&hp->lock, flags); + if (hp->index == index) { + kobject_get(&hp->kobj); + spin_unlock_irqrestore(&hp->lock, flags); + spin_unlock(&hvc_structs_lock); + return hp; + } + spin_unlock_irqrestore(&hp->lock, flags); + } + hp = NULL; + + spin_unlock(&hvc_structs_lock); + return hp; +} + + /* * Initial console vtermnos for console API usage prior to full console * initialization. Any vty adapter outside this range will not have usable @@ -107,16 +147,98 @@ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES]; /* Used for accounting purposes */ static int num_vterms = 0; -static struct task_struct *hvc_task; +/* + * Console APIs, NOT TTY. These APIs are available immediately when + * hvc_console_setup() finds adapters. + */ + +void hvc_console_print(struct console *co, const char *b, unsigned count) +{ + char c[16] __ALIGNED__; + unsigned i = 0, n = 0; + int r, donecr = 0; + + /* Console access attempt outside of acceptable console range. */ + if (co->index >= MAX_NR_HVC_CONSOLES) + return; + + /* This console adapter was removed so it is not useable. */ + if (vtermnos[co->index] < 0) + return; + + while (count > 0 || i > 0) { + if (count > 0 && i < sizeof(c)) { + if (b[n] == '\n' && !donecr) { + c[i++] = '\r'; + donecr = 1; + } else { + c[i++] = b[n++]; + donecr = 0; + --count; + } + } else { + r = hvc_put_chars(vtermnos[co->index], c, i); + if (r < 0) { + /* throw away chars on error */ + i = 0; + } else if (r > 0) { + i -= r; + if (i > 0) + memmove(c, c+r, i); + } + } + } +} + +static struct tty_driver *hvc_console_device(struct console *c, int *index) +{ + *index = c->index; + return hvc_driver; +} + +static int __init hvc_console_setup(struct console *co, char *options) +{ + return 0; +} + +struct console hvc_con_driver = { + .name = "hvc", + .write = hvc_console_print, + .device = hvc_console_device, + .setup = hvc_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +/* Early console initialization. Preceeds driver initialization. */ +static int __init hvc_console_init(void) +{ + int i; + + for (i=0; iindex value to a hvc_struct based - * upon order of exposure via hvc_probe(). + * hvc_instantiate() is an early console discovery method which locates consoles + * prior to the vio subsystem discovering them. Hotplugged vty adapters do NOT + * get an hvc_instantiate() callback since the appear after early console init. */ -static int hvc_count = -1; +int hvc_instantiate(uint32_t vtermno, int index) +{ + if (index < 0 || index >= MAX_NR_HVC_CONSOLES) + return -1; -/* Picks up late kicks after list walk but before schedule() */ -static int hvc_kicked; + if (vtermnos[index] != -1) + return -1; + + vtermnos[index] = vtermno; + return 0; +} /* Wake the sleeping khvcd */ static void hvc_kick(void) @@ -140,34 +262,6 @@ static void hvc_unthrottle(struct tty_struct *tty) hvc_kick(); } -/* - * Do not call this function with either the hvc_strucst_lock or the hvc_struct - * lock held. If successful, this function increments the kobject reference - * count against the target hvc_struct so it should be released when finished. - */ -struct hvc_struct *hvc_get_by_index(int index) -{ - struct hvc_struct *hp; - unsigned long flags; - - spin_lock(&hvc_structs_lock); - - list_for_each_entry(hp, &hvc_structs, next) { - spin_lock_irqsave(&hp->lock, flags); - if (hp->index == index) { - kobject_get(&hp->kobj); - spin_unlock_irqrestore(&hp->lock, flags); - spin_unlock(&hvc_structs_lock); - return hp; - } - spin_unlock_irqrestore(&hp->lock, flags); - } - hp = NULL; - - spin_unlock(&hvc_structs_lock); - return hp; -} - /* * The TTY interface won't be used until after the vio layer has exposed the vty * adapter to the kernel. @@ -577,14 +671,6 @@ static struct tty_operations hvc_ops = { .chars_in_buffer = hvc_chars_in_buffer, }; -char hvc_driver_name[] = "hvc_console"; - -static struct vio_device_id hvc_driver_table[] __devinitdata= { - {"serial", "hvterm1"}, - { NULL, } -}; -MODULE_DEVICE_TABLE(vio, hvc_driver_table); - /* callback when the kboject ref count reaches zero. */ static void destroy_hvc_struct(struct kobject *kobj) { @@ -674,6 +760,14 @@ static int __devexit hvc_remove(struct vio_dev *dev) return 0; } +char hvc_driver_name[] = "hvc_console"; + +static struct vio_device_id hvc_driver_table[] __devinitdata= { + {"serial", "hvterm1"}, + { NULL, } +}; +MODULE_DEVICE_TABLE(vio, hvc_driver_table); + static struct vio_driver hvc_vio_driver = { .name = hvc_driver_name, .id_table = hvc_driver_table, @@ -721,6 +815,7 @@ int __init hvc_init(void) return rc; } +module_init(hvc_init); /* This isn't particularily necessary due to this being a console driver but it * is nice to be thorough */ @@ -733,99 +828,4 @@ static void __exit hvc_exit(void) /* return tty_struct instances allocated in hvc_init(). */ put_tty_driver(hvc_driver); } - -/* - * Console APIs, NOT TTY. These APIs are available immediately when - * hvc_console_setup() finds adapters. - */ - -/* - * hvc_instantiate() is an early console discovery method which locates consoles - * prior to the vio subsystem discovering them. Hotplugged vty adapters do NOT - * get an hvc_instantiate() callback since the appear after early console init. - */ -int hvc_instantiate(uint32_t vtermno, int index) -{ - if (index < 0 || index >= MAX_NR_HVC_CONSOLES) - return -1; - - if (vtermnos[index] != -1) - return -1; - - vtermnos[index] = vtermno; - return 0; -} - -void hvc_console_print(struct console *co, const char *b, unsigned count) -{ - char c[16] __ALIGNED__; - unsigned i = 0, n = 0; - int r, donecr = 0; - - /* Console access attempt outside of acceptable console range. */ - if (co->index >= MAX_NR_HVC_CONSOLES) - return; - - /* This console adapter was removed so it is not useable. */ - if (vtermnos[co->index] < 0) - return; - - while (count > 0 || i > 0) { - if (count > 0 && i < sizeof(c)) { - if (b[n] == '\n' && !donecr) { - c[i++] = '\r'; - donecr = 1; - } else { - c[i++] = b[n++]; - donecr = 0; - --count; - } - } else { - r = hvc_put_chars(vtermnos[co->index], c, i); - if (r < 0) { - /* throw away chars on error */ - i = 0; - } else if (r > 0) { - i -= r; - if (i > 0) - memmove(c, c+r, i); - } - } - } -} - -static struct tty_driver *hvc_console_device(struct console *c, int *index) -{ - *index = c->index; - return hvc_driver; -} - -static int __init hvc_console_setup(struct console *co, char *options) -{ - return 0; -} - -struct console hvc_con_driver = { - .name = "hvc", - .write = hvc_console_print, - .device = hvc_console_device, - .setup = hvc_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -/* Early console initialization. Preceeds driver initialization. */ -static int __init hvc_console_init(void) -{ - int i; - - for (i=0; i Date: Thu, 7 Jul 2005 17:56:17 -0700 Subject: [PATCH] hvc_console: Match vio and console devices using vterm numbers Use the vterm numbers to match the vio devices being probed with the indices already allocated via the console initcall function hvc_find_vtys. The old code required hvc_find_vtys to "guess" the matching devices the vio subsystem would find and its probe order. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index f0a1456a597..4b776f4eb46 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -102,10 +102,11 @@ static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs); static DEFINE_SPINLOCK(hvc_structs_lock); /* - * This value is used to associate a tty->index value to a hvc_struct based - * upon order of exposure via hvc_probe(). + * This value is used to assign a tty->index value to a hvc_struct based + * upon order of exposure via hvc_probe(), when we can not match it to + * a console canidate registered with hvc_instantiate(). */ -static int hvc_count = -1; +static int last_hvc = -1; /* * Do not call this function with either the hvc_strucst_lock or the hvc_struct @@ -224,9 +225,10 @@ static int __init hvc_console_init(void) console_initcall(hvc_console_init); /* - * hvc_instantiate() is an early console discovery method which locates consoles - * prior to the vio subsystem discovering them. Hotplugged vty adapters do NOT - * get an hvc_instantiate() callback since the appear after early console init. + * hvc_instantiate() is an early console discovery method which locates + * consoles * prior to the vio subsystem discovering them. Hotplugged + * vty adapters do NOT get an hvc_instantiate() callback since they + * appear after early console init. */ int hvc_instantiate(uint32_t vtermno, int index) { @@ -237,6 +239,11 @@ int hvc_instantiate(uint32_t vtermno, int index) return -1; vtermnos[index] = vtermno; + + /* reserve all indices upto and including this index */ + if (last_hvc < index) + last_hvc = index; + return 0; } @@ -697,6 +704,7 @@ static int __devinit hvc_probe( const struct vio_device_id *id) { struct hvc_struct *hp; + int i; /* probed with invalid parameters. */ if (!dev || !id) @@ -717,7 +725,21 @@ static int __devinit hvc_probe( spin_lock_init(&hp->lock); spin_lock(&hvc_structs_lock); - hp->index = ++hvc_count; + + /* + * find index to use: + * see if this vterm id matches one registered for console. + */ + for (i=0; i < MAX_NR_HVC_CONSOLES; i++) + if (vtermnos[i] == hp->vtermno) + break; + + /* no matching slot, just use a counter */ + if (i >= MAX_NR_HVC_CONSOLES) + i = ++last_hvc; + + hp->index = i; + list_add_tail(&(hp->next), &hvc_structs); spin_unlock(&hvc_structs_lock); -- cgit v1.2.3 From 8b67f8c177a642b35b7a05f530c12ef2834ef182 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 7 Jul 2005 17:56:18 -0700 Subject: [PATCH] hvc_console: Dont always kick the poll thread in interrupt Have the hvc console code try to pull characters immediately when receiving an interrupt, and kick the poll thread only if the immediate poll indicates it needed a call back to do more work. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 4b776f4eb46..46508a73706 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -254,13 +254,17 @@ static void hvc_kick(void) wake_up_process(hvc_task); } +static int hvc_poll(struct hvc_struct *hp); + /* * NOTE: This API isn't used if the console adapter doesn't support interrupts. * In this case the console is poll driven. */ static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { - hvc_kick(); + /* if hvc_poll request a repoll, then kick the hvcd thread */ + if (hvc_poll(dev_instance)) + hvc_kick(); return IRQ_HANDLED; } @@ -598,8 +602,8 @@ static int hvc_poll(struct hvc_struct *hp) /* * Account for the total amount read in one loop, and if above - * 64 bytes, we do a quick schedule loop to let the tty grok the - * data and eventually throttle us. + * 64 bytes, we do a quick schedule loop to let the tty grok + * the data and eventually throttle us. */ read_total += n; if (read_total >= 64) { -- cgit v1.2.3 From 2b9e0bac9419404a2d210ccaffaec442fe63338e Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 7 Jul 2005 17:56:19 -0700 Subject: [PATCH] hvc_console: MAGIC_SYSRQ should only be on console channel Guard the MAGIC_SYSRQ ^O to be just on the console channel. Make the other channels more transparent. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 46508a73706..e7362c195b1 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -584,14 +584,17 @@ static int hvc_poll(struct hvc_struct *hp) } for (i = 0; i < n; ++i) { #ifdef CONFIG_MAGIC_SYSRQ - /* Handle the SysRq Hack */ - if (buf[i] == '\x0f') { /* ^O -- should support a sequence */ - sysrq_pressed = 1; - continue; - } else if (sysrq_pressed) { - handle_sysrq(buf[i], NULL, tty); - sysrq_pressed = 0; - continue; + if (hp->index == hvc_con_driver.index) { + /* Handle the SysRq Hack */ + /* XXX should support a sequence */ + if (buf[i] == '\x0f') { /* ^O */ + sysrq_pressed = 1; + continue; + } else if (sysrq_pressed) { + handle_sysrq(buf[i], NULL, tty); + sysrq_pressed = 0; + continue; + } } #endif /* CONFIG_MAGIC_SYSRQ */ tty_insert_flip_char(tty, buf[i], 0); -- cgit v1.2.3 From 320da0d23ed1f82a896e0cfc1549a896d267777a Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 7 Jul 2005 17:56:20 -0700 Subject: [PATCH] hvc_console: Unregister the console in the exit routine. Be thorough in our exit routine, since it says it is there to be so. Unregistering without registering is safe (checked in 2.6.10). Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index e7362c195b1..0f9d356d3bd 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -846,8 +846,9 @@ int __init hvc_init(void) } module_init(hvc_init); -/* This isn't particularily necessary due to this being a console driver but it - * is nice to be thorough */ +/* This isn't particularily necessary due to this being a console driver + * but it is nice to be thorough. + */ static void __exit hvc_exit(void) { kthread_stop(hvc_task); @@ -856,5 +857,6 @@ static void __exit hvc_exit(void) tty_unregister_driver(hvc_driver); /* return tty_struct instances allocated in hvc_init(). */ put_tty_driver(hvc_driver); + unregister_console(&hvc_con_driver); } module_exit(hvc_exit); -- cgit v1.2.3 From e51d8c90a5ead16810302b2dc5127724c9045e77 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 7 Jul 2005 17:56:21 -0700 Subject: [PATCH] hvc_console: Add missing include hvc_console checks MAGIC_SYSRQ and XMON config vars. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 0f9d356d3bd..31980994fea 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -22,6 +22,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include -- cgit v1.2.3 From 5f6d9c072df162a8601a09e6c63fd0e4f5aecd06 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 7 Jul 2005 17:56:21 -0700 Subject: [PATCH] hvc_console: remove num_vterms and some dead code num_vterms hasn't been used since the hotplug support went in. Also, remove a dead code line from a list_for_each_entry conversion. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 31980994fea..fd753250425 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -146,8 +146,6 @@ struct hvc_struct *hvc_get_by_index(int index) */ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES]; -/* Used for accounting purposes */ -static int num_vterms = 0; /* * Console APIs, NOT TTY. These APIs are available immediately when @@ -219,7 +217,7 @@ static int __init hvc_console_init(void) for (i=0; i Date: Thu, 7 Jul 2005 17:56:22 -0700 Subject: [PATCH] hvc_console: Statically initialize the vtermnos array Statically initialize the vtermnos array. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index fd753250425..de849f571ea 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -144,8 +144,8 @@ struct hvc_struct *hvc_get_by_index(int index) * console interfaces but can still be used as a tty device. This has to be * static because kmalloc will not work during early console init. */ -static uint32_t vtermnos[MAX_NR_HVC_CONSOLES]; - +static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = + {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1}; /* * Console APIs, NOT TTY. These APIs are available immediately when @@ -213,10 +213,6 @@ struct console hvc_con_driver = { /* Early console initialization. Preceeds driver initialization. */ static int __init hvc_console_init(void) { - int i; - - for (i=0; i Date: Thu, 7 Jul 2005 17:56:23 -0700 Subject: [PATCH] hvc_console: Add some sanity checks Check if a vterm was registered before accepting it as a console. Check that a slot hasn't been probed with a tty in hvc_instantiate(). Check that a slot hasn't been free'ed when handing out console device. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index de849f571ea..7bc65a76dfc 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -192,12 +192,21 @@ void hvc_console_print(struct console *co, const char *b, unsigned count) static struct tty_driver *hvc_console_device(struct console *c, int *index) { + if (vtermnos[c->index] == -1) + return NULL; + *index = c->index; return hvc_driver; } static int __init hvc_console_setup(struct console *co, char *options) { + if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES) + return -ENODEV; + + if (vtermnos[co->index] == -1) + return -ENODEV; + return 0; } @@ -227,12 +236,21 @@ console_initcall(hvc_console_init); */ int hvc_instantiate(uint32_t vtermno, int index) { + struct hvc_struct *hp; + if (index < 0 || index >= MAX_NR_HVC_CONSOLES) return -1; if (vtermnos[index] != -1) return -1; + /* make sure no no tty has been registerd in this index */ + hp = hvc_get_by_index(index); + if (hp) { + kobject_put(&hp->kobj); + return -1; + } + vtermnos[index] = vtermno; /* reserve all indices upto and including this index */ -- cgit v1.2.3 From d5ee257c3342185ba8ab642d125d192eb99ea8f2 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 7 Jul 2005 17:56:24 -0700 Subject: [PATCH] hvc_console: Separate hvc_console and vio code Separate the console setup routines of the hvc_console and the vio layer. Remove the call to find_init_vty from hvc_console.c. Fail the setup routine if the console doesn't exist, but register the console again when the specified channel is instantiated. This scheme maintains the print buffer semantics while eliminating callout and call back for the console code. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 7bc65a76dfc..d59c642f965 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -219,10 +219,23 @@ struct console hvc_con_driver = { .index = -1, }; -/* Early console initialization. Preceeds driver initialization. */ +/* + * Early console initialization. Preceeds driver initialization. + * + * (1) we are first, and the user specified another driver + * -- index will remain -1 + * (2) we are first and the user specified no driver + * -- index will be set to 0, then we will fail setup. + * (3) we are first and the user specified our driver + * -- index will be set to user specified driver, and we will fail + * (4) we are after driver, and this initcall will register us + * -- if the user didn't specify a driver then the console will match + * + * Note that for cases 2 and 3, we will match later when the io driver + * calls hvc_instantiate() and call register again. + */ static int __init hvc_console_init(void) { - hvc_find_vtys(); register_console(&hvc_con_driver); return 0; } @@ -257,6 +270,13 @@ int hvc_instantiate(uint32_t vtermno, int index) if (last_hvc < index) last_hvc = index; + /* if this index is what the user requested, then register + * now (setup won't fail at this point). It's ok to just + * call register again if previously .setup failed. + */ + if (index == hvc_con_driver.index) + register_console(&hvc_con_driver); + return 0; } -- cgit v1.2.3 From acad9559f1054487292eb10d7bb81f256e9d8f2d Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 7 Jul 2005 17:56:24 -0700 Subject: [PATCH] hvc_console: Separate hvc_console and vio code 2 Remove all the vio device driver code from hvc_console.c This will allow us to separate hvsi, hvc, and allow hvc_console to be used without the ppc64 vio layer. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Makefile | 2 +- drivers/char/hvc_console.c | 50 ++++-------------- drivers/char/hvc_vio.c | 125 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 40 deletions(-) create mode 100644 drivers/char/hvc_vio.c (limited to 'drivers') diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 1aff819f383..08f69287ea3 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -40,7 +40,7 @@ obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_SX) += sx.o generic_serial.o obj-$(CONFIG_RIO) += rio/ generic_serial.o -obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvsi.o +obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvc_vio.o hvsi.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_MMTIMER) += mmtimer.o diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index d59c642f965..df282cc9a7a 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -41,7 +41,6 @@ #include #include #include -#include #define HVC_MAJOR 229 #define HVC_MINOR 0 @@ -90,7 +89,6 @@ struct hvc_struct { int irq; struct list_head next; struct kobject kobj; /* ref count & hvc_struct lifetime */ - struct vio_dev *vdev; }; /* dynamic list of hvc_struct instances */ @@ -279,6 +277,7 @@ int hvc_instantiate(uint32_t vtermno, int index) return 0; } +EXPORT_SYMBOL(hvc_instantiate); /* Wake the sleeping khvcd */ static void hvc_kick(void) @@ -738,26 +737,19 @@ static struct kobj_type hvc_kobj_type = { .release = destroy_hvc_struct, }; -static int __devinit hvc_probe( - struct vio_dev *dev, - const struct vio_device_id *id) +struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq) { struct hvc_struct *hp; int i; - /* probed with invalid parameters. */ - if (!dev || !id) - return -EPERM; - hp = kmalloc(sizeof(*hp), GFP_KERNEL); if (!hp) - return -ENOMEM; + return ERR_PTR(-ENOMEM); memset(hp, 0x00, sizeof(*hp)); - hp->vtermno = dev->unit_address; - hp->vdev = dev; - hp->vdev->dev.driver_data = hp; - hp->irq = dev->irq; + + hp->vtermno = vtermno; + hp->irq = irq; kobject_init(&hp->kobj); hp->kobj.ktype = &hvc_kobj_type; @@ -782,12 +774,12 @@ static int __devinit hvc_probe( list_add_tail(&(hp->next), &hvc_structs); spin_unlock(&hvc_structs_lock); - return 0; + return hp; } +EXPORT_SYMBOL(hvc_alloc); -static int __devexit hvc_remove(struct vio_dev *dev) +int __devexit hvc_remove(struct hvc_struct *hp) { - struct hvc_struct *hp = dev->dev.driver_data; unsigned long flags; struct kobject *kobjp; struct tty_struct *tty; @@ -820,28 +812,12 @@ static int __devexit hvc_remove(struct vio_dev *dev) tty_hangup(tty); return 0; } - -char hvc_driver_name[] = "hvc_console"; - -static struct vio_device_id hvc_driver_table[] __devinitdata= { - {"serial", "hvterm1"}, - { NULL, } -}; -MODULE_DEVICE_TABLE(vio, hvc_driver_table); - -static struct vio_driver hvc_vio_driver = { - .name = hvc_driver_name, - .id_table = hvc_driver_table, - .probe = hvc_probe, - .remove = hvc_remove, -}; +EXPORT_SYMBOL(hvc_remove); /* Driver initialization. Follow console initialization. This is where the TTY * interfaces start to become available. */ int __init hvc_init(void) { - int rc; - /* We need more than hvc_count adapters due to hotplug additions. */ hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); if (!hvc_driver) @@ -870,10 +846,7 @@ int __init hvc_init(void) return -EIO; } - /* Register as a vio device to receive callbacks */ - rc = vio_register_driver(&hvc_vio_driver); - - return rc; + return 0; } module_init(hvc_init); @@ -884,7 +857,6 @@ static void __exit hvc_exit(void) { kthread_stop(hvc_task); - vio_unregister_driver(&hvc_vio_driver); tty_unregister_driver(hvc_driver); /* return tty_struct instances allocated in hvc_init(). */ put_tty_driver(hvc_driver); diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c new file mode 100644 index 00000000000..d2928f90ab5 --- /dev/null +++ b/drivers/char/hvc_vio.c @@ -0,0 +1,125 @@ +/* + * vio driver interface to hvc_console.c + * + * This code was moved here to allow the remaing code to be reused as a + * generic polling mode with semi-reliable transport driver core to the + * console and tty subsystems. + * + * + * Copyright (C) 2001 Anton Blanchard , IBM + * Copyright (C) 2001 Paul Mackerras , IBM + * Copyright (C) 2004 Benjamin Herrenschmidt , IBM Corp. + * Copyright (C) 2004 IBM Corporation + * + * Additional Author(s): + * Ryan S. Arnold + * + * 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 + +char hvc_driver_name[] = "hvc_console"; + +static struct vio_device_id hvc_driver_table[] __devinitdata = { + {"serial", "hvterm1"}, + { NULL, } +}; +MODULE_DEVICE_TABLE(vio, hvc_driver_table); + +static int __devinit hvc_vio_probe(struct vio_dev *vdev, + const struct vio_device_id *id) +{ + struct hvc_struct *hp; + + /* probed with invalid parameters. */ + if (!vdev || !id) + return -EPERM; + + hp = hvc_alloc(vdev->unit_address, vdev->irq); + if (IS_ERR(hp)) + return PTR_ERR(hp); + dev_set_drvdata(&vdev->dev, hp); + + return 0; +} + +static int __devexit hvc_vio_remove(struct vio_dev *vdev) +{ + struct hvc_struct *hp = dev_get_drvdata(&vdev->dev); + + return hvc_remove(hp); +} + +static struct vio_driver hvc_vio_driver = { + .name = hvc_driver_name, + .id_table = hvc_driver_table, + .probe = hvc_vio_probe, + .remove = hvc_vio_remove, + .driver = { + .owner = THIS_MODULE, + } +}; + +static int hvc_vio_init(void) +{ + int rc; + + /* Register as a vio device to receive callbacks */ + rc = vio_register_driver(&hvc_vio_driver); + + return rc; +} +module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */ + +static void hvc_vio_exit(void) +{ + vio_unregister_driver(&hvc_vio_driver); +} +module_exit(hvc_vio_exit); + +/* the device tree order defines our numbering */ +static int hvc_find_vtys(void) +{ + struct device_node *vty; + int num_found = 0; + + for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; + vty = of_find_node_by_name(vty, "vty")) { + uint32_t *vtermno; + + /* We have statically defined space for only a certain number + * of console adapters. + */ + if (num_found >= MAX_NR_HVC_CONSOLES) + break; + + vtermno = (uint32_t *)get_property(vty, "reg", NULL); + if (!vtermno) + continue; + + if (device_is_compatible(vty, "hvterm1")) { + hvc_instantiate(*vtermno, num_found); + ++num_found; + } + } + + return num_found; +} +console_initcall(hvc_find_vtys); -- cgit v1.2.3 From 030ffad23fb28fc29608a3bc21f0c3b88bf28592 Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 7 Jul 2005 17:56:25 -0700 Subject: [PATCH] hvc_console: Register ops when setting up hvc_console When registering the hvc console port, register a list of ops (read and write) to go with it, instead of calling fixed function names. This allows different ports to encode the data differently. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_console.c | 21 +++++++++++++-------- drivers/char/hvc_vio.c | 9 +++++++-- 2 files changed, 20 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index df282cc9a7a..cddb789902d 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -85,6 +85,7 @@ struct hvc_struct { char outbuf[N_OUTBUF] __ALIGNED__; int n_outbuf; uint32_t vtermno; + struct hv_ops *ops; int irq_requested; int irq; struct list_head next; @@ -142,6 +143,7 @@ struct hvc_struct *hvc_get_by_index(int index) * console interfaces but can still be used as a tty device. This has to be * static because kmalloc will not work during early console init. */ +static struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1}; @@ -154,14 +156,14 @@ void hvc_console_print(struct console *co, const char *b, unsigned count) { char c[16] __ALIGNED__; unsigned i = 0, n = 0; - int r, donecr = 0; + int r, donecr = 0, index = co->index; /* Console access attempt outside of acceptable console range. */ - if (co->index >= MAX_NR_HVC_CONSOLES) + if (index >= MAX_NR_HVC_CONSOLES) return; /* This console adapter was removed so it is not useable. */ - if (vtermnos[co->index] < 0) + if (vtermnos[index] < 0) return; while (count > 0 || i > 0) { @@ -175,7 +177,7 @@ void hvc_console_print(struct console *co, const char *b, unsigned count) --count; } } else { - r = hvc_put_chars(vtermnos[co->index], c, i); + r = cons_ops[index]->put_chars(vtermnos[index], c, i); if (r < 0) { /* throw away chars on error */ i = 0; @@ -245,7 +247,7 @@ console_initcall(hvc_console_init); * vty adapters do NOT get an hvc_instantiate() callback since they * appear after early console init. */ -int hvc_instantiate(uint32_t vtermno, int index) +int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) { struct hvc_struct *hp; @@ -263,6 +265,7 @@ int hvc_instantiate(uint32_t vtermno, int index) } vtermnos[index] = vtermno; + cons_ops[index] = ops; /* reserve all indices upto and including this index */ if (last_hvc < index) @@ -466,7 +469,7 @@ static void hvc_push(struct hvc_struct *hp) { int n; - n = hvc_put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); + n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); if (n <= 0) { if (n == 0) return; @@ -604,7 +607,7 @@ static int hvc_poll(struct hvc_struct *hp) break; } - n = hvc_get_chars(hp->vtermno, buf, count); + n = hp->ops->get_chars(hp->vtermno, buf, count); if (n <= 0) { /* Hangup the tty when disconnected from host */ if (n == -EPIPE) { @@ -737,7 +740,8 @@ static struct kobj_type hvc_kobj_type = { .release = destroy_hvc_struct, }; -struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq) +struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, + struct hv_ops *ops) { struct hvc_struct *hp; int i; @@ -750,6 +754,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq) hp->vtermno = vtermno; hp->irq = irq; + hp->ops = ops; kobject_init(&hp->kobj); hp->kobj.ktype = &hvc_kobj_type; diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index d2928f90ab5..430a2c284ad 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -43,6 +43,11 @@ static struct vio_device_id hvc_driver_table[] __devinitdata = { }; MODULE_DEVICE_TABLE(vio, hvc_driver_table); +static struct hv_ops hvc_get_put_ops = { + .get_chars = hvc_get_chars, + .put_chars = hvc_put_chars, +}; + static int __devinit hvc_vio_probe(struct vio_dev *vdev, const struct vio_device_id *id) { @@ -52,7 +57,7 @@ static int __devinit hvc_vio_probe(struct vio_dev *vdev, if (!vdev || !id) return -EPERM; - hp = hvc_alloc(vdev->unit_address, vdev->irq); + hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops); if (IS_ERR(hp)) return PTR_ERR(hp); dev_set_drvdata(&vdev->dev, hp); @@ -115,7 +120,7 @@ static int hvc_find_vtys(void) continue; if (device_is_compatible(vty, "hvterm1")) { - hvc_instantiate(*vtermno, num_found); + hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops); ++num_found; } } -- cgit v1.2.3 From 70b234a40107596a713e9981c643f2717e31463f Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 7 Jul 2005 17:56:26 -0700 Subject: [PATCH] hvc_console: Separate the NUL character filtering from get_hvc_chars Separate the NUL character filtering from get_hvc_chars. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvc_vio.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index 430a2c284ad..60bb9152b83 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -43,8 +43,30 @@ static struct vio_device_id hvc_driver_table[] __devinitdata = { }; MODULE_DEVICE_TABLE(vio, hvc_driver_table); +static int filtered_get_chars(uint32_t vtermno, char *buf, int count) +{ + unsigned long got; + int i; + + got = hvc_get_chars(vtermno, buf, count); + + /* + * Work around a HV bug where it gives us a null + * after every \r. -- paulus + */ + for (i = 1; i < got; ++i) { + if (buf[i] == 0 && buf[i-1] == '\r') { + --got; + if (i < got) + memmove(&buf[i], &buf[i+1], + got - i); + } + } + return got; +} + static struct hv_ops hvc_get_put_ops = { - .get_chars = hvc_get_chars, + .get_chars = filtered_get_chars, .put_chars = hvc_put_chars, }; -- cgit v1.2.3 From 88de0be0c7335650326a1236bf6ca1ed265c0a1c Mon Sep 17 00:00:00 2001 From: Milton Miller Date: Thu, 7 Jul 2005 17:56:27 -0700 Subject: [PATCH] hvc_console: Use hvc_get_chars in hvsi code Now that hvc_get_chars doesn't strip NULs, hvsi doesn't have to duplicate it. Signed-off-by: Milton Miller Signed-off-by: Anton Blanchard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hvsi.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index f1f1192ba2b..a22aa940e01 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -291,15 +291,13 @@ static void dump_packet(uint8_t *packet) dump_hex(packet, header->len); } -/* can't use hvc_get_chars because that strips CRs */ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count) { unsigned long got; - if (plpar_hcall(H_GET_TERM_CHAR, hp->vtermno, 0, 0, 0, &got, - (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) - return got; - return 0; + got = hvc_get_chars(hp->vtermno, buf, count); + + return got; } static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, -- cgit v1.2.3 From 2a569579be87b5ba61f9b6c54fd5f9f307c53962 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Thu, 7 Jul 2005 17:56:40 -0700 Subject: [PATCH] pm: more u32 vs. pm_message_t fixes Few more u32 vs. pm_message_t fixes. Signed-off-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/message/fusion/mptbase.c | 14 +------------- drivers/message/fusion/mptscsih.h | 2 +- drivers/net/skge.c | 4 ++-- drivers/net/typhoon.c | 6 +++--- drivers/pci/pcie/portdrv_core.c | 6 +++--- drivers/video/savage/savagefb_driver.c | 2 +- 6 files changed, 11 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 8b623278ccd..ffbe6f4720e 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1363,19 +1363,7 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state) u32 device_state; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - switch(state) - { - case 1: /* S1 */ - device_state=1; /* D1 */; - break; - case 3: /* S3 */ - case 4: /* S4 */ - device_state=3; /* D3 */; - break; - default: - return -EAGAIN /*FIXME*/; - break; - } + device_state=pci_choose_state(pdev, state); printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n", diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 5ea89bf0df1..debb8ac5954 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -84,7 +84,7 @@ extern void mptscsih_remove(struct pci_dev *); extern void mptscsih_shutdown(struct pci_dev *); #ifdef CONFIG_PM -extern int mptscsih_suspend(struct pci_dev *pdev, u32 state); +extern int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state); extern int mptscsih_resume(struct pci_dev *pdev); #endif extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 3dbb1cb09ed..5cacc7ad9e7 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3259,7 +3259,7 @@ static void __devexit skge_remove(struct pci_dev *pdev) } #ifdef CONFIG_PM -static int skge_suspend(struct pci_dev *pdev, u32 state) +static int skge_suspend(struct pci_dev *pdev, pm_message_t state) { struct skge_hw *hw = pci_get_drvdata(pdev); int i, wol = 0; @@ -3279,7 +3279,7 @@ static int skge_suspend(struct pci_dev *pdev, u32 state) } pci_save_state(pdev); - pci_enable_wake(pdev, state, wol); + pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 0b5ca253796..ecfa6f8805c 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1906,9 +1906,9 @@ typhoon_sleep(struct typhoon *tp, pci_power_t state, u16 events) */ netif_carrier_off(tp->dev); - pci_enable_wake(tp->pdev, pci_choose_state(pdev, state), 1); + pci_enable_wake(tp->pdev, state, 1); pci_disable_device(pdev); - return pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return pci_set_power_state(pdev, state); } static int @@ -2274,7 +2274,7 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state) goto need_resume; } - if(typhoon_sleep(tp, state, tp->wol_events) < 0) { + if(typhoon_sleep(tp, pci_choose_state(pdev, state), tp->wol_events) < 0) { printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name); goto need_resume; } diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 4db69982876..393e0cee91a 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -325,7 +325,7 @@ int pcie_port_device_register(struct pci_dev *dev) static int suspend_iter(struct device *dev, void *data) { struct pcie_port_service_driver *service_driver; - u32 state = (u32)data; + pm_message_t state = * (pm_message_t *) data; if ((dev->bus == &pcie_port_bus_type) && (dev->driver)) { @@ -336,9 +336,9 @@ static int suspend_iter(struct device *dev, void *data) return 0; } -int pcie_port_device_suspend(struct pci_dev *dev, u32 state) +int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state) { - device_for_each_child(&dev->dev, (void *)state, suspend_iter); + device_for_each_child(&dev->dev, &state, suspend_iter); return 0; } diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 8fadcdae6f4..f4633d1891f 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -2113,7 +2113,7 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state) printk(KERN_DEBUG "state: %u\n", state); acquire_console_sem(); - fb_set_suspend(info, state); + fb_set_suspend(info, pci_choose_state(dev, state)); savage_disable_mmio(par); release_console_sem(); -- cgit v1.2.3 From e00d9967e3addea86dded46deefc5daec5d52e5a Mon Sep 17 00:00:00 2001 From: Bernard Blackham Date: Thu, 7 Jul 2005 17:56:42 -0700 Subject: [PATCH] pm: fix u32 vs. pm_message_t confusion in cpufreq Fix u32 vs pm_message_t confusion in cpufreq. Signed-off-by: Bernard Blackham Signed-off-by: Pavel Machek Cc: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/cpufreq/cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index bf62dfe4976..7a7859dd0d9 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -869,7 +869,7 @@ EXPORT_SYMBOL(cpufreq_get); * cpufreq_suspend - let the low level driver prepare for suspend */ -static int cpufreq_suspend(struct sys_device * sysdev, u32 state) +static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) { int cpu = sysdev->id; unsigned int ret = 0; @@ -897,7 +897,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, u32 state) } if (cpufreq_driver->suspend) { - ret = cpufreq_driver->suspend(cpu_policy, state); + ret = cpufreq_driver->suspend(cpu_policy, pmsg); if (ret) { printk(KERN_ERR "cpufreq: suspend failed in ->suspend " "step on CPU %u\n", cpu_policy->cpu); -- cgit v1.2.3 From d6afe27bfff30fbec2cca6ad5626c22f4094d770 Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Thu, 7 Jul 2005 17:56:55 -0700 Subject: [PATCH] tty output lossage fix The patch fixes a few corner cases around tty line editing with very long input lines: - n_tty_receive_char(): don't simply drop eol characters, otherwise canon_data isn't increased and the reader isn't woken up. - n_tty_receive_room(): If there is no newline pending and the edit buffer is full, allow only a single character to be written (until eol is found and the line is flushed), so characters from the next line aren't dropped. - write_chan(): if an incomplete line was written, continue writing until write() returns 0, otherwise it might not write the eol character to flush the line and the writer goes to sleep without ever being woken up. BTW the core problem is that part of this should be handled in the receive_buf path, but for this it has to return the number of written characters, as the amount of written characters may not be the same as the amount of characters going into the write buffer, so the receive_room() usage in pty_write() is not really reliable. Alan said: The problem looks valid. The behaviour of 'traditional unix' appears to be the following If you exceed the line limit then beep and drop the character Always allow EOL to complete a canonical line input Always do signal/control processing if enabled Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/n_tty.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index edba5a35bf2..09103b3d8f0 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -770,10 +770,8 @@ send_signal: } if (c == '\n') { if (L_ECHO(tty) || L_ECHONL(tty)) { - if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) put_char('\a', tty); - return; - } opost('\n', tty); } goto handle_newline; @@ -790,10 +788,8 @@ send_signal: * XXX are EOL_CHAR and EOL2_CHAR echoed?!? */ if (L_ECHO(tty)) { - if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) put_char('\a', tty); - return; - } /* Record the column of first canon char. */ if (tty->canon_head == tty->read_head) tty->canon_column = tty->column; @@ -862,12 +858,9 @@ static int n_tty_receive_room(struct tty_struct *tty) * that erase characters will be handled. Other excess * characters will be beeped. */ - if (tty->icanon && !tty->canon_data) - return N_TTY_BUF_SIZE; - - if (left > 0) - return left; - return 0; + if (left <= 0) + left = tty->icanon && !tty->canon_data; + return left; } /** @@ -1473,13 +1466,17 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file, if (tty->driver->flush_chars) tty->driver->flush_chars(tty); } else { - c = tty->driver->write(tty, b, nr); - if (c < 0) { - retval = c; - goto break_out; + while (nr > 0) { + c = tty->driver->write(tty, b, nr); + if (c < 0) { + retval = c; + goto break_out; + } + if (!c) + break; + b += c; + nr -= c; } - b += c; - nr -= c; } if (!nr) break; -- cgit v1.2.3 From 6c036527a630720063b67d9a65455e8caca2c8fa Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Thu, 7 Jul 2005 17:56:59 -0700 Subject: [PATCH] mostly_read data section Add a new section called ".data.read_mostly" for data items that are read frequently and rarely written to like cpumaps etc. If these maps are placed in the .data section then these frequenly read items may end up in cachelines with data is is frequently updated. In that case all processors in an SMP system must needlessly reload the cachelines again and again containing elements of those frequently used variables. The ability to share these cachelines will allow each cpu in an SMP system to keep local copies of those shared cachelines thereby optimizing performance. Signed-off-by: Alok N Kataria Signed-off-by: Shobhit Dayal Signed-off-by: Christoph Lameter Signed-off-by: Shai Fultheim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/random.c b/drivers/char/random.c index 460b5d475ed..6b11d6b2129 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -271,7 +271,7 @@ static int random_write_wakeup_thresh = 128; * samples to avoid wasting CPU time and reduce lock contention. */ -static int trickle_thresh = INPUT_POOL_WORDS * 28; +static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; static DEFINE_PER_CPU(int, trickle_count) = 0; -- cgit v1.2.3 From 8f96c95680bfe66ff00c91859d4c73edf539b854 Mon Sep 17 00:00:00 2001 From: "KAMBAROV, ZAUR" Date: Thu, 7 Jul 2005 17:57:05 -0700 Subject: [PATCH] coverity: fix fbsysfs null pointer check Correctly test for a null pointer before going and dereferencing it. This defect was found automatically by Coverity Prevent, a static analysis tool. Signed-off-by: Zaur Kambarov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/fbsysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 7dfbf39b4ed..ddc9443254d 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -256,7 +256,7 @@ static ssize_t show_cmap(struct class_device *class_device, char *buf) unsigned int offset = 0, i; if (!fb_info->cmap.red || !fb_info->cmap.blue || - fb_info->cmap.green || fb_info->cmap.transp) + !fb_info->cmap.green || !fb_info->cmap.transp) return -EINVAL; for (i = 0; i < fb_info->cmap.len; i++) { -- cgit v1.2.3 From e2773c062e41f710d8ef1e8a790c7e558aff663d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:10 -0700 Subject: [PATCH] IB uverbs: core API extensions First of a series of patches which add support for direct userspace access to InfiniBand hardware -- so-called "userspace verbs." I believe these patches are ready to merge, but a final review would be useful. These patches should incorporate all of the feedback from the discussion when I posted an earlier version back in April (see http://lkml.org/lkml/2005/4/4/267 for the start of the thread). In particular, memory pinned for use by userspace is accounted for in current->mm->vm_locked and requests to pin memory are checked against RLIMIT_MEMLOCK. This patch: Modify the ib_verbs.h header file with changes required for InfiniBand userspace verbs support. We add a few structures to keep track of userspace context, and extend the driver API so that low-level drivers know when they're creating resources that will be used from userspace. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/include/ib_verbs.h | 124 +++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/include/ib_verbs.h b/drivers/infiniband/include/ib_verbs.h index cf01f044a22..e5bd9a10c20 100644 --- a/drivers/infiniband/include/ib_verbs.h +++ b/drivers/infiniband/include/ib_verbs.h @@ -4,6 +4,7 @@ * Copyright (c) 2004 Intel Corporation. All rights reserved. * Copyright (c) 2004 Topspin Corporation. All rights reserved. * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -41,7 +42,10 @@ #include #include + #include +#include +#include union ib_gid { u8 raw[16]; @@ -544,7 +548,7 @@ struct ib_send_wr { int num_sge; enum ib_wr_opcode opcode; int send_flags; - u32 imm_data; + __be32 imm_data; union { struct { u64 remote_addr; @@ -618,29 +622,86 @@ struct ib_fmr_attr { u8 page_size; }; +struct ib_ucontext { + struct ib_device *device; + struct list_head pd_list; + struct list_head mr_list; + struct list_head mw_list; + struct list_head cq_list; + struct list_head qp_list; + struct list_head srq_list; + struct list_head ah_list; + spinlock_t lock; +}; + +struct ib_uobject { + u64 user_handle; /* handle given to us by userspace */ + struct ib_ucontext *context; /* associated user context */ + struct list_head list; /* link to context's list */ + u32 id; /* index into kernel idr */ +}; + +struct ib_umem { + unsigned long user_base; + unsigned long virt_base; + size_t length; + int offset; + int page_size; + int writable; + struct list_head chunk_list; +}; + +struct ib_umem_chunk { + struct list_head list; + int nents; + int nmap; + struct scatterlist page_list[0]; +}; + +struct ib_udata { + void __user *inbuf; + void __user *outbuf; + size_t inlen; + size_t outlen; +}; + +#define IB_UMEM_MAX_PAGE_CHUNK \ + ((PAGE_SIZE - offsetof(struct ib_umem_chunk, page_list)) / \ + ((void *) &((struct ib_umem_chunk *) 0)->page_list[1] - \ + (void *) &((struct ib_umem_chunk *) 0)->page_list[0])) + +struct ib_umem_object { + struct ib_uobject uobject; + struct ib_umem umem; +}; + struct ib_pd { - struct ib_device *device; - atomic_t usecnt; /* count all resources */ + struct ib_device *device; + struct ib_uobject *uobject; + atomic_t usecnt; /* count all resources */ }; struct ib_ah { struct ib_device *device; struct ib_pd *pd; + struct ib_uobject *uobject; }; typedef void (*ib_comp_handler)(struct ib_cq *cq, void *cq_context); struct ib_cq { - struct ib_device *device; - ib_comp_handler comp_handler; - void (*event_handler)(struct ib_event *, void *); - void * cq_context; - int cqe; - atomic_t usecnt; /* count number of work queues */ + struct ib_device *device; + struct ib_uobject *uobject; + ib_comp_handler comp_handler; + void (*event_handler)(struct ib_event *, void *); + void * cq_context; + int cqe; + atomic_t usecnt; /* count number of work queues */ }; struct ib_srq { struct ib_device *device; + struct ib_uobject *uobject; struct ib_pd *pd; void *srq_context; atomic_t usecnt; @@ -652,6 +713,7 @@ struct ib_qp { struct ib_cq *send_cq; struct ib_cq *recv_cq; struct ib_srq *srq; + struct ib_uobject *uobject; void (*event_handler)(struct ib_event *, void *); void *qp_context; u32 qp_num; @@ -659,16 +721,18 @@ struct ib_qp { }; struct ib_mr { - struct ib_device *device; - struct ib_pd *pd; - u32 lkey; - u32 rkey; - atomic_t usecnt; /* count number of MWs */ + struct ib_device *device; + struct ib_pd *pd; + struct ib_uobject *uobject; + u32 lkey; + u32 rkey; + atomic_t usecnt; /* count number of MWs */ }; struct ib_mw { struct ib_device *device; struct ib_pd *pd; + struct ib_uobject *uobject; u32 rkey; }; @@ -737,7 +801,14 @@ struct ib_device { int (*modify_port)(struct ib_device *device, u8 port_num, int port_modify_mask, struct ib_port_modify *port_modify); - struct ib_pd * (*alloc_pd)(struct ib_device *device); + struct ib_ucontext * (*alloc_ucontext)(struct ib_device *device, + struct ib_udata *udata); + int (*dealloc_ucontext)(struct ib_ucontext *context); + int (*mmap)(struct ib_ucontext *context, + struct vm_area_struct *vma); + struct ib_pd * (*alloc_pd)(struct ib_device *device, + struct ib_ucontext *context, + struct ib_udata *udata); int (*dealloc_pd)(struct ib_pd *pd); struct ib_ah * (*create_ah)(struct ib_pd *pd, struct ib_ah_attr *ah_attr); @@ -747,7 +818,8 @@ struct ib_device { struct ib_ah_attr *ah_attr); int (*destroy_ah)(struct ib_ah *ah); struct ib_qp * (*create_qp)(struct ib_pd *pd, - struct ib_qp_init_attr *qp_init_attr); + struct ib_qp_init_attr *qp_init_attr, + struct ib_udata *udata); int (*modify_qp)(struct ib_qp *qp, struct ib_qp_attr *qp_attr, int qp_attr_mask); @@ -762,8 +834,9 @@ struct ib_device { int (*post_recv)(struct ib_qp *qp, struct ib_recv_wr *recv_wr, struct ib_recv_wr **bad_recv_wr); - struct ib_cq * (*create_cq)(struct ib_device *device, - int cqe); + struct ib_cq * (*create_cq)(struct ib_device *device, int cqe, + struct ib_ucontext *context, + struct ib_udata *udata); int (*destroy_cq)(struct ib_cq *cq); int (*resize_cq)(struct ib_cq *cq, int *cqe); int (*poll_cq)(struct ib_cq *cq, int num_entries, @@ -780,6 +853,10 @@ struct ib_device { int num_phys_buf, int mr_access_flags, u64 *iova_start); + struct ib_mr * (*reg_user_mr)(struct ib_pd *pd, + struct ib_umem *region, + int mr_access_flags, + struct ib_udata *udata); int (*query_mr)(struct ib_mr *mr, struct ib_mr_attr *mr_attr); int (*dereg_mr)(struct ib_mr *mr); @@ -817,6 +894,7 @@ struct ib_device { struct ib_mad *in_mad, struct ib_mad *out_mad); + struct module *owner; struct class_device class_dev; struct kobject ports_parent; struct list_head port_list; @@ -852,6 +930,16 @@ void *ib_get_client_data(struct ib_device *device, struct ib_client *client); void ib_set_client_data(struct ib_device *device, struct ib_client *client, void *data); +static inline int ib_copy_from_udata(void *dest, struct ib_udata *udata, size_t len) +{ + return copy_from_user(dest, udata->inbuf, len) ? -EFAULT : 0; +} + +static inline int ib_copy_to_udata(struct ib_udata *udata, void *src, size_t len) +{ + return copy_to_user(udata->outbuf, src, len) ? -EFAULT : 0; +} + int ib_register_event_handler (struct ib_event_handler *event_handler); int ib_unregister_event_handler(struct ib_event_handler *event_handler); void ib_dispatch_event(struct ib_event *event); -- cgit v1.2.3 From b5e81bf5e7084796d93167f438ec073e59aca9ed Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:11 -0700 Subject: [PATCH] IB uverbs: update kernel midlayer for new API Update kernel InfiniBand midlayer to compile against the updated API for low-level drivers. This just amounts to passing NULL for all userspace-related parameters, and setting userspace-related structure members to NULL. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/core/verbs.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 7c08ed0cd7d..2516f964651 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -4,6 +4,7 @@ * Copyright (c) 2004 Intel Corporation. All rights reserved. * Copyright (c) 2004 Topspin Corporation. All rights reserved. * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -47,10 +48,11 @@ struct ib_pd *ib_alloc_pd(struct ib_device *device) { struct ib_pd *pd; - pd = device->alloc_pd(device); + pd = device->alloc_pd(device, NULL, NULL); if (!IS_ERR(pd)) { - pd->device = device; + pd->device = device; + pd->uobject = NULL; atomic_set(&pd->usecnt, 0); } @@ -76,8 +78,9 @@ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) ah = pd->device->create_ah(pd, ah_attr); if (!IS_ERR(ah)) { - ah->device = pd->device; - ah->pd = pd; + ah->device = pd->device; + ah->pd = pd; + ah->uobject = NULL; atomic_inc(&pd->usecnt); } @@ -122,7 +125,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, { struct ib_qp *qp; - qp = pd->device->create_qp(pd, qp_init_attr); + qp = pd->device->create_qp(pd, qp_init_attr, NULL); if (!IS_ERR(qp)) { qp->device = pd->device; @@ -130,6 +133,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd, qp->send_cq = qp_init_attr->send_cq; qp->recv_cq = qp_init_attr->recv_cq; qp->srq = qp_init_attr->srq; + qp->uobject = NULL; qp->event_handler = qp_init_attr->event_handler; qp->qp_context = qp_init_attr->qp_context; qp->qp_type = qp_init_attr->qp_type; @@ -197,10 +201,11 @@ struct ib_cq *ib_create_cq(struct ib_device *device, { struct ib_cq *cq; - cq = device->create_cq(device, cqe); + cq = device->create_cq(device, cqe, NULL, NULL); if (!IS_ERR(cq)) { cq->device = device; + cq->uobject = NULL; cq->comp_handler = comp_handler; cq->event_handler = event_handler; cq->cq_context = cq_context; @@ -245,8 +250,9 @@ struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags) mr = pd->device->get_dma_mr(pd, mr_access_flags); if (!IS_ERR(mr)) { - mr->device = pd->device; - mr->pd = pd; + mr->device = pd->device; + mr->pd = pd; + mr->uobject = NULL; atomic_inc(&pd->usecnt); atomic_set(&mr->usecnt, 0); } @@ -267,8 +273,9 @@ struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd, mr_access_flags, iova_start); if (!IS_ERR(mr)) { - mr->device = pd->device; - mr->pd = pd; + mr->device = pd->device; + mr->pd = pd; + mr->uobject = NULL; atomic_inc(&pd->usecnt); atomic_set(&mr->usecnt, 0); } @@ -344,8 +351,9 @@ struct ib_mw *ib_alloc_mw(struct ib_pd *pd) mw = pd->device->alloc_mw(pd); if (!IS_ERR(mw)) { - mw->device = pd->device; - mw->pd = pd; + mw->device = pd->device; + mw->pd = pd; + mw->uobject = NULL; atomic_inc(&pd->usecnt); } -- cgit v1.2.3 From 1cf296b66afeec2edc39cc7bbedbf3d0afd2a373 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:11 -0700 Subject: [PATCH] IB uverbs: update mthca for new API Update mthca to compile against the updated API for low-level drivers. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/mthca/mthca_provider.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 0b5adfd9159..0cc86f8e185 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -284,7 +284,9 @@ static int mthca_query_gid(struct ib_device *ibdev, u8 port, return err; } -static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev) +static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev, + struct ib_ucontext *context, + struct ib_udata *udata) { struct mthca_pd *pd; int err; @@ -338,7 +340,8 @@ static int mthca_ah_destroy(struct ib_ah *ah) } static struct ib_qp *mthca_create_qp(struct ib_pd *pd, - struct ib_qp_init_attr *init_attr) + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata) { struct mthca_qp *qp; int err; @@ -409,7 +412,9 @@ static int mthca_destroy_qp(struct ib_qp *qp) return 0; } -static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries) +static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries, + struct ib_ucontext *context, + struct ib_udata *udata) { struct mthca_cq *cq; int nent; @@ -692,6 +697,8 @@ int mthca_register_device(struct mthca_dev *dev) int i; strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX); + dev->ib_dev.owner = THIS_MODULE; + dev->ib_dev.node_type = IB_NODE_CA; dev->ib_dev.phys_port_cnt = dev->limits.num_ports; dev->ib_dev.dma_device = &dev->pdev->dev; -- cgit v1.2.3 From 8a96b3f9af2d0351285665b532f9359d6cd73f42 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:12 -0700 Subject: [PATCH] IB uverbs: add user verbs ABI header Add the ib_user_verbs.h header file, which defines the ABI used by InfiniBand userspace verbs for kernel/user communication. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/include/ib_user_verbs.h | 389 +++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 drivers/infiniband/include/ib_user_verbs.h (limited to 'drivers') diff --git a/drivers/infiniband/include/ib_user_verbs.h b/drivers/infiniband/include/ib_user_verbs.h new file mode 100644 index 00000000000..7c613706af7 --- /dev/null +++ b/drivers/infiniband/include/ib_user_verbs.h @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * 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. + * + * $Id: ib_user_verbs.h 2708 2005-06-24 17:27:21Z roland $ + */ + +#ifndef IB_USER_VERBS_H +#define IB_USER_VERBS_H + +#include + +/* + * Increment this value if any changes that break userspace ABI + * compatibility are made. + */ +#define IB_USER_VERBS_ABI_VERSION 1 + +enum { + IB_USER_VERBS_CMD_QUERY_PARAMS, + IB_USER_VERBS_CMD_GET_CONTEXT, + IB_USER_VERBS_CMD_QUERY_DEVICE, + IB_USER_VERBS_CMD_QUERY_PORT, + IB_USER_VERBS_CMD_QUERY_GID, + IB_USER_VERBS_CMD_QUERY_PKEY, + IB_USER_VERBS_CMD_ALLOC_PD, + IB_USER_VERBS_CMD_DEALLOC_PD, + IB_USER_VERBS_CMD_CREATE_AH, + IB_USER_VERBS_CMD_MODIFY_AH, + IB_USER_VERBS_CMD_QUERY_AH, + IB_USER_VERBS_CMD_DESTROY_AH, + IB_USER_VERBS_CMD_REG_MR, + IB_USER_VERBS_CMD_REG_SMR, + IB_USER_VERBS_CMD_REREG_MR, + IB_USER_VERBS_CMD_QUERY_MR, + IB_USER_VERBS_CMD_DEREG_MR, + IB_USER_VERBS_CMD_ALLOC_MW, + IB_USER_VERBS_CMD_BIND_MW, + IB_USER_VERBS_CMD_DEALLOC_MW, + IB_USER_VERBS_CMD_CREATE_CQ, + IB_USER_VERBS_CMD_RESIZE_CQ, + IB_USER_VERBS_CMD_DESTROY_CQ, + IB_USER_VERBS_CMD_POLL_CQ, + IB_USER_VERBS_CMD_PEEK_CQ, + IB_USER_VERBS_CMD_REQ_NOTIFY_CQ, + IB_USER_VERBS_CMD_CREATE_QP, + IB_USER_VERBS_CMD_QUERY_QP, + IB_USER_VERBS_CMD_MODIFY_QP, + IB_USER_VERBS_CMD_DESTROY_QP, + IB_USER_VERBS_CMD_POST_SEND, + IB_USER_VERBS_CMD_POST_RECV, + IB_USER_VERBS_CMD_ATTACH_MCAST, + IB_USER_VERBS_CMD_DETACH_MCAST +}; + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + * In particular do not use pointer types -- pass pointers in __u64 + * instead. + */ + +struct ib_uverbs_async_event_desc { + __u64 element; + __u32 event_type; /* enum ib_event_type */ + __u32 reserved; +}; + +struct ib_uverbs_comp_event_desc { + __u64 cq_handle; +}; + +/* + * All commands from userspace should start with a __u32 command field + * followed by __u16 in_words and out_words fields (which give the + * length of the command block and response buffer if any in 32-bit + * words). The kernel driver will read these fields first and read + * the rest of the command struct based on these value. + */ + +struct ib_uverbs_cmd_hdr { + __u32 command; + __u16 in_words; + __u16 out_words; +}; + +/* + * No driver_data for "query params" command, since this is intended + * to be a core function with no possible device dependence. + */ +struct ib_uverbs_query_params { + __u64 response; +}; + +struct ib_uverbs_query_params_resp { + __u32 num_cq_events; +}; + +struct ib_uverbs_get_context { + __u64 response; + __u64 cq_fd_tab; + __u64 driver_data[0]; +}; + +struct ib_uverbs_get_context_resp { + __u32 async_fd; + __u32 reserved; +}; + +struct ib_uverbs_query_device { + __u64 response; + __u64 driver_data[0]; +}; + +struct ib_uverbs_query_device_resp { + __u64 fw_ver; + __u64 node_guid; + __u64 sys_image_guid; + __u64 max_mr_size; + __u64 page_size_cap; + __u32 vendor_id; + __u32 vendor_part_id; + __u32 hw_ver; + __u32 max_qp; + __u32 max_qp_wr; + __u32 device_cap_flags; + __u32 max_sge; + __u32 max_sge_rd; + __u32 max_cq; + __u32 max_cqe; + __u32 max_mr; + __u32 max_pd; + __u32 max_qp_rd_atom; + __u32 max_ee_rd_atom; + __u32 max_res_rd_atom; + __u32 max_qp_init_rd_atom; + __u32 max_ee_init_rd_atom; + __u32 atomic_cap; + __u32 max_ee; + __u32 max_rdd; + __u32 max_mw; + __u32 max_raw_ipv6_qp; + __u32 max_raw_ethy_qp; + __u32 max_mcast_grp; + __u32 max_mcast_qp_attach; + __u32 max_total_mcast_qp_attach; + __u32 max_ah; + __u32 max_fmr; + __u32 max_map_per_fmr; + __u32 max_srq; + __u32 max_srq_wr; + __u32 max_srq_sge; + __u16 max_pkeys; + __u8 local_ca_ack_delay; + __u8 phys_port_cnt; + __u8 reserved[4]; +}; + +struct ib_uverbs_query_port { + __u64 response; + __u8 port_num; + __u8 reserved[7]; + __u64 driver_data[0]; +}; + +struct ib_uverbs_query_port_resp { + __u32 port_cap_flags; + __u32 max_msg_sz; + __u32 bad_pkey_cntr; + __u32 qkey_viol_cntr; + __u32 gid_tbl_len; + __u16 pkey_tbl_len; + __u16 lid; + __u16 sm_lid; + __u8 state; + __u8 max_mtu; + __u8 active_mtu; + __u8 lmc; + __u8 max_vl_num; + __u8 sm_sl; + __u8 subnet_timeout; + __u8 init_type_reply; + __u8 active_width; + __u8 active_speed; + __u8 phys_state; + __u8 reserved[3]; +}; + +struct ib_uverbs_query_gid { + __u64 response; + __u8 port_num; + __u8 index; + __u8 reserved[6]; + __u64 driver_data[0]; +}; + +struct ib_uverbs_query_gid_resp { + __u8 gid[16]; +}; + +struct ib_uverbs_query_pkey { + __u64 response; + __u8 port_num; + __u8 index; + __u8 reserved[6]; + __u64 driver_data[0]; +}; + +struct ib_uverbs_query_pkey_resp { + __u16 pkey; + __u16 reserved; +}; + +struct ib_uverbs_alloc_pd { + __u64 response; + __u64 driver_data[0]; +}; + +struct ib_uverbs_alloc_pd_resp { + __u32 pd_handle; +}; + +struct ib_uverbs_dealloc_pd { + __u32 pd_handle; +}; + +struct ib_uverbs_reg_mr { + __u64 response; + __u64 start; + __u64 length; + __u64 hca_va; + __u32 pd_handle; + __u32 access_flags; + __u64 driver_data[0]; +}; + +struct ib_uverbs_reg_mr_resp { + __u32 mr_handle; + __u32 lkey; + __u32 rkey; +}; + +struct ib_uverbs_dereg_mr { + __u32 mr_handle; +}; + +struct ib_uverbs_create_cq { + __u64 response; + __u64 user_handle; + __u32 cqe; + __u32 event_handler; + __u64 driver_data[0]; +}; + +struct ib_uverbs_create_cq_resp { + __u32 cq_handle; + __u32 cqe; +}; + +struct ib_uverbs_destroy_cq { + __u32 cq_handle; +}; + +struct ib_uverbs_create_qp { + __u64 response; + __u64 user_handle; + __u32 pd_handle; + __u32 send_cq_handle; + __u32 recv_cq_handle; + __u32 srq_handle; + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + __u8 sq_sig_all; + __u8 qp_type; + __u8 is_srq; + __u8 reserved; + __u64 driver_data[0]; +}; + +struct ib_uverbs_create_qp_resp { + __u32 qp_handle; + __u32 qpn; +}; + +/* + * This struct needs to remain a multiple of 8 bytes to keep the + * alignment of the modify QP parameters. + */ +struct ib_uverbs_qp_dest { + __u8 dgid[16]; + __u32 flow_label; + __u16 dlid; + __u16 reserved; + __u8 sgid_index; + __u8 hop_limit; + __u8 traffic_class; + __u8 sl; + __u8 src_path_bits; + __u8 static_rate; + __u8 is_global; + __u8 port_num; +}; + +struct ib_uverbs_modify_qp { + struct ib_uverbs_qp_dest dest; + struct ib_uverbs_qp_dest alt_dest; + __u32 qp_handle; + __u32 attr_mask; + __u32 qkey; + __u32 rq_psn; + __u32 sq_psn; + __u32 dest_qp_num; + __u32 qp_access_flags; + __u16 pkey_index; + __u16 alt_pkey_index; + __u8 qp_state; + __u8 cur_qp_state; + __u8 path_mtu; + __u8 path_mig_state; + __u8 en_sqd_async_notify; + __u8 max_rd_atomic; + __u8 max_dest_rd_atomic; + __u8 min_rnr_timer; + __u8 port_num; + __u8 timeout; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 alt_port_num; + __u8 alt_timeout; + __u8 reserved[2]; + __u64 driver_data[0]; +}; + +struct ib_uverbs_modify_qp_resp { +}; + +struct ib_uverbs_destroy_qp { + __u32 qp_handle; +}; + +struct ib_uverbs_attach_mcast { + __u8 gid[16]; + __u32 qp_handle; + __u16 mlid; + __u16 reserved; + __u64 driver_data[0]; +}; + +struct ib_uverbs_detach_mcast { + __u8 gid[16]; + __u32 qp_handle; + __u16 mlid; + __u16 reserved; + __u64 driver_data[0]; +}; + +#endif /* IB_USER_VERBS_H */ -- cgit v1.2.3 From bc38a6abdd5a50e007d0fcd9b9b6280132b79e62 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:13 -0700 Subject: [PATCH] IB uverbs: core implementation Add the core of the InfiniBand userspace verbs implementation, including creating character device nodes, dispatching requests from userspace, and passing event notifications back up to userspace. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/core/uverbs.h | 132 +++++ drivers/infiniband/core/uverbs_cmd.c | 1006 +++++++++++++++++++++++++++++++++ drivers/infiniband/core/uverbs_main.c | 698 +++++++++++++++++++++++ 3 files changed, 1836 insertions(+) create mode 100644 drivers/infiniband/core/uverbs.h create mode 100644 drivers/infiniband/core/uverbs_cmd.c create mode 100644 drivers/infiniband/core/uverbs_main.c (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h new file mode 100644 index 00000000000..57347f1e82c --- /dev/null +++ b/drivers/infiniband/core/uverbs.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * 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. + * + * $Id: uverbs.h 2559 2005-06-06 19:43:16Z roland $ + */ + +#ifndef UVERBS_H +#define UVERBS_H + +/* Include device.h and fs.h until cdev.h is self-sufficient */ +#include +#include +#include +#include +#include + +#include +#include + +struct ib_uverbs_device { + int devnum; + struct cdev dev; + struct class_device class_dev; + struct ib_device *ib_dev; + int num_comp; +}; + +struct ib_uverbs_event_file { + struct kref ref; + struct ib_uverbs_file *uverbs_file; + spinlock_t lock; + int fd; + int is_async; + wait_queue_head_t poll_wait; + struct list_head event_list; +}; + +struct ib_uverbs_file { + struct kref ref; + struct ib_uverbs_device *device; + struct ib_ucontext *ucontext; + struct ib_event_handler event_handler; + struct ib_uverbs_event_file async_file; + struct ib_uverbs_event_file comp_file[1]; +}; + +struct ib_uverbs_async_event { + struct ib_uverbs_async_event_desc desc; + struct list_head list; +}; + +struct ib_uverbs_comp_event { + struct ib_uverbs_comp_event_desc desc; + struct list_head list; +}; + +struct ib_uobject_mr { + struct ib_uobject uobj; + struct page *page_list; + struct scatterlist *sg_list; +}; + +extern struct semaphore ib_uverbs_idr_mutex; +extern struct idr ib_uverbs_pd_idr; +extern struct idr ib_uverbs_mr_idr; +extern struct idr ib_uverbs_mw_idr; +extern struct idr ib_uverbs_ah_idr; +extern struct idr ib_uverbs_cq_idr; +extern struct idr ib_uverbs_qp_idr; + +void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context); +void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr); +void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr); + +int ib_umem_get(struct ib_device *dev, struct ib_umem *mem, + void *addr, size_t size, int write); +void ib_umem_release(struct ib_device *dev, struct ib_umem *umem); +void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem); + +#define IB_UVERBS_DECLARE_CMD(name) \ + ssize_t ib_uverbs_##name(struct ib_uverbs_file *file, \ + const char __user *buf, int in_len, \ + int out_len) + +IB_UVERBS_DECLARE_CMD(query_params); +IB_UVERBS_DECLARE_CMD(get_context); +IB_UVERBS_DECLARE_CMD(query_device); +IB_UVERBS_DECLARE_CMD(query_port); +IB_UVERBS_DECLARE_CMD(query_gid); +IB_UVERBS_DECLARE_CMD(query_pkey); +IB_UVERBS_DECLARE_CMD(alloc_pd); +IB_UVERBS_DECLARE_CMD(dealloc_pd); +IB_UVERBS_DECLARE_CMD(reg_mr); +IB_UVERBS_DECLARE_CMD(dereg_mr); +IB_UVERBS_DECLARE_CMD(create_cq); +IB_UVERBS_DECLARE_CMD(destroy_cq); +IB_UVERBS_DECLARE_CMD(create_qp); +IB_UVERBS_DECLARE_CMD(modify_qp); +IB_UVERBS_DECLARE_CMD(destroy_qp); +IB_UVERBS_DECLARE_CMD(attach_mcast); +IB_UVERBS_DECLARE_CMD(detach_mcast); + +#endif /* UVERBS_H */ diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c new file mode 100644 index 00000000000..5f2bbcda4c7 --- /dev/null +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -0,0 +1,1006 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * 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. + * + * $Id: uverbs_cmd.c 2708 2005-06-24 17:27:21Z roland $ + */ + +#include + +#include "uverbs.h" + +#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \ + do { \ + (udata)->inbuf = (void __user *) (ibuf); \ + (udata)->outbuf = (void __user *) (obuf); \ + (udata)->inlen = (ilen); \ + (udata)->outlen = (olen); \ + } while (0) + +ssize_t ib_uverbs_query_params(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_query_params cmd; + struct ib_uverbs_query_params_resp resp; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + memset(&resp, 0, sizeof resp); + + resp.num_cq_events = file->device->num_comp; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) + return -EFAULT; + + return in_len; +} + +ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_get_context cmd; + struct ib_uverbs_get_context_resp resp; + struct ib_udata udata; + struct ib_device *ibdev = file->device->ib_dev; + int i; + int ret = in_len; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + file->ucontext = ibdev->alloc_ucontext(ibdev, &udata); + if (IS_ERR(file->ucontext)) { + ret = PTR_ERR(file->ucontext); + file->ucontext = NULL; + return ret; + } + + file->ucontext->device = ibdev; + INIT_LIST_HEAD(&file->ucontext->pd_list); + INIT_LIST_HEAD(&file->ucontext->mr_list); + INIT_LIST_HEAD(&file->ucontext->mw_list); + INIT_LIST_HEAD(&file->ucontext->cq_list); + INIT_LIST_HEAD(&file->ucontext->qp_list); + INIT_LIST_HEAD(&file->ucontext->srq_list); + INIT_LIST_HEAD(&file->ucontext->ah_list); + spin_lock_init(&file->ucontext->lock); + + resp.async_fd = file->async_file.fd; + for (i = 0; i < file->device->num_comp; ++i) + if (copy_to_user((void __user *) (unsigned long) cmd.cq_fd_tab + + i * sizeof (__u32), + &file->comp_file[i].fd, sizeof (__u32))) + goto err; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + goto err; + + return in_len; + +err: + ibdev->dealloc_ucontext(file->ucontext); + file->ucontext = NULL; + + return -EFAULT; +} + +ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_query_device cmd; + struct ib_uverbs_query_device_resp resp; + struct ib_device_attr attr; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + ret = ib_query_device(file->device->ib_dev, &attr); + if (ret) + return ret; + + memset(&resp, 0, sizeof resp); + + resp.fw_ver = attr.fw_ver; + resp.node_guid = attr.node_guid; + resp.sys_image_guid = attr.sys_image_guid; + resp.max_mr_size = attr.max_mr_size; + resp.page_size_cap = attr.page_size_cap; + resp.vendor_id = attr.vendor_id; + resp.vendor_part_id = attr.vendor_part_id; + resp.hw_ver = attr.hw_ver; + resp.max_qp = attr.max_qp; + resp.max_qp_wr = attr.max_qp_wr; + resp.device_cap_flags = attr.device_cap_flags; + resp.max_sge = attr.max_sge; + resp.max_sge_rd = attr.max_sge_rd; + resp.max_cq = attr.max_cq; + resp.max_cqe = attr.max_cqe; + resp.max_mr = attr.max_mr; + resp.max_pd = attr.max_pd; + resp.max_qp_rd_atom = attr.max_qp_rd_atom; + resp.max_ee_rd_atom = attr.max_ee_rd_atom; + resp.max_res_rd_atom = attr.max_res_rd_atom; + resp.max_qp_init_rd_atom = attr.max_qp_init_rd_atom; + resp.max_ee_init_rd_atom = attr.max_ee_init_rd_atom; + resp.atomic_cap = attr.atomic_cap; + resp.max_ee = attr.max_ee; + resp.max_rdd = attr.max_rdd; + resp.max_mw = attr.max_mw; + resp.max_raw_ipv6_qp = attr.max_raw_ipv6_qp; + resp.max_raw_ethy_qp = attr.max_raw_ethy_qp; + resp.max_mcast_grp = attr.max_mcast_grp; + resp.max_mcast_qp_attach = attr.max_mcast_qp_attach; + resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach; + resp.max_ah = attr.max_ah; + resp.max_fmr = attr.max_fmr; + resp.max_map_per_fmr = attr.max_map_per_fmr; + resp.max_srq = attr.max_srq; + resp.max_srq_wr = attr.max_srq_wr; + resp.max_srq_sge = attr.max_srq_sge; + resp.max_pkeys = attr.max_pkeys; + resp.local_ca_ack_delay = attr.local_ca_ack_delay; + resp.phys_port_cnt = file->device->ib_dev->phys_port_cnt; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + return -EFAULT; + + return in_len; +} + +ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_query_port cmd; + struct ib_uverbs_query_port_resp resp; + struct ib_port_attr attr; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + ret = ib_query_port(file->device->ib_dev, cmd.port_num, &attr); + if (ret) + return ret; + + memset(&resp, 0, sizeof resp); + + resp.state = attr.state; + resp.max_mtu = attr.max_mtu; + resp.active_mtu = attr.active_mtu; + resp.gid_tbl_len = attr.gid_tbl_len; + resp.port_cap_flags = attr.port_cap_flags; + resp.max_msg_sz = attr.max_msg_sz; + resp.bad_pkey_cntr = attr.bad_pkey_cntr; + resp.qkey_viol_cntr = attr.qkey_viol_cntr; + resp.pkey_tbl_len = attr.pkey_tbl_len; + resp.lid = attr.lid; + resp.sm_lid = attr.sm_lid; + resp.lmc = attr.lmc; + resp.max_vl_num = attr.max_vl_num; + resp.sm_sl = attr.sm_sl; + resp.subnet_timeout = attr.subnet_timeout; + resp.init_type_reply = attr.init_type_reply; + resp.active_width = attr.active_width; + resp.active_speed = attr.active_speed; + resp.phys_state = attr.phys_state; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + return -EFAULT; + + return in_len; +} + +ssize_t ib_uverbs_query_gid(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_query_gid cmd; + struct ib_uverbs_query_gid_resp resp; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + memset(&resp, 0, sizeof resp); + + ret = ib_query_gid(file->device->ib_dev, cmd.port_num, cmd.index, + (union ib_gid *) resp.gid); + if (ret) + return ret; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + return -EFAULT; + + return in_len; +} + +ssize_t ib_uverbs_query_pkey(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_query_pkey cmd; + struct ib_uverbs_query_pkey_resp resp; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + memset(&resp, 0, sizeof resp); + + ret = ib_query_pkey(file->device->ib_dev, cmd.port_num, cmd.index, + &resp.pkey); + if (ret) + return ret; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + return -EFAULT; + + return in_len; +} + +ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_alloc_pd cmd; + struct ib_uverbs_alloc_pd_resp resp; + struct ib_udata udata; + struct ib_uobject *uobj; + struct ib_pd *pd; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); + if (!uobj) + return -ENOMEM; + + uobj->context = file->ucontext; + + pd = file->device->ib_dev->alloc_pd(file->device->ib_dev, + file->ucontext, &udata); + if (IS_ERR(pd)) { + ret = PTR_ERR(pd); + goto err; + } + + pd->device = file->device->ib_dev; + pd->uobject = uobj; + atomic_set(&pd->usecnt, 0); + +retry: + if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) { + ret = -ENOMEM; + goto err_pd; + } + + down(&ib_uverbs_idr_mutex); + ret = idr_get_new(&ib_uverbs_pd_idr, pd, &uobj->id); + up(&ib_uverbs_idr_mutex); + + if (ret == -EAGAIN) + goto retry; + if (ret) + goto err_pd; + + spin_lock_irq(&file->ucontext->lock); + list_add_tail(&uobj->list, &file->ucontext->pd_list); + spin_unlock_irq(&file->ucontext->lock); + + memset(&resp, 0, sizeof resp); + resp.pd_handle = uobj->id; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_list; + } + + return in_len; + +err_list: + spin_lock_irq(&file->ucontext->lock); + list_del(&uobj->list); + spin_unlock_irq(&file->ucontext->lock); + + down(&ib_uverbs_idr_mutex); + idr_remove(&ib_uverbs_pd_idr, uobj->id); + up(&ib_uverbs_idr_mutex); + +err_pd: + ib_dealloc_pd(pd); + +err: + kfree(uobj); + return ret; +} + +ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_dealloc_pd cmd; + struct ib_pd *pd; + struct ib_uobject *uobj; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + down(&ib_uverbs_idr_mutex); + + pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); + if (!pd || pd->uobject->context != file->ucontext) + goto out; + + uobj = pd->uobject; + + ret = ib_dealloc_pd(pd); + if (ret) + goto out; + + idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle); + + spin_lock_irq(&file->ucontext->lock); + list_del(&uobj->list); + spin_unlock_irq(&file->ucontext->lock); + + kfree(uobj); + +out: + up(&ib_uverbs_idr_mutex); + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_reg_mr cmd; + struct ib_uverbs_reg_mr_resp resp; + struct ib_udata udata; + struct ib_umem_object *obj; + struct ib_pd *pd; + struct ib_mr *mr; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK)) + return -EINVAL; + + obj = kmalloc(sizeof *obj, GFP_KERNEL); + if (!obj) + return -ENOMEM; + + obj->uobject.context = file->ucontext; + + /* + * We ask for writable memory if any access flags other than + * "remote read" are set. "Local write" and "remote write" + * obviously require write access. "Remote atomic" can do + * things like fetch and add, which will modify memory, and + * "MW bind" can change permissions by binding a window. + */ + ret = ib_umem_get(file->device->ib_dev, &obj->umem, + (void *) (unsigned long) cmd.start, cmd.length, + !!(cmd.access_flags & ~IB_ACCESS_REMOTE_READ)); + if (ret) + goto err_free; + + obj->umem.virt_base = cmd.hca_va; + + down(&ib_uverbs_idr_mutex); + + pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); + if (!pd || pd->uobject->context != file->ucontext) { + ret = -EINVAL; + goto err_up; + } + + if (!pd->device->reg_user_mr) { + ret = -ENOSYS; + goto err_up; + } + + mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata); + if (IS_ERR(mr)) { + ret = PTR_ERR(mr); + goto err_up; + } + + mr->device = pd->device; + mr->pd = pd; + mr->uobject = &obj->uobject; + atomic_inc(&pd->usecnt); + atomic_set(&mr->usecnt, 0); + + memset(&resp, 0, sizeof resp); + resp.lkey = mr->lkey; + resp.rkey = mr->rkey; + +retry: + if (!idr_pre_get(&ib_uverbs_mr_idr, GFP_KERNEL)) { + ret = -ENOMEM; + goto err_unreg; + } + + ret = idr_get_new(&ib_uverbs_mr_idr, mr, &obj->uobject.id); + + if (ret == -EAGAIN) + goto retry; + if (ret) + goto err_unreg; + + resp.mr_handle = obj->uobject.id; + + spin_lock_irq(&file->ucontext->lock); + list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); + spin_unlock_irq(&file->ucontext->lock); + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_list; + } + + up(&ib_uverbs_idr_mutex); + + return in_len; + +err_list: + spin_lock_irq(&file->ucontext->lock); + list_del(&obj->uobject.list); + spin_unlock_irq(&file->ucontext->lock); + +err_unreg: + ib_dereg_mr(mr); + +err_up: + up(&ib_uverbs_idr_mutex); + + ib_umem_release(file->device->ib_dev, &obj->umem); + +err_free: + kfree(obj); + return ret; +} + +ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_dereg_mr cmd; + struct ib_mr *mr; + struct ib_umem_object *memobj; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + down(&ib_uverbs_idr_mutex); + + mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle); + if (!mr || mr->uobject->context != file->ucontext) + goto out; + + memobj = container_of(mr->uobject, struct ib_umem_object, uobject); + + ret = ib_dereg_mr(mr); + if (ret) + goto out; + + idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle); + + spin_lock_irq(&file->ucontext->lock); + list_del(&memobj->uobject.list); + spin_unlock_irq(&file->ucontext->lock); + + ib_umem_release(file->device->ib_dev, &memobj->umem); + kfree(memobj); + +out: + up(&ib_uverbs_idr_mutex); + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_cq cmd; + struct ib_uverbs_create_cq_resp resp; + struct ib_udata udata; + struct ib_uobject *uobj; + struct ib_cq *cq; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + if (cmd.event_handler >= file->device->num_comp) + return -EINVAL; + + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); + if (!uobj) + return -ENOMEM; + + uobj->user_handle = cmd.user_handle; + uobj->context = file->ucontext; + + cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, + file->ucontext, &udata); + if (IS_ERR(cq)) { + ret = PTR_ERR(cq); + goto err; + } + + cq->device = file->device->ib_dev; + cq->uobject = uobj; + cq->comp_handler = ib_uverbs_comp_handler; + cq->event_handler = ib_uverbs_cq_event_handler; + cq->cq_context = file; + atomic_set(&cq->usecnt, 0); + +retry: + if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) { + ret = -ENOMEM; + goto err_cq; + } + + down(&ib_uverbs_idr_mutex); + ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->id); + up(&ib_uverbs_idr_mutex); + + if (ret == -EAGAIN) + goto retry; + if (ret) + goto err_cq; + + spin_lock_irq(&file->ucontext->lock); + list_add_tail(&uobj->list, &file->ucontext->cq_list); + spin_unlock_irq(&file->ucontext->lock); + + memset(&resp, 0, sizeof resp); + resp.cq_handle = uobj->id; + resp.cqe = cq->cqe; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_list; + } + + return in_len; + +err_list: + spin_lock_irq(&file->ucontext->lock); + list_del(&uobj->list); + spin_unlock_irq(&file->ucontext->lock); + + down(&ib_uverbs_idr_mutex); + idr_remove(&ib_uverbs_cq_idr, uobj->id); + up(&ib_uverbs_idr_mutex); + +err_cq: + ib_destroy_cq(cq); + +err: + kfree(uobj); + return ret; +} + +ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_destroy_cq cmd; + struct ib_cq *cq; + struct ib_uobject *uobj; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + down(&ib_uverbs_idr_mutex); + + cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); + if (!cq || cq->uobject->context != file->ucontext) + goto out; + + uobj = cq->uobject; + + ret = ib_destroy_cq(cq); + if (ret) + goto out; + + idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle); + + spin_lock_irq(&file->ucontext->lock); + list_del(&uobj->list); + spin_unlock_irq(&file->ucontext->lock); + + kfree(uobj); + +out: + up(&ib_uverbs_idr_mutex); + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_qp cmd; + struct ib_uverbs_create_qp_resp resp; + struct ib_udata udata; + struct ib_uobject *uobj; + struct ib_pd *pd; + struct ib_cq *scq, *rcq; + struct ib_qp *qp; + struct ib_qp_init_attr attr; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); + if (!uobj) + return -ENOMEM; + + down(&ib_uverbs_idr_mutex); + + pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); + scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle); + rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle); + + if (!pd || pd->uobject->context != file->ucontext || + !scq || scq->uobject->context != file->ucontext || + !rcq || rcq->uobject->context != file->ucontext) { + ret = -EINVAL; + goto err_up; + } + + attr.event_handler = ib_uverbs_qp_event_handler; + attr.qp_context = file; + attr.send_cq = scq; + attr.recv_cq = rcq; + attr.srq = NULL; + attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; + attr.qp_type = cmd.qp_type; + + attr.cap.max_send_wr = cmd.max_send_wr; + attr.cap.max_recv_wr = cmd.max_recv_wr; + attr.cap.max_send_sge = cmd.max_send_sge; + attr.cap.max_recv_sge = cmd.max_recv_sge; + attr.cap.max_inline_data = cmd.max_inline_data; + + uobj->user_handle = cmd.user_handle; + uobj->context = file->ucontext; + + qp = pd->device->create_qp(pd, &attr, &udata); + if (IS_ERR(qp)) { + ret = PTR_ERR(qp); + goto err_up; + } + + qp->device = pd->device; + qp->pd = pd; + qp->send_cq = attr.send_cq; + qp->recv_cq = attr.recv_cq; + qp->srq = attr.srq; + qp->uobject = uobj; + qp->event_handler = attr.event_handler; + qp->qp_context = attr.qp_context; + qp->qp_type = attr.qp_type; + atomic_inc(&pd->usecnt); + atomic_inc(&attr.send_cq->usecnt); + atomic_inc(&attr.recv_cq->usecnt); + if (attr.srq) + atomic_inc(&attr.srq->usecnt); + + memset(&resp, 0, sizeof resp); + resp.qpn = qp->qp_num; + +retry: + if (!idr_pre_get(&ib_uverbs_qp_idr, GFP_KERNEL)) { + ret = -ENOMEM; + goto err_destroy; + } + + ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->id); + + if (ret == -EAGAIN) + goto retry; + if (ret) + goto err_destroy; + + resp.qp_handle = uobj->id; + + spin_lock_irq(&file->ucontext->lock); + list_add_tail(&uobj->list, &file->ucontext->qp_list); + spin_unlock_irq(&file->ucontext->lock); + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_list; + } + + up(&ib_uverbs_idr_mutex); + + return in_len; + +err_list: + spin_lock_irq(&file->ucontext->lock); + list_del(&uobj->list); + spin_unlock_irq(&file->ucontext->lock); + +err_destroy: + ib_destroy_qp(qp); + +err_up: + up(&ib_uverbs_idr_mutex); + + kfree(uobj); + return ret; +} + +ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_modify_qp cmd; + struct ib_qp *qp; + struct ib_qp_attr *attr; + int ret; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + attr = kmalloc(sizeof *attr, GFP_KERNEL); + if (!attr) + return -ENOMEM; + + down(&ib_uverbs_idr_mutex); + + qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); + if (!qp || qp->uobject->context != file->ucontext) { + ret = -EINVAL; + goto out; + } + + attr->qp_state = cmd.qp_state; + attr->cur_qp_state = cmd.cur_qp_state; + attr->path_mtu = cmd.path_mtu; + attr->path_mig_state = cmd.path_mig_state; + attr->qkey = cmd.qkey; + attr->rq_psn = cmd.rq_psn; + attr->sq_psn = cmd.sq_psn; + attr->dest_qp_num = cmd.dest_qp_num; + attr->qp_access_flags = cmd.qp_access_flags; + attr->pkey_index = cmd.pkey_index; + attr->alt_pkey_index = cmd.pkey_index; + attr->en_sqd_async_notify = cmd.en_sqd_async_notify; + attr->max_rd_atomic = cmd.max_rd_atomic; + attr->max_dest_rd_atomic = cmd.max_dest_rd_atomic; + attr->min_rnr_timer = cmd.min_rnr_timer; + attr->port_num = cmd.port_num; + attr->timeout = cmd.timeout; + attr->retry_cnt = cmd.retry_cnt; + attr->rnr_retry = cmd.rnr_retry; + attr->alt_port_num = cmd.alt_port_num; + attr->alt_timeout = cmd.alt_timeout; + + memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16); + attr->ah_attr.grh.flow_label = cmd.dest.flow_label; + attr->ah_attr.grh.sgid_index = cmd.dest.sgid_index; + attr->ah_attr.grh.hop_limit = cmd.dest.hop_limit; + attr->ah_attr.grh.traffic_class = cmd.dest.traffic_class; + attr->ah_attr.dlid = cmd.dest.dlid; + attr->ah_attr.sl = cmd.dest.sl; + attr->ah_attr.src_path_bits = cmd.dest.src_path_bits; + attr->ah_attr.static_rate = cmd.dest.static_rate; + attr->ah_attr.ah_flags = cmd.dest.is_global ? IB_AH_GRH : 0; + attr->ah_attr.port_num = cmd.dest.port_num; + + memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16); + attr->alt_ah_attr.grh.flow_label = cmd.alt_dest.flow_label; + attr->alt_ah_attr.grh.sgid_index = cmd.alt_dest.sgid_index; + attr->alt_ah_attr.grh.hop_limit = cmd.alt_dest.hop_limit; + attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class; + attr->alt_ah_attr.dlid = cmd.alt_dest.dlid; + attr->alt_ah_attr.sl = cmd.alt_dest.sl; + attr->alt_ah_attr.src_path_bits = cmd.alt_dest.src_path_bits; + attr->alt_ah_attr.static_rate = cmd.alt_dest.static_rate; + attr->alt_ah_attr.ah_flags = cmd.alt_dest.is_global ? IB_AH_GRH : 0; + attr->alt_ah_attr.port_num = cmd.alt_dest.port_num; + + ret = ib_modify_qp(qp, attr, cmd.attr_mask); + if (ret) + goto out; + + ret = in_len; + +out: + up(&ib_uverbs_idr_mutex); + kfree(attr); + + return ret; +} + +ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_destroy_qp cmd; + struct ib_qp *qp; + struct ib_uobject *uobj; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + down(&ib_uverbs_idr_mutex); + + qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); + if (!qp || qp->uobject->context != file->ucontext) + goto out; + + uobj = qp->uobject; + + ret = ib_destroy_qp(qp); + if (ret) + goto out; + + idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); + + spin_lock_irq(&file->ucontext->lock); + list_del(&uobj->list); + spin_unlock_irq(&file->ucontext->lock); + + kfree(uobj); + +out: + up(&ib_uverbs_idr_mutex); + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_attach_mcast cmd; + struct ib_qp *qp; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + down(&ib_uverbs_idr_mutex); + + qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); + if (qp && qp->uobject->context == file->ucontext) + ret = ib_attach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); + + up(&ib_uverbs_idr_mutex); + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_detach_mcast cmd; + struct ib_qp *qp; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + down(&ib_uverbs_idr_mutex); + + qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); + if (qp && qp->uobject->context == file->ucontext) + ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); + + up(&ib_uverbs_idr_mutex); + + return ret ? ret : in_len; +} diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c new file mode 100644 index 00000000000..fbbe03d8c90 --- /dev/null +++ b/drivers/infiniband/core/uverbs_main.c @@ -0,0 +1,698 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * 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. + * + * $Id: uverbs_main.c 2733 2005-06-28 19:14:34Z roland $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "uverbs.h" + +MODULE_AUTHOR("Roland Dreier"); +MODULE_DESCRIPTION("InfiniBand userspace verbs access"); +MODULE_LICENSE("Dual BSD/GPL"); + +#define INFINIBANDEVENTFS_MAGIC 0x49426576 /* "IBev" */ + +enum { + IB_UVERBS_MAJOR = 231, + IB_UVERBS_BASE_MINOR = 192, + IB_UVERBS_MAX_DEVICES = 32 +}; + +#define IB_UVERBS_BASE_DEV MKDEV(IB_UVERBS_MAJOR, IB_UVERBS_BASE_MINOR) + +DECLARE_MUTEX(ib_uverbs_idr_mutex); +DEFINE_IDR(ib_uverbs_pd_idr); +DEFINE_IDR(ib_uverbs_mr_idr); +DEFINE_IDR(ib_uverbs_mw_idr); +DEFINE_IDR(ib_uverbs_ah_idr); +DEFINE_IDR(ib_uverbs_cq_idr); +DEFINE_IDR(ib_uverbs_qp_idr); + +static spinlock_t map_lock; +static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); + +static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) = { + [IB_USER_VERBS_CMD_QUERY_PARAMS] = ib_uverbs_query_params, + [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context, + [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device, + [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port, + [IB_USER_VERBS_CMD_QUERY_GID] = ib_uverbs_query_gid, + [IB_USER_VERBS_CMD_QUERY_PKEY] = ib_uverbs_query_pkey, + [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd, + [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd, + [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr, + [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, + [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, + [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, + [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, + [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, + [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, + [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, + [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, +}; + +static struct vfsmount *uverbs_event_mnt; + +static void ib_uverbs_add_one(struct ib_device *device); +static void ib_uverbs_remove_one(struct ib_device *device); + +static int ib_dealloc_ucontext(struct ib_ucontext *context) +{ + struct ib_uobject *uobj, *tmp; + + if (!context) + return 0; + + down(&ib_uverbs_idr_mutex); + + /* XXX Free AHs */ + + list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { + struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); + idr_remove(&ib_uverbs_qp_idr, uobj->id); + ib_destroy_qp(qp); + list_del(&uobj->list); + kfree(uobj); + } + + list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { + struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id); + idr_remove(&ib_uverbs_cq_idr, uobj->id); + ib_destroy_cq(cq); + list_del(&uobj->list); + kfree(uobj); + } + + /* XXX Free SRQs */ + /* XXX Free MWs */ + + list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { + struct ib_mr *mr = idr_find(&ib_uverbs_mr_idr, uobj->id); + struct ib_umem_object *memobj; + + idr_remove(&ib_uverbs_mr_idr, uobj->id); + ib_dereg_mr(mr); + + memobj = container_of(uobj, struct ib_umem_object, uobject); + ib_umem_release_on_close(mr->device, &memobj->umem); + + list_del(&uobj->list); + kfree(memobj); + } + + list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) { + struct ib_pd *pd = idr_find(&ib_uverbs_pd_idr, uobj->id); + idr_remove(&ib_uverbs_pd_idr, uobj->id); + ib_dealloc_pd(pd); + list_del(&uobj->list); + kfree(uobj); + } + + up(&ib_uverbs_idr_mutex); + + return context->device->dealloc_ucontext(context); +} + +static void ib_uverbs_release_file(struct kref *ref) +{ + struct ib_uverbs_file *file = + container_of(ref, struct ib_uverbs_file, ref); + + module_put(file->device->ib_dev->owner); + kfree(file); +} + +static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, + size_t count, loff_t *pos) +{ + struct ib_uverbs_event_file *file = filp->private_data; + void *event; + int eventsz; + int ret = 0; + + spin_lock_irq(&file->lock); + + while (list_empty(&file->event_list) && file->fd >= 0) { + spin_unlock_irq(&file->lock); + + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (wait_event_interruptible(file->poll_wait, + !list_empty(&file->event_list) || + file->fd < 0)) + return -ERESTARTSYS; + + spin_lock_irq(&file->lock); + } + + if (file->fd < 0) { + spin_unlock_irq(&file->lock); + return -ENODEV; + } + + if (file->is_async) { + event = list_entry(file->event_list.next, + struct ib_uverbs_async_event, list); + eventsz = sizeof (struct ib_uverbs_async_event_desc); + } else { + event = list_entry(file->event_list.next, + struct ib_uverbs_comp_event, list); + eventsz = sizeof (struct ib_uverbs_comp_event_desc); + } + + if (eventsz > count) { + ret = -EINVAL; + event = NULL; + } else + list_del(file->event_list.next); + + spin_unlock_irq(&file->lock); + + if (event) { + if (copy_to_user(buf, event, eventsz)) + ret = -EFAULT; + else + ret = eventsz; + } + + kfree(event); + + return ret; +} + +static unsigned int ib_uverbs_event_poll(struct file *filp, + struct poll_table_struct *wait) +{ + unsigned int pollflags = 0; + struct ib_uverbs_event_file *file = filp->private_data; + + poll_wait(filp, &file->poll_wait, wait); + + spin_lock_irq(&file->lock); + if (file->fd < 0) + pollflags = POLLERR; + else if (!list_empty(&file->event_list)) + pollflags = POLLIN | POLLRDNORM; + spin_unlock_irq(&file->lock); + + return pollflags; +} + +static void ib_uverbs_event_release(struct ib_uverbs_event_file *file) +{ + struct list_head *entry, *tmp; + + spin_lock_irq(&file->lock); + if (file->fd != -1) { + file->fd = -1; + list_for_each_safe(entry, tmp, &file->event_list) + if (file->is_async) + kfree(list_entry(entry, struct ib_uverbs_async_event, list)); + else + kfree(list_entry(entry, struct ib_uverbs_comp_event, list)); + } + spin_unlock_irq(&file->lock); +} + +static int ib_uverbs_event_close(struct inode *inode, struct file *filp) +{ + struct ib_uverbs_event_file *file = filp->private_data; + + ib_uverbs_event_release(file); + kref_put(&file->uverbs_file->ref, ib_uverbs_release_file); + + return 0; +} + +static struct file_operations uverbs_event_fops = { + /* + * No .owner field since we artificially create event files, + * so there is no increment to the module reference count in + * the open path. All event files come from a uverbs command + * file, which already takes a module reference, so this is OK. + */ + .read = ib_uverbs_event_read, + .poll = ib_uverbs_event_poll, + .release = ib_uverbs_event_close +}; + +void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) +{ + struct ib_uverbs_file *file = cq_context; + struct ib_uverbs_comp_event *entry; + unsigned long flags; + + entry = kmalloc(sizeof *entry, GFP_ATOMIC); + if (!entry) + return; + + entry->desc.cq_handle = cq->uobject->user_handle; + + spin_lock_irqsave(&file->comp_file[0].lock, flags); + list_add_tail(&entry->list, &file->comp_file[0].event_list); + spin_unlock_irqrestore(&file->comp_file[0].lock, flags); + + wake_up_interruptible(&file->comp_file[0].poll_wait); +} + +static void ib_uverbs_async_handler(struct ib_uverbs_file *file, + __u64 element, __u64 event) +{ + struct ib_uverbs_async_event *entry; + unsigned long flags; + + entry = kmalloc(sizeof *entry, GFP_ATOMIC); + if (!entry) + return; + + entry->desc.element = element; + entry->desc.event_type = event; + + spin_lock_irqsave(&file->async_file.lock, flags); + list_add_tail(&entry->list, &file->async_file.event_list); + spin_unlock_irqrestore(&file->async_file.lock, flags); + + wake_up_interruptible(&file->async_file.poll_wait); +} + +void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr) +{ + ib_uverbs_async_handler(context_ptr, + event->element.cq->uobject->user_handle, + event->event); +} + +void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr) +{ + ib_uverbs_async_handler(context_ptr, + event->element.qp->uobject->user_handle, + event->event); +} + +static void ib_uverbs_event_handler(struct ib_event_handler *handler, + struct ib_event *event) +{ + struct ib_uverbs_file *file = + container_of(handler, struct ib_uverbs_file, event_handler); + + ib_uverbs_async_handler(file, event->element.port_num, event->event); +} + +static int ib_uverbs_event_init(struct ib_uverbs_event_file *file, + struct ib_uverbs_file *uverbs_file) +{ + struct file *filp; + + spin_lock_init(&file->lock); + INIT_LIST_HEAD(&file->event_list); + init_waitqueue_head(&file->poll_wait); + file->uverbs_file = uverbs_file; + + file->fd = get_unused_fd(); + if (file->fd < 0) + return file->fd; + + filp = get_empty_filp(); + if (!filp) { + put_unused_fd(file->fd); + return -ENFILE; + } + + filp->f_op = &uverbs_event_fops; + filp->f_vfsmnt = mntget(uverbs_event_mnt); + filp->f_dentry = dget(uverbs_event_mnt->mnt_root); + filp->f_mapping = filp->f_dentry->d_inode->i_mapping; + filp->f_flags = O_RDONLY; + filp->f_mode = FMODE_READ; + filp->private_data = file; + + fd_install(file->fd, filp); + + return 0; +} + +static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, + size_t count, loff_t *pos) +{ + struct ib_uverbs_file *file = filp->private_data; + struct ib_uverbs_cmd_hdr hdr; + + if (count < sizeof hdr) + return -EINVAL; + + if (copy_from_user(&hdr, buf, sizeof hdr)) + return -EFAULT; + + if (hdr.in_words * 4 != count) + return -EINVAL; + + if (hdr.command < 0 || hdr.command >= ARRAY_SIZE(uverbs_cmd_table)) + return -EINVAL; + + if (!file->ucontext && + hdr.command != IB_USER_VERBS_CMD_QUERY_PARAMS && + hdr.command != IB_USER_VERBS_CMD_GET_CONTEXT) + return -EINVAL; + + return uverbs_cmd_table[hdr.command](file, buf + sizeof hdr, + hdr.in_words * 4, hdr.out_words * 4); +} + +static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct ib_uverbs_file *file = filp->private_data; + + if (!file->ucontext) + return -ENODEV; + else + return file->device->ib_dev->mmap(file->ucontext, vma); +} + +static int ib_uverbs_open(struct inode *inode, struct file *filp) +{ + struct ib_uverbs_device *dev = + container_of(inode->i_cdev, struct ib_uverbs_device, dev); + struct ib_uverbs_file *file; + int i = 0; + int ret; + + if (!try_module_get(dev->ib_dev->owner)) + return -ENODEV; + + file = kmalloc(sizeof *file + + (dev->num_comp - 1) * sizeof (struct ib_uverbs_event_file), + GFP_KERNEL); + if (!file) + return -ENOMEM; + + file->device = dev; + kref_init(&file->ref); + + file->ucontext = NULL; + + ret = ib_uverbs_event_init(&file->async_file, file); + if (ret) + goto err; + + file->async_file.is_async = 1; + + kref_get(&file->ref); + + for (i = 0; i < dev->num_comp; ++i) { + ret = ib_uverbs_event_init(&file->comp_file[i], file); + if (ret) + goto err_async; + kref_get(&file->ref); + file->comp_file[i].is_async = 0; + } + + + filp->private_data = file; + + INIT_IB_EVENT_HANDLER(&file->event_handler, dev->ib_dev, + ib_uverbs_event_handler); + if (ib_register_event_handler(&file->event_handler)) + goto err_async; + + return 0; + +err_async: + while (i--) + ib_uverbs_event_release(&file->comp_file[i]); + + ib_uverbs_event_release(&file->async_file); + +err: + kref_put(&file->ref, ib_uverbs_release_file); + + return ret; +} + +static int ib_uverbs_close(struct inode *inode, struct file *filp) +{ + struct ib_uverbs_file *file = filp->private_data; + int i; + + ib_unregister_event_handler(&file->event_handler); + ib_uverbs_event_release(&file->async_file); + ib_dealloc_ucontext(file->ucontext); + + for (i = 0; i < file->device->num_comp; ++i) + ib_uverbs_event_release(&file->comp_file[i]); + + kref_put(&file->ref, ib_uverbs_release_file); + + return 0; +} + +static struct file_operations uverbs_fops = { + .owner = THIS_MODULE, + .write = ib_uverbs_write, + .open = ib_uverbs_open, + .release = ib_uverbs_close +}; + +static struct file_operations uverbs_mmap_fops = { + .owner = THIS_MODULE, + .write = ib_uverbs_write, + .mmap = ib_uverbs_mmap, + .open = ib_uverbs_open, + .release = ib_uverbs_close +}; + +static struct ib_client uverbs_client = { + .name = "uverbs", + .add = ib_uverbs_add_one, + .remove = ib_uverbs_remove_one +}; + +static ssize_t show_ibdev(struct class_device *class_dev, char *buf) +{ + struct ib_uverbs_device *dev = + container_of(class_dev, struct ib_uverbs_device, class_dev); + + return sprintf(buf, "%s\n", dev->ib_dev->name); +} +static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); + +static void ib_uverbs_release_class_dev(struct class_device *class_dev) +{ + struct ib_uverbs_device *dev = + container_of(class_dev, struct ib_uverbs_device, class_dev); + + cdev_del(&dev->dev); + clear_bit(dev->devnum, dev_map); + kfree(dev); +} + +static struct class uverbs_class = { + .name = "infiniband_verbs", + .release = ib_uverbs_release_class_dev +}; + +static ssize_t show_abi_version(struct class *class, char *buf) +{ + return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION); +} +static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); + +static void ib_uverbs_add_one(struct ib_device *device) +{ + struct ib_uverbs_device *uverbs_dev; + + if (!device->alloc_ucontext) + return; + + uverbs_dev = kmalloc(sizeof *uverbs_dev, GFP_KERNEL); + if (!uverbs_dev) + return; + + memset(uverbs_dev, 0, sizeof *uverbs_dev); + + spin_lock(&map_lock); + uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); + if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) { + spin_unlock(&map_lock); + goto err; + } + set_bit(uverbs_dev->devnum, dev_map); + spin_unlock(&map_lock); + + uverbs_dev->ib_dev = device; + uverbs_dev->num_comp = 1; + + if (device->mmap) + cdev_init(&uverbs_dev->dev, &uverbs_mmap_fops); + else + cdev_init(&uverbs_dev->dev, &uverbs_fops); + uverbs_dev->dev.owner = THIS_MODULE; + kobject_set_name(&uverbs_dev->dev.kobj, "uverbs%d", uverbs_dev->devnum); + if (cdev_add(&uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) + goto err; + + uverbs_dev->class_dev.class = &uverbs_class; + uverbs_dev->class_dev.dev = device->dma_device; + uverbs_dev->class_dev.devt = uverbs_dev->dev.dev; + snprintf(uverbs_dev->class_dev.class_id, BUS_ID_SIZE, "uverbs%d", uverbs_dev->devnum); + if (class_device_register(&uverbs_dev->class_dev)) + goto err_cdev; + + if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_ibdev)) + goto err_class; + + ib_set_client_data(device, &uverbs_client, uverbs_dev); + + return; + +err_class: + class_device_unregister(&uverbs_dev->class_dev); + +err_cdev: + cdev_del(&uverbs_dev->dev); + clear_bit(uverbs_dev->devnum, dev_map); + +err: + kfree(uverbs_dev); + return; +} + +static void ib_uverbs_remove_one(struct ib_device *device) +{ + struct ib_uverbs_device *uverbs_dev = ib_get_client_data(device, &uverbs_client); + + if (!uverbs_dev) + return; + + class_device_unregister(&uverbs_dev->class_dev); +} + +static struct super_block *uverbs_event_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) +{ + return get_sb_pseudo(fs_type, "infinibandevent:", NULL, + INFINIBANDEVENTFS_MAGIC); +} + +static struct file_system_type uverbs_event_fs = { + /* No owner field so module can be unloaded */ + .name = "infinibandeventfs", + .get_sb = uverbs_event_get_sb, + .kill_sb = kill_litter_super +}; + +static int __init ib_uverbs_init(void) +{ + int ret; + + spin_lock_init(&map_lock); + + ret = register_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES, + "infiniband_verbs"); + if (ret) { + printk(KERN_ERR "user_verbs: couldn't register device number\n"); + goto out; + } + + ret = class_register(&uverbs_class); + if (ret) { + printk(KERN_ERR "user_verbs: couldn't create class infiniband_verbs\n"); + goto out_chrdev; + } + + ret = class_create_file(&uverbs_class, &class_attr_abi_version); + if (ret) { + printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n"); + goto out_class; + } + + ret = register_filesystem(&uverbs_event_fs); + if (ret) { + printk(KERN_ERR "user_verbs: couldn't register infinibandeventfs\n"); + goto out_class; + } + + uverbs_event_mnt = kern_mount(&uverbs_event_fs); + if (IS_ERR(uverbs_event_mnt)) { + ret = PTR_ERR(uverbs_event_mnt); + printk(KERN_ERR "user_verbs: couldn't mount infinibandeventfs\n"); + goto out_fs; + } + + ret = ib_register_client(&uverbs_client); + if (ret) { + printk(KERN_ERR "user_verbs: couldn't register client\n"); + goto out_mnt; + } + + return 0; + +out_mnt: + mntput(uverbs_event_mnt); + +out_fs: + unregister_filesystem(&uverbs_event_fs); + +out_class: + class_unregister(&uverbs_class); + +out_chrdev: + unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); + +out: + return ret; +} + +static void __exit ib_uverbs_cleanup(void) +{ + ib_unregister_client(&uverbs_client); + mntput(uverbs_event_mnt); + unregister_filesystem(&uverbs_event_fs); + class_unregister(&uverbs_class); + unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); +} + +module_init(ib_uverbs_init); +module_exit(ib_uverbs_cleanup); -- cgit v1.2.3 From eb8ffbfed50e7945c024a80e3688d5beffa3b641 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:14 -0700 Subject: [PATCH] IB uverbs: memory pinning implementation Add support for pinning userspace memory regions and returning a list of pages in the region. This includes tracking pinned memory against vm_locked and preventing unprivileged users from exceeding RLIMIT_MEMLOCK. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/core/uverbs_mem.c | 221 +++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 drivers/infiniband/core/uverbs_mem.c (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_mem.c b/drivers/infiniband/core/uverbs_mem.c new file mode 100644 index 00000000000..ed550f6595b --- /dev/null +++ b/drivers/infiniband/core/uverbs_mem.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * 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. + * + * $Id: uverbs_mem.c 2743 2005-06-28 22:27:59Z roland $ + */ + +#include +#include + +#include "uverbs.h" + +struct ib_umem_account_work { + struct work_struct work; + struct mm_struct *mm; + unsigned long diff; +}; + + +static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty) +{ + struct ib_umem_chunk *chunk, *tmp; + int i; + + list_for_each_entry_safe(chunk, tmp, &umem->chunk_list, list) { + dma_unmap_sg(dev->dma_device, chunk->page_list, + chunk->nents, DMA_BIDIRECTIONAL); + for (i = 0; i < chunk->nents; ++i) { + if (umem->writable && dirty) + set_page_dirty_lock(chunk->page_list[i].page); + put_page(chunk->page_list[i].page); + } + + kfree(chunk); + } +} + +int ib_umem_get(struct ib_device *dev, struct ib_umem *mem, + void *addr, size_t size, int write) +{ + struct page **page_list; + struct ib_umem_chunk *chunk; + unsigned long locked; + unsigned long lock_limit; + unsigned long cur_base; + unsigned long npages; + int ret = 0; + int off; + int i; + + if (!can_do_mlock()) + return -EPERM; + + page_list = (struct page **) __get_free_page(GFP_KERNEL); + if (!page_list) + return -ENOMEM; + + mem->user_base = (unsigned long) addr; + mem->length = size; + mem->offset = (unsigned long) addr & ~PAGE_MASK; + mem->page_size = PAGE_SIZE; + mem->writable = write; + + INIT_LIST_HEAD(&mem->chunk_list); + + npages = PAGE_ALIGN(size + mem->offset) >> PAGE_SHIFT; + + down_write(¤t->mm->mmap_sem); + + locked = npages + current->mm->locked_vm; + lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT; + + if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) { + ret = -ENOMEM; + goto out; + } + + cur_base = (unsigned long) addr & PAGE_MASK; + + while (npages) { + ret = get_user_pages(current, current->mm, cur_base, + min_t(int, npages, + PAGE_SIZE / sizeof (struct page *)), + 1, !write, page_list, NULL); + + if (ret < 0) + goto out; + + cur_base += ret * PAGE_SIZE; + npages -= ret; + + off = 0; + + while (ret) { + chunk = kmalloc(sizeof *chunk + sizeof (struct scatterlist) * + min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK), + GFP_KERNEL); + if (!chunk) { + ret = -ENOMEM; + goto out; + } + + chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK); + for (i = 0; i < chunk->nents; ++i) { + chunk->page_list[i].page = page_list[i + off]; + chunk->page_list[i].offset = 0; + chunk->page_list[i].length = PAGE_SIZE; + } + + chunk->nmap = dma_map_sg(dev->dma_device, + &chunk->page_list[0], + chunk->nents, + DMA_BIDIRECTIONAL); + if (chunk->nmap <= 0) { + for (i = 0; i < chunk->nents; ++i) + put_page(chunk->page_list[i].page); + kfree(chunk); + + ret = -ENOMEM; + goto out; + } + + ret -= chunk->nents; + off += chunk->nents; + list_add_tail(&chunk->list, &mem->chunk_list); + } + + ret = 0; + } + +out: + if (ret < 0) + __ib_umem_release(dev, mem, 0); + else + current->mm->locked_vm = locked; + + up_write(¤t->mm->mmap_sem); + free_page((unsigned long) page_list); + + return ret; +} + +void ib_umem_release(struct ib_device *dev, struct ib_umem *umem) +{ + __ib_umem_release(dev, umem, 1); + + down_write(¤t->mm->mmap_sem); + current->mm->locked_vm -= + PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT; + up_write(¤t->mm->mmap_sem); +} + +static void ib_umem_account(void *work_ptr) +{ + struct ib_umem_account_work *work = work_ptr; + + down_write(&work->mm->mmap_sem); + work->mm->locked_vm -= work->diff; + up_write(&work->mm->mmap_sem); + mmput(work->mm); + kfree(work); +} + +void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem) +{ + struct ib_umem_account_work *work; + struct mm_struct *mm; + + __ib_umem_release(dev, umem, 1); + + mm = get_task_mm(current); + if (!mm) + return; + + /* + * We may be called with the mm's mmap_sem already held. This + * can happen when a userspace munmap() is the call that drops + * the last reference to our file and calls our release + * method. If there are memory regions to destroy, we'll end + * up here and not be able to take the mmap_sem. Therefore we + * defer the vm_locked accounting to the system workqueue. + */ + + work = kmalloc(sizeof *work, GFP_KERNEL); + if (!work) + return; + + INIT_WORK(&work->work, ib_umem_account, work); + work->mm = mm; + work->diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT; + + schedule_work(&work->work); +} -- cgit v1.2.3 From 2d927d696c088ceb22c776e1e89937dc289d4078 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:14 -0700 Subject: [PATCH] IB uverbs: hook up Kconfig/Makefile Hook up InfiniBand userspace verbs to Kconfig and the make system. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/Kconfig | 10 ++++++++++ drivers/infiniband/core/Makefile | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 3cc3ff0cccb..79c8e2dd9c3 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -7,6 +7,16 @@ config INFINIBAND any protocols you wish to use as well as drivers for your InfiniBand hardware. +config INFINIBAND_USER_VERBS + tristate "InfiniBand userspace verbs support" + depends on INFINIBAND + ---help--- + Userspace InfiniBand verbs support. This is the kernel side + of userspace verbs, which allows userspace processes to + directly access InfiniBand hardware for fast-path + operations. You will also need libibverbs and a hardware + driver library from . + source "drivers/infiniband/hw/mthca/Kconfig" source "drivers/infiniband/ulp/ipoib/Kconfig" diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index d2dbfb52c0a..e1a7cf3e863 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -1,6 +1,7 @@ EXTRA_CFLAGS += -Idrivers/infiniband/include -obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o ib_umad.o +obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o ib_umad.o +obj-$(CONFIG_INFINIBAND_USER_VERBS) += ib_uverbs.o ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ device.o fmr_pool.o cache.o @@ -10,3 +11,5 @@ ib_mad-y := mad.o smi.o agent.o ib_sa-y := sa_query.o ib_umad-y := user_mad.o + +ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_mem.o -- cgit v1.2.3 From e95975e8b87de47c08e032e7762fc7df7dfc2060 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:15 -0700 Subject: [PATCH] IB uverbs: add mthca ABI header Add the mthca_user.h header file, which defines the device-specific ABI used by the mthca low-level driver for kernel/user communication. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/mthca/mthca_user.h | 81 ++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 drivers/infiniband/hw/mthca/mthca_user.h (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h new file mode 100644 index 00000000000..3024c1b4547 --- /dev/null +++ b/drivers/infiniband/hw/mthca/mthca_user.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * 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. + * + */ + +#ifndef MTHCA_USER_H +#define MTHCA_USER_H + +#include + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + * In particular do not use pointer types -- pass pointers in __u64 + * instead. + */ + +struct mthca_alloc_ucontext_resp { + __u32 qp_tab_size; + __u32 uarc_size; +}; + +struct mthca_alloc_pd_resp { + __u32 pdn; + __u32 reserved; +}; + +struct mthca_create_cq { + __u32 lkey; + __u32 pdn; + __u64 arm_db_page; + __u64 set_db_page; + __u32 arm_db_index; + __u32 set_db_index; +}; + +struct mthca_create_cq_resp { + __u32 cqn; + __u32 reserved; +}; + +struct mthca_create_qp { + __u32 lkey; + __u32 reserved; + __u64 sq_db_page; + __u64 rq_db_page; + __u32 sq_db_index; + __u32 rq_db_index; +}; + +#endif /* MTHCA_USER_H */ -- cgit v1.2.3 From 56483ec1b70221f8c9838ccc9a89b43d9de66993 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:16 -0700 Subject: [PATCH] IB uverbs: add mthca user doorbell record support Add support for userspace doorbell records to mthca. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/mthca/mthca_memfree.c | 141 +++++++++++++++++++++++++++- drivers/infiniband/hw/mthca/mthca_memfree.h | 14 ++- 2 files changed, 149 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 6d3b05dd9e3..2a864615035 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -47,6 +48,15 @@ enum { MTHCA_TABLE_CHUNK_SIZE = 1 << 18 }; +struct mthca_user_db_table { + struct semaphore mutex; + struct { + u64 uvirt; + struct scatterlist mem; + int refcount; + } page[0]; +}; + void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm) { struct mthca_icm_chunk *chunk, *tmp; @@ -344,13 +354,133 @@ void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table) kfree(table); } -static u64 mthca_uarc_virt(struct mthca_dev *dev, int page) +static u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int page) { return dev->uar_table.uarc_base + - dev->driver_uar.index * dev->uar_table.uarc_size + + uar->index * dev->uar_table.uarc_size + page * 4096; } +int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index, u64 uaddr) +{ + int ret = 0; + u8 status; + int i; + + if (!mthca_is_memfree(dev)) + return 0; + + if (index < 0 || index > dev->uar_table.uarc_size / 8) + return -EINVAL; + + down(&db_tab->mutex); + + i = index / MTHCA_DB_REC_PER_PAGE; + + if ((db_tab->page[i].refcount >= MTHCA_DB_REC_PER_PAGE) || + (db_tab->page[i].uvirt && db_tab->page[i].uvirt != uaddr) || + (uaddr & 4095)) { + ret = -EINVAL; + goto out; + } + + if (db_tab->page[i].refcount) { + ++db_tab->page[i].refcount; + goto out; + } + + ret = get_user_pages(current, current->mm, uaddr & PAGE_MASK, 1, 1, 0, + &db_tab->page[i].mem.page, NULL); + if (ret < 0) + goto out; + + db_tab->page[i].mem.length = 4096; + db_tab->page[i].mem.offset = uaddr & ~PAGE_MASK; + + ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE); + if (ret < 0) { + put_page(db_tab->page[i].mem.page); + goto out; + } + + ret = mthca_MAP_ICM_page(dev, sg_dma_address(&db_tab->page[i].mem), + mthca_uarc_virt(dev, uar, i), &status); + if (!ret && status) + ret = -EINVAL; + if (ret) { + pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE); + put_page(db_tab->page[i].mem.page); + goto out; + } + + db_tab->page[i].uvirt = uaddr; + db_tab->page[i].refcount = 1; + +out: + up(&db_tab->mutex); + return ret; +} + +void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index) +{ + if (!mthca_is_memfree(dev)) + return; + + /* + * To make our bookkeeping simpler, we don't unmap DB + * pages until we clean up the whole db table. + */ + + down(&db_tab->mutex); + + --db_tab->page[index / MTHCA_DB_REC_PER_PAGE].refcount; + + up(&db_tab->mutex); +} + +struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev) +{ + struct mthca_user_db_table *db_tab; + int npages; + int i; + + if (!mthca_is_memfree(dev)) + return NULL; + + npages = dev->uar_table.uarc_size / 4096; + db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL); + if (!db_tab) + return ERR_PTR(-ENOMEM); + + init_MUTEX(&db_tab->mutex); + for (i = 0; i < npages; ++i) { + db_tab->page[i].refcount = 0; + db_tab->page[i].uvirt = 0; + } + + return db_tab; +} + +void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab) +{ + int i; + u8 status; + + if (!mthca_is_memfree(dev)) + return; + + for (i = 0; i < dev->uar_table.uarc_size / 4096; ++i) { + if (db_tab->page[i].uvirt) { + mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status); + pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE); + put_page(db_tab->page[i].mem.page); + } + } +} + int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db) { int group; @@ -407,7 +537,8 @@ int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db) } memset(page->db_rec, 0, 4096); - ret = mthca_MAP_ICM_page(dev, page->mapping, mthca_uarc_virt(dev, i), &status); + ret = mthca_MAP_ICM_page(dev, page->mapping, + mthca_uarc_virt(dev, &dev->driver_uar, i), &status); if (!ret && status) ret = -EINVAL; if (ret) { @@ -461,7 +592,7 @@ void mthca_free_db(struct mthca_dev *dev, int type, int db_index) if (bitmap_empty(page->used, MTHCA_DB_REC_PER_PAGE) && i >= dev->db_tab->max_group1 - 1) { - mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status); + mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status); dma_free_coherent(&dev->pdev->dev, 4096, page->db_rec, page->mapping); @@ -530,7 +661,7 @@ void mthca_cleanup_db_tab(struct mthca_dev *dev) if (!bitmap_empty(dev->db_tab->page[i].used, MTHCA_DB_REC_PER_PAGE)) mthca_warn(dev, "Kernel UARC page %d not empty\n", i); - mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status); + mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status); dma_free_coherent(&dev->pdev->dev, 4096, dev->db_tab->page[i].db_rec, diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h index fe7be2a6bc4..4761d844cb5 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.h +++ b/drivers/infiniband/hw/mthca/mthca_memfree.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -148,7 +149,7 @@ struct mthca_db_table { struct semaphore mutex; }; -enum { +enum mthca_db_type { MTHCA_DB_TYPE_INVALID = 0x0, MTHCA_DB_TYPE_CQ_SET_CI = 0x1, MTHCA_DB_TYPE_CQ_ARM = 0x2, @@ -158,6 +159,17 @@ enum { MTHCA_DB_TYPE_GROUP_SEP = 0x7 }; +struct mthca_user_db_table; +struct mthca_uar; + +int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index, u64 uaddr); +void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index); +struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev); +void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab); + int mthca_init_db_tab(struct mthca_dev *dev); void mthca_cleanup_db_tab(struct mthca_dev *dev); int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db); -- cgit v1.2.3 From 5e0b537c7d94efe3fea0fee8e2533c3231a8af75 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:16 -0700 Subject: [PATCH] IB uverbs: add mthca user context support Add support for managing userspace contexts to mthca. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/mthca/mthca_provider.c | 58 ++++++++++++++++++++++++++++ drivers/infiniband/hw/mthca/mthca_provider.h | 14 +++++++ 2 files changed, 72 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 0cc86f8e185..bfd33a47002 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -37,6 +38,8 @@ #include "mthca_dev.h" #include "mthca_cmd.h" +#include "mthca_user.h" +#include "mthca_memfree.h" static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *props) @@ -284,6 +287,59 @@ static int mthca_query_gid(struct ib_device *ibdev, u8 port, return err; } +static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata) +{ + struct mthca_alloc_ucontext_resp uresp; + struct mthca_ucontext *context; + int err; + + memset(&uresp, 0, sizeof uresp); + + uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps; + if (mthca_is_memfree(to_mdev(ibdev))) + uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size; + else + uresp.uarc_size = 0; + + context = kmalloc(sizeof *context, GFP_KERNEL); + if (!context) + return ERR_PTR(-ENOMEM); + + err = mthca_uar_alloc(to_mdev(ibdev), &context->uar); + if (err) { + kfree(context); + return ERR_PTR(err); + } + + context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev)); + if (IS_ERR(context->db_tab)) { + err = PTR_ERR(context->db_tab); + mthca_uar_free(to_mdev(ibdev), &context->uar); + kfree(context); + return ERR_PTR(err); + } + + if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) { + mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, context->db_tab); + mthca_uar_free(to_mdev(ibdev), &context->uar); + kfree(context); + return ERR_PTR(-EFAULT); + } + + return &context->ibucontext; +} + +static int mthca_dealloc_ucontext(struct ib_ucontext *context) +{ + mthca_cleanup_user_db_tab(to_mdev(context->device), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab); + mthca_uar_free(to_mdev(context->device), &to_mucontext(context)->uar); + kfree(to_mucontext(context)); + + return 0; +} + static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev, struct ib_ucontext *context, struct ib_udata *udata) @@ -708,6 +764,8 @@ int mthca_register_device(struct mthca_dev *dev) dev->ib_dev.modify_port = mthca_modify_port; dev->ib_dev.query_pkey = mthca_query_pkey; dev->ib_dev.query_gid = mthca_query_gid; + dev->ib_dev.alloc_ucontext = mthca_alloc_ucontext; + dev->ib_dev.dealloc_ucontext = mthca_dealloc_ucontext; dev->ib_dev.alloc_pd = mthca_alloc_pd; dev->ib_dev.dealloc_pd = mthca_dealloc_pd; dev->ib_dev.create_ah = mthca_ah_create; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 4d976cccb1a..27cd43cadd4 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -54,6 +55,14 @@ struct mthca_uar { int index; }; +struct mthca_user_db_table; + +struct mthca_ucontext { + struct ib_ucontext ibucontext; + struct mthca_uar uar; + struct mthca_user_db_table *db_tab; +}; + struct mthca_mtt; struct mthca_mr { @@ -236,6 +245,11 @@ struct mthca_sqp { dma_addr_t header_dma; }; +static inline struct mthca_ucontext *to_mucontext(struct ib_ucontext *ibucontext) +{ + return container_of(ibucontext, struct mthca_ucontext, ibucontext); +} + static inline struct mthca_fmr *to_mfmr(struct ib_fmr *ibmr) { return container_of(ibmr, struct mthca_fmr, ibmr); -- cgit v1.2.3 From 53b8b3ffd5e0b10f3c683096a663d0cc22179c43 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:17 -0700 Subject: [PATCH] IB uverbs: add mthca mmap support Add support for mmap() method to mthca, so that userspace can get access to doorbell registers. This allows userspace to get direct access to the HCA for data path operations. Each userspace context gets its own copy of the doorbell registers and is only allowed to use resources that the kernel has given it access to. In other words, this is safe. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/mthca/mthca_provider.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index bfd33a47002..9acb8c54ce4 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -35,6 +35,7 @@ */ #include +#include #include "mthca_dev.h" #include "mthca_cmd.h" @@ -340,6 +341,22 @@ static int mthca_dealloc_ucontext(struct ib_ucontext *context) return 0; } +static int mthca_mmap_uar(struct ib_ucontext *context, + struct vm_area_struct *vma) +{ + if (vma->vm_end - vma->vm_start != PAGE_SIZE) + return -EINVAL; + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (remap_pfn_range(vma, vma->vm_start, + to_mucontext(context)->uar.pfn, + PAGE_SIZE, vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev, struct ib_ucontext *context, struct ib_udata *udata) @@ -766,6 +783,7 @@ int mthca_register_device(struct mthca_dev *dev) dev->ib_dev.query_gid = mthca_query_gid; dev->ib_dev.alloc_ucontext = mthca_alloc_ucontext; dev->ib_dev.dealloc_ucontext = mthca_dealloc_ucontext; + dev->ib_dev.mmap = mthca_mmap_uar; dev->ib_dev.alloc_pd = mthca_alloc_pd; dev->ib_dev.dealloc_pd = mthca_dealloc_pd; dev->ib_dev.create_ah = mthca_ah_create; -- cgit v1.2.3 From 99264c1ee2ce908f95c075cce97698758a793b58 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:18 -0700 Subject: [PATCH] IB uverbs: add mthca user PD support Add support for userspace protection domains (PDs) to mthca. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/mthca/mthca_dev.h | 3 ++- drivers/infiniband/hw/mthca/mthca_main.c | 2 +- drivers/infiniband/hw/mthca/mthca_pd.c | 24 +++++++++++++++--------- drivers/infiniband/hw/mthca/mthca_provider.c | 10 +++++++++- drivers/infiniband/hw/mthca/mthca_provider.h | 1 + 5 files changed, 28 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 4127f09dc5e..3801facf6f1 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -378,7 +379,7 @@ void mthca_unregister_device(struct mthca_dev *dev); int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar); void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar); -int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd); +int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd); void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd); struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size); diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 09519b604c0..2ef916859e1 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -665,7 +665,7 @@ static int __devinit mthca_setup_hca(struct mthca_dev *dev) goto err_pd_table_free; } - err = mthca_pd_alloc(dev, &dev->driver_pd); + err = mthca_pd_alloc(dev, 1, &dev->driver_pd); if (err) { mthca_err(dev, "Failed to create driver PD, " "aborting.\n"); diff --git a/drivers/infiniband/hw/mthca/mthca_pd.c b/drivers/infiniband/hw/mthca/mthca_pd.c index ea66847e4ea..c2c899844e9 100644 --- a/drivers/infiniband/hw/mthca/mthca_pd.c +++ b/drivers/infiniband/hw/mthca/mthca_pd.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -37,23 +38,27 @@ #include "mthca_dev.h" -int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd) +int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd) { - int err; + int err = 0; might_sleep(); + pd->privileged = privileged; + atomic_set(&pd->sqp_count, 0); pd->pd_num = mthca_alloc(&dev->pd_table.alloc); if (pd->pd_num == -1) return -ENOMEM; - err = mthca_mr_alloc_notrans(dev, pd->pd_num, - MTHCA_MPT_FLAG_LOCAL_READ | - MTHCA_MPT_FLAG_LOCAL_WRITE, - &pd->ntmr); - if (err) - mthca_free(&dev->pd_table.alloc, pd->pd_num); + if (privileged) { + err = mthca_mr_alloc_notrans(dev, pd->pd_num, + MTHCA_MPT_FLAG_LOCAL_READ | + MTHCA_MPT_FLAG_LOCAL_WRITE, + &pd->ntmr); + if (err) + mthca_free(&dev->pd_table.alloc, pd->pd_num); + } return err; } @@ -61,7 +66,8 @@ int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd) void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd) { might_sleep(); - mthca_free_mr(dev, &pd->ntmr); + if (pd->privileged) + mthca_free_mr(dev, &pd->ntmr); mthca_free(&dev->pd_table.alloc, pd->pd_num); } diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 9acb8c54ce4..318356c19ab 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -368,12 +368,20 @@ static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev, if (!pd) return ERR_PTR(-ENOMEM); - err = mthca_pd_alloc(to_mdev(ibdev), pd); + err = mthca_pd_alloc(to_mdev(ibdev), !context, pd); if (err) { kfree(pd); return ERR_PTR(err); } + if (context) { + if (ib_copy_to_udata(udata, &pd->pd_num, sizeof (__u32))) { + mthca_pd_free(to_mdev(ibdev), pd); + kfree(pd); + return ERR_PTR(-EFAULT); + } + } + return &pd->ibpd; } diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 27cd43cadd4..579d10cd142 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -92,6 +92,7 @@ struct mthca_pd { u32 pd_num; atomic_t sqp_count; struct mthca_mr ntmr; + int privileged; }; struct mthca_eq { -- cgit v1.2.3 From 24d4281be0598d2d4ab9a2ffb1b78f5af0ffaddf Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:19 -0700 Subject: [PATCH] IB uverbs: add mthca user MR support Add support for userspace memory regions (MRs) to mthca. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/mthca/mthca_provider.c | 82 ++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 318356c19ab..bbdfcbe6bad 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -654,6 +654,87 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd, return &mr->ibmr; } +static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, + int acc, struct ib_udata *udata) +{ + struct mthca_dev *dev = to_mdev(pd->device); + struct ib_umem_chunk *chunk; + struct mthca_mr *mr; + u64 *pages; + int shift, n, len; + int i, j, k; + int err = 0; + + shift = ffs(region->page_size) - 1; + + mr = kmalloc(sizeof *mr, GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + n = 0; + list_for_each_entry(chunk, ®ion->chunk_list, list) + n += chunk->nents; + + mr->mtt = mthca_alloc_mtt(dev, n); + if (IS_ERR(mr->mtt)) { + err = PTR_ERR(mr->mtt); + goto err; + } + + pages = (u64 *) __get_free_page(GFP_KERNEL); + if (!pages) { + err = -ENOMEM; + goto err_mtt; + } + + i = n = 0; + + list_for_each_entry(chunk, ®ion->chunk_list, list) + for (j = 0; j < chunk->nmap; ++j) { + len = sg_dma_len(&chunk->page_list[j]) >> shift; + for (k = 0; k < len; ++k) { + pages[i++] = sg_dma_address(&chunk->page_list[j]) + + region->page_size * k; + /* + * Be friendly to WRITE_MTT command + * and leave two empty slots for the + * index and reserved fields of the + * mailbox. + */ + if (i == PAGE_SIZE / sizeof (u64) - 2) { + err = mthca_write_mtt(dev, mr->mtt, + n, pages, i); + if (err) + goto mtt_done; + n += i; + i = 0; + } + } + } + + if (i) + err = mthca_write_mtt(dev, mr->mtt, n, pages, i); +mtt_done: + free_page((unsigned long) pages); + if (err) + goto err_mtt; + + err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, region->virt_base, + region->length, convert_access(acc), mr); + + if (err) + goto err_mtt; + + return &mr->ibmr; + +err_mtt: + mthca_free_mtt(dev, mr->mtt); + +err: + kfree(mr); + return ERR_PTR(err); +} + static int mthca_dereg_mr(struct ib_mr *mr) { struct mthca_mr *mmr = to_mmr(mr); @@ -804,6 +885,7 @@ int mthca_register_device(struct mthca_dev *dev) dev->ib_dev.poll_cq = mthca_poll_cq; dev->ib_dev.get_dma_mr = mthca_get_dma_mr; dev->ib_dev.reg_phys_mr = mthca_reg_phys_mr; + dev->ib_dev.reg_user_mr = mthca_reg_user_mr; dev->ib_dev.dereg_mr = mthca_dereg_mr; if (dev->mthca_flags & MTHCA_FLAG_FMR) { -- cgit v1.2.3 From 74c2174e7be52f9d2d210511bf3b490f4b41574c Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:19 -0700 Subject: [PATCH] IB uverbs: add mthca user CQ support Add support for userspace completion queues (CQs) to mthca. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/mthca/mthca_cq.c | 76 ++++++++++++++++------------ drivers/infiniband/hw/mthca/mthca_dev.h | 1 + drivers/infiniband/hw/mthca/mthca_provider.c | 69 ++++++++++++++++++++++--- drivers/infiniband/hw/mthca/mthca_provider.h | 1 + 4 files changed, 110 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 766e9031ec4..b5aea7b869f 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -742,6 +743,7 @@ err_out: } int mthca_init_cq(struct mthca_dev *dev, int nent, + struct mthca_ucontext *ctx, u32 pdn, struct mthca_cq *cq) { int size = nent * MTHCA_CQ_ENTRY_SIZE; @@ -753,30 +755,33 @@ int mthca_init_cq(struct mthca_dev *dev, int nent, might_sleep(); - cq->ibcq.cqe = nent - 1; + cq->ibcq.cqe = nent - 1; + cq->is_kernel = !ctx; cq->cqn = mthca_alloc(&dev->cq_table.alloc); if (cq->cqn == -1) return -ENOMEM; if (mthca_is_memfree(dev)) { - cq->arm_sn = 1; - err = mthca_table_get(dev, dev->cq_table.table, cq->cqn); if (err) goto err_out; - err = -ENOMEM; + if (cq->is_kernel) { + cq->arm_sn = 1; + + err = -ENOMEM; - cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, - cq->cqn, &cq->set_ci_db); - if (cq->set_ci_db_index < 0) - goto err_out_icm; + cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, + cq->cqn, &cq->set_ci_db); + if (cq->set_ci_db_index < 0) + goto err_out_icm; - cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM, - cq->cqn, &cq->arm_db); - if (cq->arm_db_index < 0) - goto err_out_ci; + cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM, + cq->cqn, &cq->arm_db); + if (cq->arm_db_index < 0) + goto err_out_ci; + } } mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); @@ -785,12 +790,14 @@ int mthca_init_cq(struct mthca_dev *dev, int nent, cq_context = mailbox->buf; - err = mthca_alloc_cq_buf(dev, size, cq); - if (err) - goto err_out_mailbox; + if (cq->is_kernel) { + err = mthca_alloc_cq_buf(dev, size, cq); + if (err) + goto err_out_mailbox; - for (i = 0; i < nent; ++i) - set_cqe_hw(get_cqe(cq, i)); + for (i = 0; i < nent; ++i) + set_cqe_hw(get_cqe(cq, i)); + } spin_lock_init(&cq->lock); atomic_set(&cq->refcount, 1); @@ -801,11 +808,14 @@ int mthca_init_cq(struct mthca_dev *dev, int nent, MTHCA_CQ_STATE_DISARMED | MTHCA_CQ_FLAG_TR); cq_context->start = cpu_to_be64(0); - cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24 | - dev->driver_uar.index); + cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24); + if (ctx) + cq_context->logsize_usrpage |= cpu_to_be32(ctx->uar.index); + else + cq_context->logsize_usrpage |= cpu_to_be32(dev->driver_uar.index); cq_context->error_eqn = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn); cq_context->comp_eqn = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn); - cq_context->pd = cpu_to_be32(dev->driver_pd.pd_num); + cq_context->pd = cpu_to_be32(pdn); cq_context->lkey = cpu_to_be32(cq->mr.ibmr.lkey); cq_context->cqn = cpu_to_be32(cq->cqn); @@ -843,18 +853,20 @@ int mthca_init_cq(struct mthca_dev *dev, int nent, return 0; err_out_free_mr: - mthca_free_mr(dev, &cq->mr); - mthca_free_cq_buf(dev, cq); + if (cq->is_kernel) { + mthca_free_mr(dev, &cq->mr); + mthca_free_cq_buf(dev, cq); + } err_out_mailbox: mthca_free_mailbox(dev, mailbox); err_out_arm: - if (mthca_is_memfree(dev)) + if (cq->is_kernel && mthca_is_memfree(dev)) mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index); err_out_ci: - if (mthca_is_memfree(dev)) + if (cq->is_kernel && mthca_is_memfree(dev)) mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index); err_out_icm: @@ -892,7 +904,8 @@ void mthca_free_cq(struct mthca_dev *dev, int j; printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n", - cq->cqn, cq->cons_index, !!next_cqe_sw(cq)); + cq->cqn, cq->cons_index, + cq->is_kernel ? !!next_cqe_sw(cq) : 0); for (j = 0; j < 16; ++j) printk(KERN_ERR "[%2x] %08x\n", j * 4, be32_to_cpu(ctx[j])); } @@ -910,12 +923,13 @@ void mthca_free_cq(struct mthca_dev *dev, atomic_dec(&cq->refcount); wait_event(cq->wait, !atomic_read(&cq->refcount)); - mthca_free_mr(dev, &cq->mr); - mthca_free_cq_buf(dev, cq); - - if (mthca_is_memfree(dev)) { - mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index); - mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index); + if (cq->is_kernel) { + mthca_free_mr(dev, &cq->mr); + mthca_free_cq_buf(dev, cq); + if (mthca_is_memfree(dev)) { + mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index); + mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index); + } } mthca_table_put(dev, dev->cq_table.table, cq->cqn); diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 3801facf6f1..751f69479a7 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -414,6 +414,7 @@ int mthca_poll_cq(struct ib_cq *ibcq, int num_entries, int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify); int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify); int mthca_init_cq(struct mthca_dev *dev, int nent, + struct mthca_ucontext *ctx, u32 pdn, struct mthca_cq *cq); void mthca_free_cq(struct mthca_dev *dev, struct mthca_cq *cq); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index bbdfcbe6bad..9feb7618ba4 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -497,28 +497,85 @@ static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries, struct ib_ucontext *context, struct ib_udata *udata) { + struct mthca_create_cq ucmd; struct mthca_cq *cq; int nent; int err; + if (context) { + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) + return ERR_PTR(-EFAULT); + + err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, + ucmd.set_db_index, ucmd.set_db_page); + if (err) + return ERR_PTR(err); + + err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, + ucmd.arm_db_index, ucmd.arm_db_page); + if (err) + goto err_unmap_set; + } + cq = kmalloc(sizeof *cq, GFP_KERNEL); - if (!cq) - return ERR_PTR(-ENOMEM); + if (!cq) { + err = -ENOMEM; + goto err_unmap_arm; + } + + if (context) { + cq->mr.ibmr.lkey = ucmd.lkey; + cq->set_ci_db_index = ucmd.set_db_index; + cq->arm_db_index = ucmd.arm_db_index; + } for (nent = 1; nent <= entries; nent <<= 1) ; /* nothing */ - err = mthca_init_cq(to_mdev(ibdev), nent, cq); - if (err) { - kfree(cq); - cq = ERR_PTR(err); + err = mthca_init_cq(to_mdev(ibdev), nent, + context ? to_mucontext(context) : NULL, + context ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num, + cq); + if (err) + goto err_free; + + if (context && ib_copy_to_udata(udata, &cq->cqn, sizeof (__u32))) { + mthca_free_cq(to_mdev(ibdev), cq); + goto err_free; } return &cq->ibcq; + +err_free: + kfree(cq); + +err_unmap_arm: + if (context) + mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, ucmd.arm_db_index); + +err_unmap_set: + if (context) + mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, ucmd.set_db_index); + + return ERR_PTR(err); } static int mthca_destroy_cq(struct ib_cq *cq) { + if (cq->uobject) { + mthca_unmap_user_db(to_mdev(cq->device), + &to_mucontext(cq->uobject->context)->uar, + to_mucontext(cq->uobject->context)->db_tab, + to_mcq(cq)->arm_db_index); + mthca_unmap_user_db(to_mdev(cq->device), + &to_mucontext(cq->uobject->context)->uar, + to_mucontext(cq->uobject->context)->db_tab, + to_mcq(cq)->set_ci_db_index); + } mthca_free_cq(to_mdev(cq->device), to_mcq(cq)); kfree(cq); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 579d10cd142..1d032791cc8 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -177,6 +177,7 @@ struct mthca_cq { int cqn; u32 cons_index; int is_direct; + int is_kernel; /* Next fields are Arbel only */ int set_ci_db_index; -- cgit v1.2.3 From 80c8ec2c04e539aac4e9810a46bc04c1b424b4dd Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 7 Jul 2005 17:57:20 -0700 Subject: [PATCH] IB uverbs: add mthca user QP support Add support for userspace queue pairs (QPs) to mthca. Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/infiniband/hw/mthca/mthca_dev.h | 2 + drivers/infiniband/hw/mthca/mthca_provider.c | 80 ++++++++-- drivers/infiniband/hw/mthca/mthca_qp.c | 215 ++++++++++++++++++--------- 3 files changed, 212 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 751f69479a7..5ecdd2eeeb0 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -440,12 +440,14 @@ int mthca_alloc_qp(struct mthca_dev *dev, struct mthca_cq *recv_cq, enum ib_qp_type type, enum ib_sig_type send_policy, + struct ib_qp_cap *cap, struct mthca_qp *qp); int mthca_alloc_sqp(struct mthca_dev *dev, struct mthca_pd *pd, struct mthca_cq *send_cq, struct mthca_cq *recv_cq, enum ib_sig_type send_policy, + struct ib_qp_cap *cap, int qpn, int port, struct mthca_sqp *sqp); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 9feb7618ba4..7a58ce90e17 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -424,6 +424,7 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *init_attr, struct ib_udata *udata) { + struct mthca_create_qp ucmd; struct mthca_qp *qp; int err; @@ -432,41 +433,82 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd, case IB_QPT_UC: case IB_QPT_UD: { + struct mthca_ucontext *context; + qp = kmalloc(sizeof *qp, GFP_KERNEL); if (!qp) return ERR_PTR(-ENOMEM); - qp->sq.max = init_attr->cap.max_send_wr; - qp->rq.max = init_attr->cap.max_recv_wr; - qp->sq.max_gs = init_attr->cap.max_send_sge; - qp->rq.max_gs = init_attr->cap.max_recv_sge; + if (pd->uobject) { + context = to_mucontext(pd->uobject->context); + + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) + return ERR_PTR(-EFAULT); + + err = mthca_map_user_db(to_mdev(pd->device), &context->uar, + context->db_tab, + ucmd.sq_db_index, ucmd.sq_db_page); + if (err) { + kfree(qp); + return ERR_PTR(err); + } + + err = mthca_map_user_db(to_mdev(pd->device), &context->uar, + context->db_tab, + ucmd.rq_db_index, ucmd.rq_db_page); + if (err) { + mthca_unmap_user_db(to_mdev(pd->device), + &context->uar, + context->db_tab, + ucmd.sq_db_index); + kfree(qp); + return ERR_PTR(err); + } + + qp->mr.ibmr.lkey = ucmd.lkey; + qp->sq.db_index = ucmd.sq_db_index; + qp->rq.db_index = ucmd.rq_db_index; + } err = mthca_alloc_qp(to_mdev(pd->device), to_mpd(pd), to_mcq(init_attr->send_cq), to_mcq(init_attr->recv_cq), init_attr->qp_type, init_attr->sq_sig_type, - qp); + &init_attr->cap, qp); + + if (err && pd->uobject) { + context = to_mucontext(pd->uobject->context); + + mthca_unmap_user_db(to_mdev(pd->device), + &context->uar, + context->db_tab, + ucmd.sq_db_index); + mthca_unmap_user_db(to_mdev(pd->device), + &context->uar, + context->db_tab, + ucmd.rq_db_index); + } + qp->ibqp.qp_num = qp->qpn; break; } case IB_QPT_SMI: case IB_QPT_GSI: { + /* Don't allow userspace to create special QPs */ + if (pd->uobject) + return ERR_PTR(-EINVAL); + qp = kmalloc(sizeof (struct mthca_sqp), GFP_KERNEL); if (!qp) return ERR_PTR(-ENOMEM); - qp->sq.max = init_attr->cap.max_send_wr; - qp->rq.max = init_attr->cap.max_recv_wr; - qp->sq.max_gs = init_attr->cap.max_send_sge; - qp->rq.max_gs = init_attr->cap.max_recv_sge; - qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1; err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd), to_mcq(init_attr->send_cq), to_mcq(init_attr->recv_cq), - init_attr->sq_sig_type, + init_attr->sq_sig_type, &init_attr->cap, qp->ibqp.qp_num, init_attr->port_num, to_msqp(qp)); break; @@ -481,13 +523,27 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd, return ERR_PTR(err); } - init_attr->cap.max_inline_data = 0; + init_attr->cap.max_inline_data = 0; + init_attr->cap.max_send_wr = qp->sq.max; + init_attr->cap.max_recv_wr = qp->rq.max; + init_attr->cap.max_send_sge = qp->sq.max_gs; + init_attr->cap.max_recv_sge = qp->rq.max_gs; return &qp->ibqp; } static int mthca_destroy_qp(struct ib_qp *qp) { + if (qp->uobject) { + mthca_unmap_user_db(to_mdev(qp->device), + &to_mucontext(qp->uobject->context)->uar, + to_mucontext(qp->uobject->context)->db_tab, + to_mqp(qp)->sq.db_index); + mthca_unmap_user_db(to_mdev(qp->device), + &to_mucontext(qp->uobject->context)->uar, + to_mucontext(qp->uobject->context)->db_tab, + to_mqp(qp)->rq.db_index); + } mthca_free_qp(to_mdev(qp->device), to_mqp(qp)); kfree(qp); return 0; diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 163a8ef4186..f7126b14d5a 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -46,7 +47,9 @@ enum { MTHCA_MAX_DIRECT_QP_SIZE = 4 * PAGE_SIZE, MTHCA_ACK_REQ_FREQ = 10, MTHCA_FLIGHT_LIMIT = 9, - MTHCA_UD_HEADER_SIZE = 72 /* largest UD header possible */ + MTHCA_UD_HEADER_SIZE = 72, /* largest UD header possible */ + MTHCA_INLINE_HEADER_SIZE = 4, /* data segment overhead for inline */ + MTHCA_INLINE_CHUNK_SIZE = 16 /* inline data segment chunk */ }; enum { @@ -689,7 +692,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) /* leave arbel_sched_queue as 0 */ - qp_context->usr_page = cpu_to_be32(dev->driver_uar.index); + if (qp->ibqp.uobject) + qp_context->usr_page = + cpu_to_be32(to_mucontext(qp->ibqp.uobject->context)->uar.index); + else + qp_context->usr_page = cpu_to_be32(dev->driver_uar.index); qp_context->local_qpn = cpu_to_be32(qp->qpn); if (attr_mask & IB_QP_DEST_QPN) { qp_context->remote_qpn = cpu_to_be32(attr->dest_qp_num); @@ -954,6 +961,15 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev, qp->send_wqe_offset = ALIGN(qp->rq.max << qp->rq.wqe_shift, 1 << qp->sq.wqe_shift); + + /* + * If this is a userspace QP, we don't actually have to + * allocate anything. All we need is to calculate the WQE + * sizes and the send_wqe_offset, so we're done now. + */ + if (pd->ibpd.uobject) + return 0; + size = PAGE_ALIGN(qp->send_wqe_offset + (qp->sq.max << qp->sq.wqe_shift)); @@ -1053,10 +1069,32 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev, return err; } -static int mthca_alloc_memfree(struct mthca_dev *dev, +static void mthca_free_wqe_buf(struct mthca_dev *dev, struct mthca_qp *qp) { - int ret = 0; + int i; + int size = PAGE_ALIGN(qp->send_wqe_offset + + (qp->sq.max << qp->sq.wqe_shift)); + + if (qp->is_direct) { + dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf, + pci_unmap_addr(&qp->queue.direct, mapping)); + } else { + for (i = 0; i < size / PAGE_SIZE; ++i) { + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + qp->queue.page_list[i].buf, + pci_unmap_addr(&qp->queue.page_list[i], + mapping)); + } + } + + kfree(qp->wrid); +} + +static int mthca_map_memfree(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + int ret; if (mthca_is_memfree(dev)) { ret = mthca_table_get(dev, dev->qp_table.qp_table, qp->qpn); @@ -1067,35 +1105,15 @@ static int mthca_alloc_memfree(struct mthca_dev *dev, if (ret) goto err_qpc; - ret = mthca_table_get(dev, dev->qp_table.rdb_table, - qp->qpn << dev->qp_table.rdb_shift); - if (ret) - goto err_eqpc; - - qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ, - qp->qpn, &qp->rq.db); - if (qp->rq.db_index < 0) { - ret = -ENOMEM; - goto err_rdb; - } + ret = mthca_table_get(dev, dev->qp_table.rdb_table, + qp->qpn << dev->qp_table.rdb_shift); + if (ret) + goto err_eqpc; - qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ, - qp->qpn, &qp->sq.db); - if (qp->sq.db_index < 0) { - ret = -ENOMEM; - goto err_rq_db; - } } return 0; -err_rq_db: - mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index); - -err_rdb: - mthca_table_put(dev, dev->qp_table.rdb_table, - qp->qpn << dev->qp_table.rdb_shift); - err_eqpc: mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn); @@ -1105,6 +1123,35 @@ err_qpc: return ret; } +static void mthca_unmap_memfree(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + mthca_table_put(dev, dev->qp_table.rdb_table, + qp->qpn << dev->qp_table.rdb_shift); + mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn); + mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn); +} + +static int mthca_alloc_memfree(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + int ret = 0; + + if (mthca_is_memfree(dev)) { + qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ, + qp->qpn, &qp->rq.db); + if (qp->rq.db_index < 0) + return ret; + + qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ, + qp->qpn, &qp->sq.db); + if (qp->sq.db_index < 0) + mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index); + } + + return ret; +} + static void mthca_free_memfree(struct mthca_dev *dev, struct mthca_qp *qp) { @@ -1112,11 +1159,6 @@ static void mthca_free_memfree(struct mthca_dev *dev, mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index); mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index); } - - mthca_table_put(dev, dev->qp_table.rdb_table, - qp->qpn << dev->qp_table.rdb_shift); - mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn); - mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn); } static void mthca_wq_init(struct mthca_wq* wq) @@ -1147,13 +1189,28 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev, mthca_wq_init(&qp->sq); mthca_wq_init(&qp->rq); - ret = mthca_alloc_memfree(dev, qp); + ret = mthca_map_memfree(dev, qp); if (ret) return ret; ret = mthca_alloc_wqe_buf(dev, pd, qp); if (ret) { - mthca_free_memfree(dev, qp); + mthca_unmap_memfree(dev, qp); + return ret; + } + + /* + * If this is a userspace QP, we're done now. The doorbells + * will be allocated and buffers will be initialized in + * userspace. + */ + if (pd->ibpd.uobject) + return 0; + + ret = mthca_alloc_memfree(dev, qp); + if (ret) { + mthca_free_wqe_buf(dev, qp); + mthca_unmap_memfree(dev, qp); return ret; } @@ -1186,22 +1243,39 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev, return 0; } -static void mthca_align_qp_size(struct mthca_dev *dev, struct mthca_qp *qp) +static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap, + struct mthca_qp *qp) { - int i; - - if (!mthca_is_memfree(dev)) - return; + /* Sanity check QP size before proceeding */ + if (cap->max_send_wr > 65536 || cap->max_recv_wr > 65536 || + cap->max_send_sge > 64 || cap->max_recv_sge > 64) + return -EINVAL; - for (i = 0; 1 << i < qp->rq.max; ++i) - ; /* nothing */ + if (mthca_is_memfree(dev)) { + qp->rq.max = cap->max_recv_wr ? + roundup_pow_of_two(cap->max_recv_wr) : 0; + qp->sq.max = cap->max_send_wr ? + roundup_pow_of_two(cap->max_send_wr) : 0; + } else { + qp->rq.max = cap->max_recv_wr; + qp->sq.max = cap->max_send_wr; + } - qp->rq.max = 1 << i; + qp->rq.max_gs = cap->max_recv_sge; + qp->sq.max_gs = max_t(int, cap->max_send_sge, + ALIGN(cap->max_inline_data + MTHCA_INLINE_HEADER_SIZE, + MTHCA_INLINE_CHUNK_SIZE) / + sizeof (struct mthca_data_seg)); - for (i = 0; 1 << i < qp->sq.max; ++i) - ; /* nothing */ + /* + * For MLX transport we need 2 extra S/G entries: + * one for the header and one for the checksum at the end + */ + if ((qp->transport == MLX && qp->sq.max_gs + 2 > dev->limits.max_sg) || + qp->sq.max_gs > dev->limits.max_sg || qp->rq.max_gs > dev->limits.max_sg) + return -EINVAL; - qp->sq.max = 1 << i; + return 0; } int mthca_alloc_qp(struct mthca_dev *dev, @@ -1210,11 +1284,14 @@ int mthca_alloc_qp(struct mthca_dev *dev, struct mthca_cq *recv_cq, enum ib_qp_type type, enum ib_sig_type send_policy, + struct ib_qp_cap *cap, struct mthca_qp *qp) { int err; - mthca_align_qp_size(dev, qp); + err = mthca_set_qp_size(dev, cap, qp); + if (err) + return err; switch (type) { case IB_QPT_RC: qp->transport = RC; break; @@ -1247,14 +1324,17 @@ int mthca_alloc_sqp(struct mthca_dev *dev, struct mthca_cq *send_cq, struct mthca_cq *recv_cq, enum ib_sig_type send_policy, + struct ib_qp_cap *cap, int qpn, int port, struct mthca_sqp *sqp) { - int err = 0; u32 mqpn = qpn * 2 + dev->qp_table.sqp_start + port - 1; + int err; - mthca_align_qp_size(dev, &sqp->qp); + err = mthca_set_qp_size(dev, cap, &sqp->qp); + if (err) + return err; sqp->header_buf_size = sqp->qp.sq.max * MTHCA_UD_HEADER_SIZE; sqp->header_buf = dma_alloc_coherent(&dev->pdev->dev, sqp->header_buf_size, @@ -1313,8 +1393,6 @@ void mthca_free_qp(struct mthca_dev *dev, struct mthca_qp *qp) { u8 status; - int size; - int i; struct mthca_cq *send_cq; struct mthca_cq *recv_cq; @@ -1344,31 +1422,22 @@ void mthca_free_qp(struct mthca_dev *dev, if (qp->state != IB_QPS_RESET) mthca_MODIFY_QP(dev, MTHCA_TRANS_ANY2RST, qp->qpn, 0, NULL, 0, &status); - mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn); - if (qp->ibqp.send_cq != qp->ibqp.recv_cq) - mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn); - - mthca_free_mr(dev, &qp->mr); - - size = PAGE_ALIGN(qp->send_wqe_offset + - (qp->sq.max << qp->sq.wqe_shift)); + /* + * If this is a userspace QP, the buffers, MR, CQs and so on + * will be cleaned up in userspace, so all we have to do is + * unref the mem-free tables and free the QPN in our table. + */ + if (!qp->ibqp.uobject) { + mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn); + if (qp->ibqp.send_cq != qp->ibqp.recv_cq) + mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn); - if (qp->is_direct) { - pci_free_consistent(dev->pdev, size, - qp->queue.direct.buf, - pci_unmap_addr(&qp->queue.direct, mapping)); - } else { - for (i = 0; i < size / PAGE_SIZE; ++i) { - pci_free_consistent(dev->pdev, PAGE_SIZE, - qp->queue.page_list[i].buf, - pci_unmap_addr(&qp->queue.page_list[i], - mapping)); - } + mthca_free_mr(dev, &qp->mr); + mthca_free_memfree(dev, qp); + mthca_free_wqe_buf(dev, qp); } - kfree(qp->wrid); - - mthca_free_memfree(dev, qp); + mthca_unmap_memfree(dev, qp); if (is_sqp(dev, qp)) { atomic_dec(&(to_mpd(qp->ibqp.pd)->sqp_count)); -- cgit v1.2.3 From 38b32d6237588e6dca9b9a84256b507a29207f68 Mon Sep 17 00:00:00 2001 From: Martin Loschwitz Date: Thu, 7 Jul 2005 17:57:31 -0700 Subject: [PATCH] dvb: cinergyT2: endianness fix for raw remote-control keys Fixed litte/big-endian conversion for raw remote-control keys. Signed-off-by: Martin Loschwitz Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/cinergyT2/cinergyT2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 96c57fde95a..7d8b3cad350 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -699,6 +699,8 @@ static void cinergyt2_query_rc (void *data) for (n=0; len>0 && n<(len/sizeof(rc_events[0])); n++) { int i; +/* dprintk(1,"rc_events[%d].value = %x, type=%x\n",n,le32_to_cpu(rc_events[n].value),rc_events[n].type);*/ + if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC && rc_events[n].value == ~0) { @@ -714,7 +716,7 @@ static void cinergyt2_query_rc (void *data) cinergyt2->rc_input_event = KEY_MAX; for (i=0; irc_input_event = rc_keys[i+2]; break; -- cgit v1.2.3 From 25a26ec3b60b29300a652d7d81a69b6bc08b35b5 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:57:35 -0700 Subject: [PATCH] dvb: remove obsolete skystar2 driver Remove the skystar2 driver which has been obsoleted by the generalized flexcop-pci driver. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/Kconfig | 14 - drivers/media/dvb/b2c2/Makefile | 2 - drivers/media/dvb/b2c2/skystar2.c | 2644 ------------------------------------- 3 files changed, 2660 deletions(-) delete mode 100644 drivers/media/dvb/b2c2/skystar2.c (limited to 'drivers') diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index fafd0ab3a28..d7417eac2ab 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -35,17 +35,3 @@ config DVB_B2C2_FLEXCOP_DEBUG help Say Y if you want to enable the module option to control debug messages of all B2C2 FlexCop drivers. - -config DVB_B2C2_SKYSTAR - tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI" - depends on DVB_CORE && PCI - select DVB_STV0299 - select DVB_MT352 - select DVB_MT312 - select DVB_NXT2002 - help - Support for the Skystar2 PCI DVB card by Technisat, which - is equipped with the FlexCopII chipset by B2C2, and - for the B2C2/BBTI Air2PC-ATSC card. - - Say Y if you own such a device and want to use it. diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile index 7703812af34..1a1c3bca55f 100644 --- a/drivers/media/dvb/b2c2/Makefile +++ b/drivers/media/dvb/b2c2/Makefile @@ -9,6 +9,4 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o b2c2-flexcop-usb-objs = flexcop-usb.o obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o -obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o - EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c deleted file mode 100644 index acbc4c34f72..00000000000 --- a/drivers/media/dvb/b2c2/skystar2.c +++ /dev/null @@ -1,2644 +0,0 @@ -/* - * skystar2.c - driver for the Technisat SkyStar2 PCI DVB card - * based on the FlexCopII by B2C2,Inc. - * - * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc - * - * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl() - * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped - * Vincenzo Di Massa, hawk.it at tiscalinet.it - * - * Converted to Linux coding style - * Misc reorganization, polishing, restyling - * Roberto Ragusa, skystar2-c5b8 at robertoragusa dot it - * - * Added hardware filtering support, - * Niklas Peinecke, peinecke at gdv.uni-hannover.de - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * 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 Lesser 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 "dvb_frontend.h" - -#include -#include -#include "dvb_demux.h" -#include "dmxdev.h" -#include "dvb_filter.h" -#include "dvbdev.h" -#include "demux.h" -#include "dvb_net.h" -#include "stv0299.h" -#include "mt352.h" -#include "mt312.h" -#include "nxt2002.h" - -static int debug; -static int enable_hw_filters = 2; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Set debugging level (0 = default, 1 = most messages, 2 = all messages)."); -module_param(enable_hw_filters, int, 0444); -MODULE_PARM_DESC(enable_hw_filters, "enable hardware filters: supported values: 0 (none), 1, 2"); - -#define dprintk(x...) do { if (debug>=1) printk(x); } while (0) -#define ddprintk(x...) do { if (debug>=2) printk(x); } while (0) - -#define SIZE_OF_BUF_DMA1 0x3ac00 -#define SIZE_OF_BUF_DMA2 0x758 - -#define MAX_N_HW_FILTERS (6+32) -#define N_PID_SLOTS 256 - -struct dmaq { - u32 bus_addr; - u32 head; - u32 tail; - u32 buffer_size; - u8 *buffer; -}; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) -#define __iomem -#endif - -struct adapter { - struct pci_dev *pdev; - - u8 card_revision; - u32 b2c2_revision; - u32 pid_filter_max; - u32 mac_filter_max; - u32 irq; - void __iomem *io_mem; - unsigned long io_port; - u8 mac_addr[8]; - u32 dw_sram_type; - - struct dvb_adapter dvb_adapter; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - struct i2c_adapter i2c_adap; - struct dvb_net dvbnet; - - struct semaphore i2c_sem; - - struct dmaq dmaq1; - struct dmaq dmaq2; - - u32 dma_ctrl; - u32 dma_status; - - int capturing; - - spinlock_t lock; - - int useable_hw_filters; - u16 hw_pids[MAX_N_HW_FILTERS]; - u16 pid_list[N_PID_SLOTS]; - int pid_rc[N_PID_SLOTS]; // ref counters for the pids - int pid_count; - int whole_bandwidth_count; - u32 mac_filter; - - struct dvb_frontend* fe; - int (*fe_sleep)(struct dvb_frontend* fe); -}; - -#define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg) -#define read_reg_dw(adapter,reg) readl(adapter->io_mem + reg) - -static void write_reg_bitfield(struct adapter *adapter, u32 reg, u32 zeromask, u32 orvalue) -{ - u32 tmp; - - tmp = read_reg_dw(adapter, reg); - tmp = (tmp & ~zeromask) | orvalue; - write_reg_dw(adapter, reg, tmp); -} - -/* i2c functions */ -static int i2c_main_write_for_flex2(struct adapter *adapter, u32 command, u8 *buf, int retries) -{ - int i; - u32 value; - - write_reg_dw(adapter, 0x100, 0); - write_reg_dw(adapter, 0x100, command); - - for (i = 0; i < retries; i++) { - value = read_reg_dw(adapter, 0x100); - - if ((value & 0x40000000) == 0) { - if ((value & 0x81000000) == 0x80000000) { - if (buf != 0) - *buf = (value >> 0x10) & 0xff; - - return 1; - } - } else { - write_reg_dw(adapter, 0x100, 0); - write_reg_dw(adapter, 0x100, command); - } - } - - return 0; -} - -/* device = 0x10000000 for tuner, 0x20000000 for eeprom */ -static void i2c_main_setup(u32 device, u32 chip_addr, u8 op, u8 addr, u32 value, u32 len, u32 *command) -{ - *command = device | ((len - 1) << 26) | (value << 16) | (addr << 8) | chip_addr; - - if (op != 0) - *command = *command | 0x03000000; - else - *command = *command | 0x01000000; -} - -static int flex_i2c_read4(struct adapter *adapter, u32 device, u32 chip_addr, u16 addr, u8 *buf, u8 len) -{ - u32 command; - u32 value; - - int result, i; - - i2c_main_setup(device, chip_addr, 1, addr, 0, len, &command); - - result = i2c_main_write_for_flex2(adapter, command, buf, 100000); - - if ((result & 0xff) != 0) { - if (len > 1) { - value = read_reg_dw(adapter, 0x104); - - for (i = 1; i < len; i++) { - buf[i] = value & 0xff; - value = value >> 8; - } - } - } - - return result; -} - -static int flex_i2c_write4(struct adapter *adapter, u32 device, u32 chip_addr, u32 addr, u8 *buf, u8 len) -{ - u32 command; - u32 value; - int i; - - if (len > 1) { - value = 0; - - for (i = len; i > 1; i--) { - value = value << 8; - value = value | buf[i - 1]; - } - - write_reg_dw(adapter, 0x104, value); - } - - i2c_main_setup(device, chip_addr, 0, addr, buf[0], len, &command); - - return i2c_main_write_for_flex2(adapter, command, NULL, 100000); -} - -static void fixchipaddr(u32 device, u32 bus, u32 addr, u32 *ret) -{ - if (device == 0x20000000) - *ret = bus | ((addr >> 8) & 3); - else - *ret = bus; -} - -static u32 flex_i2c_read(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len) -{ - u32 chipaddr; - u32 bytes_to_transfer; - u8 *start; - - ddprintk("%s:\n", __FUNCTION__); - - start = buf; - - while (len != 0) { - bytes_to_transfer = len; - - if (bytes_to_transfer > 4) - bytes_to_transfer = 4; - - fixchipaddr(device, bus, addr, &chipaddr); - - if (flex_i2c_read4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0) - return buf - start; - - buf = buf + bytes_to_transfer; - addr = addr + bytes_to_transfer; - len = len - bytes_to_transfer; - }; - - return buf - start; -} - -static u32 flex_i2c_write(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len) -{ - u32 chipaddr; - u32 bytes_to_transfer; - u8 *start; - - ddprintk("%s:\n", __FUNCTION__); - - start = buf; - - while (len != 0) { - bytes_to_transfer = len; - - if (bytes_to_transfer > 4) - bytes_to_transfer = 4; - - fixchipaddr(device, bus, addr, &chipaddr); - - if (flex_i2c_write4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0) - return buf - start; - - buf = buf + bytes_to_transfer; - addr = addr + bytes_to_transfer; - len = len - bytes_to_transfer; - } - - return buf - start; -} - -static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msgs, int num) -{ - struct adapter *tmp = i2c_get_adapdata(adapter); - int i, ret = 0; - - if (down_interruptible(&tmp->i2c_sem)) - return -ERESTARTSYS; - - ddprintk("%s: %d messages to transfer\n", __FUNCTION__, num); - - for (i = 0; i < num; i++) { - ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i, - msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); - } - - // read command - if ((num == 2) && (msgs[0].flags == 0) && (msgs[1].flags == I2C_M_RD) && (msgs[0].buf != NULL) && (msgs[1].buf != NULL)) { - - ret = flex_i2c_read(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len); - - up(&tmp->i2c_sem); - - if (ret != msgs[1].len) { - dprintk("%s: read error !\n", __FUNCTION__); - - for (i = 0; i < 2; i++) { - dprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i, - msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); - } - - return -EREMOTEIO; - } - - return num; - } - // write command - for (i = 0; i < num; i++) { - - if ((msgs[i].flags != 0) || (msgs[i].buf == NULL) || (msgs[i].len < 2)) - return -EINVAL; - - ret = flex_i2c_write(tmp, 0x10000000, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1); - - up(&tmp->i2c_sem); - - if (ret != msgs[0].len - 1) { - dprintk("%s: write error %i !\n", __FUNCTION__, ret); - - dprintk("message %d: flags=0x%x, addr=0x%x, buf[0]=0x%x, len=%d \n", i, - msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); - - return -EREMOTEIO; - } - - return num; - } - - printk("%s: unknown command format !\n", __FUNCTION__); - - return -EINVAL; -} - -/* SRAM (Skystar2 rev2.3 has one "ISSI IS61LV256" chip on board, - but it seems that FlexCopII can work with more than one chip) */ -static void sram_set_net_dest(struct adapter *adapter, u8 dest) -{ - u32 tmp; - - udelay(1000); - - tmp = (read_reg_dw(adapter, 0x714) & 0xfffffffc) | (dest & 3); - - udelay(1000); - - write_reg_dw(adapter, 0x714, tmp); - write_reg_dw(adapter, 0x714, tmp); - - udelay(1000); - - /* return value is never used? */ -/* return tmp; */ -} - -static void sram_set_cai_dest(struct adapter *adapter, u8 dest) -{ - u32 tmp; - - udelay(1000); - - tmp = (read_reg_dw(adapter, 0x714) & 0xfffffff3) | ((dest & 3) << 2); - - udelay(1000); - udelay(1000); - - write_reg_dw(adapter, 0x714, tmp); - write_reg_dw(adapter, 0x714, tmp); - - udelay(1000); - - /* return value is never used? */ -/* return tmp; */ -} - -static void sram_set_cao_dest(struct adapter *adapter, u8 dest) -{ - u32 tmp; - - udelay(1000); - - tmp = (read_reg_dw(adapter, 0x714) & 0xffffffcf) | ((dest & 3) << 4); - - udelay(1000); - udelay(1000); - - write_reg_dw(adapter, 0x714, tmp); - write_reg_dw(adapter, 0x714, tmp); - - udelay(1000); - - /* return value is never used? */ -/* return tmp; */ -} - -static void sram_set_media_dest(struct adapter *adapter, u8 dest) -{ - u32 tmp; - - udelay(1000); - - tmp = (read_reg_dw(adapter, 0x714) & 0xffffff3f) | ((dest & 3) << 6); - - udelay(1000); - udelay(1000); - - write_reg_dw(adapter, 0x714, tmp); - write_reg_dw(adapter, 0x714, tmp); - - udelay(1000); - - /* return value is never used? */ -/* return tmp; */ -} - -/* SRAM memory is accessed through a buffer register in the FlexCop - chip (0x700). This register has the following structure: - bits 0-14 : address - bit 15 : read/write flag - bits 16-23 : 8-bit word to write - bits 24-27 : = 4 - bits 28-29 : memory bank selector - bit 31 : busy flag -*/ -static void flex_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) -{ - int i, retries; - u32 command; - - for (i = 0; i < len; i++) { - command = bank | addr | 0x04000000 | (*buf << 0x10); - - retries = 2; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __FUNCTION__); - - write_reg_dw(adapter, 0x700, command); - - buf++; - addr++; - } -} - -static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) -{ - int i, retries; - u32 command, value; - - for (i = 0; i < len; i++) { - command = bank | addr | 0x04008000; - - retries = 10000; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __FUNCTION__); - - write_reg_dw(adapter, 0x700, command); - - retries = 10000; - - while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { - mdelay(1); - retries--; - }; - - if (retries == 0) - printk("%s: SRAM timeout\n", __FUNCTION__); - - value = read_reg_dw(adapter, 0x700) >> 0x10; - - *buf = (value & 0xff); - - addr++; - buf++; - } -} - -static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) -{ - u32 bank; - - bank = 0; - - if (adapter->dw_sram_type == 0x20000) { - bank = (addr & 0x18000) << 0x0d; - } - - if (adapter->dw_sram_type == 0x00000) { - if ((addr >> 0x0f) == 0) - bank = 0x20000000; - else - bank = 0x10000000; - } - - flex_sram_write(adapter, bank, addr & 0x7fff, buf, len); -} - -static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) -{ - u32 bank; - - bank = 0; - - if (adapter->dw_sram_type == 0x20000) { - bank = (addr & 0x18000) << 0x0d; - } - - if (adapter->dw_sram_type == 0x00000) { - if ((addr >> 0x0f) == 0) - bank = 0x20000000; - else - bank = 0x10000000; - } - - flex_sram_read(adapter, bank, addr & 0x7fff, buf, len); -} - -static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len) -{ - u32 length; - - while (len != 0) { - length = len; - - // check if the address range belongs to the same - // 32K memory chip. If not, the data is read from - // one chip at a time. - if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { - length = (((addr >> 0x0f) + 1) << 0x0f) - addr; - } - - sram_read_chunk(adapter, addr, buf, length); - - addr = addr + length; - buf = buf + length; - len = len - length; - } -} - -static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len) -{ - u32 length; - - while (len != 0) { - length = len; - - // check if the address range belongs to the same - // 32K memory chip. If not, the data is written to - // one chip at a time. - if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { - length = (((addr >> 0x0f) + 1) << 0x0f) - addr; - } - - sram_write_chunk(adapter, addr, buf, length); - - addr = addr + length; - buf = buf + length; - len = len - length; - } -} - -static void sram_set_size(struct adapter *adapter, u32 mask) -{ - write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c)))); -} - -static void sram_init(struct adapter *adapter) -{ - u32 tmp; - - tmp = read_reg_dw(adapter, 0x71c); - - write_reg_dw(adapter, 0x71c, 1); - - if (read_reg_dw(adapter, 0x71c) != 0) { - write_reg_dw(adapter, 0x71c, tmp); - - adapter->dw_sram_type = tmp & 0x30000; - - ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type); - - } else { - - adapter->dw_sram_type = 0x10000; - - ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type); - } - - /* return value is never used? */ -/* return adapter->dw_sram_type; */ -} - -static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr) -{ - u8 tmp1, tmp2; - - dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr); - - sram_set_size(adapter, mask); - sram_init(adapter); - - tmp2 = 0xa5; - tmp1 = 0x4f; - - sram_write(adapter, addr, &tmp2, 1); - sram_write(adapter, addr + 4, &tmp1, 1); - - tmp2 = 0; - - mdelay(20); - - sram_read(adapter, addr, &tmp2, 1); - sram_read(adapter, addr, &tmp2, 1); - - dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2); - - if (tmp2 != 0xa5) - return 0; - - tmp2 = 0x5a; - tmp1 = 0xf4; - - sram_write(adapter, addr, &tmp2, 1); - sram_write(adapter, addr + 4, &tmp1, 1); - - tmp2 = 0; - - mdelay(20); - - sram_read(adapter, addr, &tmp2, 1); - sram_read(adapter, addr, &tmp2, 1); - - dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2); - - if (tmp2 != 0x5a) - return 0; - - return 1; -} - -static u32 sram_length(struct adapter *adapter) -{ - if (adapter->dw_sram_type == 0x10000) - return 32768; // 32K - if (adapter->dw_sram_type == 0x00000) - return 65536; // 64K - if (adapter->dw_sram_type == 0x20000) - return 131072; // 128K - - return 32768; // 32K -} - -/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory. - - for 128K there are 4x32K chips at bank 0,1,2,3. - - for 64K there are 2x32K chips at bank 1,2. - - for 32K there is one 32K chip at bank 0. - - FlexCop works only with one bank at a time. The bank is selected - by bits 28-29 of the 0x700 register. - - bank 0 covers addresses 0x00000-0x07fff - bank 1 covers addresses 0x08000-0x0ffff - bank 2 covers addresses 0x10000-0x17fff - bank 3 covers addresses 0x18000-0x1ffff -*/ -static int sram_detect_for_flex2(struct adapter *adapter) -{ - u32 tmp, tmp2, tmp3; - - dprintk("%s:\n", __FUNCTION__); - - tmp = read_reg_dw(adapter, 0x208); - write_reg_dw(adapter, 0x208, 0); - - tmp2 = read_reg_dw(adapter, 0x71c); - - dprintk("%s: tmp2 = %x\n", __FUNCTION__, tmp2); - - write_reg_dw(adapter, 0x71c, 1); - - tmp3 = read_reg_dw(adapter, 0x71c); - - dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3); - - write_reg_dw(adapter, 0x71c, tmp2); - - // check for internal SRAM ??? - tmp3--; - if (tmp3 != 0) { - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - - dprintk("%s: sram size = 32K\n", __FUNCTION__); - - return 32; - } - - if (sram_test_location(adapter, 0x20000, 0x18000) != 0) { - sram_set_size(adapter, 0x20000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - - dprintk("%s: sram size = 128K\n", __FUNCTION__); - - return 128; - } - - if (sram_test_location(adapter, 0x00000, 0x10000) != 0) { - sram_set_size(adapter, 0x00000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - - dprintk("%s: sram size = 64K\n", __FUNCTION__); - - return 64; - } - - if (sram_test_location(adapter, 0x10000, 0x00000) != 0) { - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - - dprintk("%s: sram size = 32K\n", __FUNCTION__); - - return 32; - } - - sram_set_size(adapter, 0x10000); - sram_init(adapter); - write_reg_dw(adapter, 0x208, tmp); - - dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__); - - return 0; -} - -static void sll_detect_sram_size(struct adapter *adapter) -{ - sram_detect_for_flex2(adapter); -} - -/* EEPROM (Skystar2 has one "24LC08B" chip on board) */ -/* -static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len) -{ - return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len); -} -*/ - -static int eeprom_read(struct adapter *adapter, u16 addr, u8 *buf, u16 len) -{ - return flex_i2c_read(adapter, 0x20000000, 0x50, addr, buf, len); -} - -static u8 calc_lrc(u8 *buf, int len) -{ - int i; - u8 sum; - - sum = 0; - - for (i = 0; i < len; i++) - sum = sum ^ buf[i]; - - return sum; -} - -static int eeprom_lrc_read(struct adapter *adapter, u32 addr, u32 len, u8 *buf, int retries) -{ - int i; - - for (i = 0; i < retries; i++) { - if (eeprom_read(adapter, addr, buf, len) == len) { - if (calc_lrc(buf, len - 1) == buf[len - 1]) - return 1; - } - } - - return 0; -} - -/* -static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries) -{ - int i; - - for (i = 0; i < retries; i++) { - if (eeprom_write(adapter, addr, wbuf, len) == len) { - if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1) - return 1; - } - } - - return 0; -} -*/ - - -/* These functions could be used to unlock SkyStar2 cards. */ - -/* -static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len) -{ - u8 rbuf[20]; - u8 wbuf[20]; - - if (len != 16) - return 0; - - memcpy(wbuf, key, len); - - wbuf[16] = 0; - wbuf[17] = 0; - wbuf[18] = 0; - wbuf[19] = calc_lrc(wbuf, 19); - - return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4); -} - -static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len) -{ - u8 buf[20]; - - if (len != 16) - return 0; - - if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0) - return 0; - - memcpy(key, buf, len); - - return 1; -} -*/ - -static int eeprom_get_mac_addr(struct adapter *adapter, char type, u8 *mac) -{ - u8 tmp[8]; - - if (eeprom_lrc_read(adapter, 0x3f8, 8, tmp, 4) != 0) { - if (type != 0) { - mac[0] = tmp[0]; - mac[1] = tmp[1]; - mac[2] = tmp[2]; - mac[3] = 0xfe; - mac[4] = 0xff; - mac[5] = tmp[3]; - mac[6] = tmp[4]; - mac[7] = tmp[5]; - - } else { - - mac[0] = tmp[0]; - mac[1] = tmp[1]; - mac[2] = tmp[2]; - mac[3] = tmp[3]; - mac[4] = tmp[4]; - mac[5] = tmp[5]; - } - - return 1; - - } else { - - if (type == 0) { - memset(mac, 0, 6); - - } else { - - memset(mac, 0, 8); - } - - return 0; - } -} - -/* -static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac) -{ - u8 tmp[8]; - - if (type != 0) { - tmp[0] = mac[0]; - tmp[1] = mac[1]; - tmp[2] = mac[2]; - tmp[3] = mac[5]; - tmp[4] = mac[6]; - tmp[5] = mac[7]; - - } else { - - tmp[0] = mac[0]; - tmp[1] = mac[1]; - tmp[2] = mac[2]; - tmp[3] = mac[3]; - tmp[4] = mac[4]; - tmp[5] = mac[5]; - } - - tmp[6] = 0; - tmp[7] = calc_lrc(tmp, 7); - - if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8) - return 1; - - return 0; -} -*/ - -/* PID filter */ - -/* every flexcop has 6 "lower" hw PID filters */ -/* these are enabled by setting bits 0-5 of 0x208 */ -/* for the 32 additional filters we have to select one */ -/* of them through 0x310 and modify through 0x314 */ -/* op: 0=disable, 1=enable */ -static void filter_enable_hw_filter(struct adapter *adapter, int id, u8 op) -{ - dprintk("%s: id=%d op=%d\n", __FUNCTION__, id, op); - if (id <= 5) { - u32 mask = (0x00000001 << id); - write_reg_bitfield(adapter, 0x208, mask, op ? mask : 0); - } else { - /* select */ - write_reg_bitfield(adapter, 0x310, 0x1f, (id - 6) & 0x1f); - /* modify */ - write_reg_bitfield(adapter, 0x314, 0x00006000, op ? 0x00004000 : 0); - } -} - -/* this sets the PID that should pass the specified filter */ -static void pid_set_hw_pid(struct adapter *adapter, int id, u16 pid) -{ - dprintk("%s: id=%d pid=%d\n", __FUNCTION__, id, pid); - if (id <= 5) { - u32 adr = 0x300 + ((id & 6) << 1); - int shift = (id & 1) ? 16 : 0; - dprintk("%s: id=%d addr=%x %c pid=%d\n", __FUNCTION__, id, adr, (id & 1) ? 'h' : 'l', pid); - write_reg_bitfield(adapter, adr, (0x7fff) << shift, (pid & 0x1fff) << shift); - } else { - /* select */ - write_reg_bitfield(adapter, 0x310, 0x1f, (id - 6) & 0x1f); - /* modify */ - write_reg_bitfield(adapter, 0x314, 0x1fff, pid & 0x1fff); - } -} - - -/* -static void filter_enable_null_filter(struct adapter *adapter, u32 op) -{ - dprintk("%s: op=%x\n", __FUNCTION__, op); - - write_reg_bitfield(adapter, 0x208, 0x00000040, op?0x00000040:0); -} -*/ - -static void filter_enable_mask_filter(struct adapter *adapter, u32 op) -{ - dprintk("%s: op=%x\n", __FUNCTION__, op); - - write_reg_bitfield(adapter, 0x208, 0x00000080, op ? 0x00000080 : 0); -} - - -static void ctrl_enable_mac(struct adapter *adapter, u32 op) -{ - write_reg_bitfield(adapter, 0x208, 0x00004000, op ? 0x00004000 : 0); -} - -static int ca_set_mac_dst_addr_filter(struct adapter *adapter, u8 *mac) -{ - u32 tmp1, tmp2; - - tmp1 = (mac[3] << 0x18) | (mac[2] << 0x10) | (mac[1] << 0x08) | mac[0]; - tmp2 = (mac[5] << 0x08) | mac[4]; - - write_reg_dw(adapter, 0x418, tmp1); - write_reg_dw(adapter, 0x41c, tmp2); - - return 0; -} - -/* -static void set_ignore_mac_filter(struct adapter *adapter, u8 op) -{ - if (op != 0) { - write_reg_bitfield(adapter, 0x208, 0x00004000, 0); - adapter->mac_filter = 1; - } else { - if (adapter->mac_filter != 0) { - adapter->mac_filter = 0; - write_reg_bitfield(adapter, 0x208, 0x00004000, 0x00004000); - } - } -} -*/ - -/* -static void check_null_filter_enable(struct adapter *adapter) -{ - filter_enable_null_filter(adapter, 1); - filter_enable_mask_filter(adapter, 1); -} -*/ - -static void pid_set_group_pid(struct adapter *adapter, u16 pid) -{ - u32 value; - - dprintk("%s: pid=%x\n", __FUNCTION__, pid); - value = (pid & 0x3fff) | (read_reg_dw(adapter, 0x30c) & 0xffff0000); - write_reg_dw(adapter, 0x30c, value); -} - -static void pid_set_group_mask(struct adapter *adapter, u16 pid) -{ - u32 value; - - dprintk("%s: pid=%x\n", __FUNCTION__, pid); - value = ((pid & 0x3fff) << 0x10) | (read_reg_dw(adapter, 0x30c) & 0xffff); - write_reg_dw(adapter, 0x30c, value); -} - -/* -static int pid_get_group_pid(struct adapter *adapter) -{ - return read_reg_dw(adapter, 0x30c) & 0x00001fff; -} - -static int pid_get_group_mask(struct adapter *adapter) -{ - return (read_reg_dw(adapter, 0x30c) >> 0x10)& 0x00001fff; -} -*/ - -/* -static void reset_hardware_pid_filter(struct adapter *adapter) -{ - pid_set_stream1_pid(adapter, 0x1fff); - - pid_set_stream2_pid(adapter, 0x1fff); - filter_enable_stream2_filter(adapter, 0); - - pid_set_pcr_pid(adapter, 0x1fff); - filter_enable_pcr_filter(adapter, 0); - - pid_set_pmt_pid(adapter, 0x1fff); - filter_enable_pmt_filter(adapter, 0); - - pid_set_ecm_pid(adapter, 0x1fff); - filter_enable_ecm_filter(adapter, 0); - - pid_set_emm_pid(adapter, 0x1fff); - filter_enable_emm_filter(adapter, 0); -} -*/ - -static void init_pids(struct adapter *adapter) -{ - int i; - - adapter->pid_count = 0; - adapter->whole_bandwidth_count = 0; - for (i = 0; i < adapter->useable_hw_filters; i++) { - dprintk("%s: setting filter %d to 0x1fff\n", __FUNCTION__, i); - adapter->hw_pids[i] = 0x1fff; - pid_set_hw_pid(adapter, i, 0x1fff); -} - - pid_set_group_pid(adapter, 0); - pid_set_group_mask(adapter, 0x1fe0); -} - -static void open_whole_bandwidth(struct adapter *adapter) -{ - dprintk("%s:\n", __FUNCTION__); - pid_set_group_pid(adapter, 0); - pid_set_group_mask(adapter, 0); -/* - filter_enable_mask_filter(adapter, 1); -*/ -} - -static void close_whole_bandwidth(struct adapter *adapter) -{ - dprintk("%s:\n", __FUNCTION__); - pid_set_group_pid(adapter, 0); - pid_set_group_mask(adapter, 0x1fe0); -/* - filter_enable_mask_filter(adapter, 1); -*/ -} - -static void whole_bandwidth_inc(struct adapter *adapter) -{ - if (adapter->whole_bandwidth_count++ == 0) - open_whole_bandwidth(adapter); -} - -static void whole_bandwidth_dec(struct adapter *adapter) -{ - if (--adapter->whole_bandwidth_count <= 0) - close_whole_bandwidth(adapter); -} - -/* The specified PID has to be let through the - hw filters. - We try to allocate an hardware filter and open whole - bandwidth when allocation is impossible. - All pids<=0x1f pass through the group filter. - Returns 1 on success, -1 on error */ -static int add_hw_pid(struct adapter *adapter, u16 pid) -{ - int i; - - dprintk("%s: pid=%d\n", __FUNCTION__, pid); - - if (pid <= 0x1f) - return 1; - - /* we can't use a filter for 0x2000, so no search */ - if (pid != 0x2000) { - /* find an unused hardware filter */ - for (i = 0; i < adapter->useable_hw_filters; i++) { - dprintk("%s: pid=%d searching slot=%d\n", __FUNCTION__, pid, i); - if (adapter->hw_pids[i] == 0x1fff) { - dprintk("%s: pid=%d slot=%d\n", __FUNCTION__, pid, i); - adapter->hw_pids[i] = pid; - pid_set_hw_pid(adapter, i, pid); - filter_enable_hw_filter(adapter, i, 1); - return 1; - } - } - } - /* if we have not used a filter, this pid depends on whole bandwidth */ - dprintk("%s: pid=%d whole_bandwidth\n", __FUNCTION__, pid); - whole_bandwidth_inc(adapter); - return 1; - } - -/* returns -1 if the pid was not present in the filters */ -static int remove_hw_pid(struct adapter *adapter, u16 pid) -{ - int i; - - dprintk("%s: pid=%d\n", __FUNCTION__, pid); - - if (pid <= 0x1f) - return 1; - - /* we can't use a filter for 0x2000, so no search */ - if (pid != 0x2000) { - for (i = 0; i < adapter->useable_hw_filters; i++) { - dprintk("%s: pid=%d searching slot=%d\n", __FUNCTION__, pid, i); - if (adapter->hw_pids[i] == pid) { // find the pid slot - dprintk("%s: pid=%d slot=%d\n", __FUNCTION__, pid, i); - adapter->hw_pids[i] = 0x1fff; - pid_set_hw_pid(adapter, i, 0x1fff); - filter_enable_hw_filter(adapter, i, 0); - return 1; - } - } - } - /* if we have not used a filter, this pid depended on whole bandwith */ - dprintk("%s: pid=%d whole_bandwidth\n", __FUNCTION__, pid); - whole_bandwidth_dec(adapter); - return 1; - } - -/* Adds a PID to the filters. - Adding a pid more than once is possible, we keep reference counts. - Whole stream available through pid==0x2000. - Returns 1 on success, -1 on error */ -static int add_pid(struct adapter *adapter, u16 pid) -{ - int i; - - dprintk("%s: pid=%d\n", __FUNCTION__, pid); - - if (pid > 0x1ffe && pid != 0x2000) - return -1; - - // check if the pid is already present - for (i = 0; i < adapter->pid_count; i++) - if (adapter->pid_list[i] == pid) { - adapter->pid_rc[i]++; // increment ref counter - return 1; - } - - if (adapter->pid_count == N_PID_SLOTS) - return -1; // no more pids can be added - adapter->pid_list[adapter->pid_count] = pid; // register pid - adapter->pid_rc[adapter->pid_count] = 1; - adapter->pid_count++; - // hardware setting - add_hw_pid(adapter, pid); - - return 1; - } - -/* Removes a PID from the filters. */ -static int remove_pid(struct adapter *adapter, u16 pid) -{ - int i; - - dprintk("%s: pid=%d\n", __FUNCTION__, pid); - - if (pid > 0x1ffe && pid != 0x2000) - return -1; - - // check if the pid is present (it must be!) - for (i = 0; i < adapter->pid_count; i++) { - if (adapter->pid_list[i] == pid) { - adapter->pid_rc[i]--; - if (adapter->pid_rc[i] <= 0) { - // remove from the list - adapter->pid_count--; - adapter->pid_list[i]=adapter->pid_list[adapter->pid_count]; - adapter->pid_rc[i] = adapter->pid_rc[adapter->pid_count]; - // hardware setting - remove_hw_pid(adapter, pid); - } - return 1; - } - } - - return -1; -} - - -/* dma & irq */ -static void ctrl_enable_smc(struct adapter *adapter, u32 op) -{ - write_reg_bitfield(adapter, 0x208, 0x00000800, op ? 0x00000800 : 0); -} - -static void dma_enable_disable_irq(struct adapter *adapter, u32 flag1, u32 flag2, u32 flag3) -{ - adapter->dma_ctrl = adapter->dma_ctrl & 0x000f0000; - - if (flag1 == 0) { - if (flag2 == 0) - adapter->dma_ctrl = adapter->dma_ctrl & ~0x00010000; - else - adapter->dma_ctrl = adapter->dma_ctrl | 0x00010000; - - if (flag3 == 0) - adapter->dma_ctrl = adapter->dma_ctrl & ~0x00020000; - else - adapter->dma_ctrl = adapter->dma_ctrl | 0x00020000; - - } else { - - if (flag2 == 0) - adapter->dma_ctrl = adapter->dma_ctrl & ~0x00040000; - else - adapter->dma_ctrl = adapter->dma_ctrl | 0x00040000; - - if (flag3 == 0) - adapter->dma_ctrl = adapter->dma_ctrl & ~0x00080000; - else - adapter->dma_ctrl = adapter->dma_ctrl | 0x00080000; - } -} - -static void irq_dma_enable_disable_irq(struct adapter *adapter, u32 op) -{ - u32 value; - - value = read_reg_dw(adapter, 0x208) & 0xfff0ffff; - - if (op != 0) - value = value | (adapter->dma_ctrl & 0x000f0000); - - write_reg_dw(adapter, 0x208, value); -} - -/* FlexCopII has 2 dma channels. DMA1 is used to transfer TS data to - system memory. - - The DMA1 buffer is divided in 2 subbuffers of equal size. - FlexCopII will transfer TS data to one subbuffer, signal an interrupt - when the subbuffer is full and continue fillig the second subbuffer. - - For DMA1: - subbuffer size in 32-bit words is stored in the first 24 bits of - register 0x004. The last 8 bits of register 0x004 contain the number - of subbuffers. - - the first 30 bits of register 0x000 contain the address of the first - subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1, - when dma1 is enabled. - - the first 30 bits of register 0x00c contain the address of the second - subbuffer. the last 2 bits contain 1. - - register 0x008 will contain the address of the subbuffer that was filled - with TS data, when FlexCopII will generate an interrupt. - - For DMA2: - subbuffer size in 32-bit words is stored in the first 24 bits of - register 0x014. The last 8 bits of register 0x014 contain the number - of subbuffers. - - the first 30 bits of register 0x010 contain the address of the first - subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1, - when dma1 is enabled. - - the first 30 bits of register 0x01c contain the address of the second - subbuffer. the last 2 bits contain 1. - - register 0x018 contains the address of the subbuffer that was filled - with TS data, when FlexCopII generates an interrupt. -*/ -static int dma_init_dma(struct adapter *adapter, u32 dma_channel) -{ - u32 subbuffers, subbufsize, subbuf0, subbuf1; - - if (dma_channel == 0) { - dprintk("%s: Initializing DMA1 channel\n", __FUNCTION__); - - subbuffers = 2; - - subbufsize = (((adapter->dmaq1.buffer_size / 2) / 4) << 8) | subbuffers; - - subbuf0 = adapter->dmaq1.bus_addr & 0xfffffffc; - - subbuf1 = ((adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) & 0xfffffffc) | 1; - - dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0); - udelay(1000); - write_reg_dw(adapter, 0x000, subbuf0); - - dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4); - udelay(1000); - write_reg_dw(adapter, 0x004, subbufsize); - - dprintk("%s: second subbuffer address = 0x%x\n", __FUNCTION__, subbuf1); - udelay(1000); - write_reg_dw(adapter, 0x00c, subbuf1); - - dprintk("%s: counter = 0x%x\n", __FUNCTION__, adapter->dmaq1.bus_addr & 0xfffffffc); - write_reg_dw(adapter, 0x008, adapter->dmaq1.bus_addr & 0xfffffffc); - udelay(1000); - - dma_enable_disable_irq(adapter, 0, 1, subbuffers ? 1 : 0); - - irq_dma_enable_disable_irq(adapter, 1); - - sram_set_media_dest(adapter, 1); - sram_set_net_dest(adapter, 1); - sram_set_cai_dest(adapter, 2); - sram_set_cao_dest(adapter, 2); - } - - if (dma_channel == 1) { - dprintk("%s: Initializing DMA2 channel\n", __FUNCTION__); - - subbuffers = 2; - - subbufsize = (((adapter->dmaq2.buffer_size / 2) / 4) << 8) | subbuffers; - - subbuf0 = adapter->dmaq2.bus_addr & 0xfffffffc; - - subbuf1 = ((adapter->dmaq2.bus_addr + adapter->dmaq2.buffer_size / 2) & 0xfffffffc) | 1; - - dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0); - udelay(1000); - write_reg_dw(adapter, 0x010, subbuf0); - - dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4); - udelay(1000); - write_reg_dw(adapter, 0x014, subbufsize); - - dprintk("%s: second buffer address = 0x%x\n", __FUNCTION__, subbuf1); - udelay(1000); - write_reg_dw(adapter, 0x01c, subbuf1); - - sram_set_cai_dest(adapter, 2); - } - - return 0; -} - -static void ctrl_enable_receive_data(struct adapter *adapter, u32 op) -{ - if (op == 0) { - write_reg_bitfield(adapter, 0x208, 0x00008000, 0); - adapter->dma_status = adapter->dma_status & ~0x00000004; - } else { - write_reg_bitfield(adapter, 0x208, 0x00008000, 0x00008000); - adapter->dma_status = adapter->dma_status | 0x00000004; - } -} - -/* bit 0 of dma_mask is set to 1 if dma1 channel has to be enabled/disabled - bit 1 of dma_mask is set to 1 if dma2 channel has to be enabled/disabled -*/ -static void dma_start_stop(struct adapter *adapter, u32 dma_mask, int start_stop) -{ - u32 dma_enable, dma1_enable, dma2_enable; - - dprintk("%s: dma_mask=%x\n", __FUNCTION__, dma_mask); - - if (start_stop == 1) { - dprintk("%s: starting dma\n", __FUNCTION__); - - dma1_enable = 0; - dma2_enable = 0; - - if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) == 0) && (adapter->dmaq1.bus_addr != 0)) { - adapter->dma_status = adapter->dma_status | 1; - dma1_enable = 1; - } - - if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) == 0) && (adapter->dmaq2.bus_addr != 0)) { - adapter->dma_status = adapter->dma_status | 2; - dma2_enable = 1; - } - // enable dma1 and dma2 - if ((dma1_enable == 1) && (dma2_enable == 1)) { - write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr | 1); - write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1); - write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr | 1); - - ctrl_enable_receive_data(adapter, 1); - - return; - } - // enable dma1 - if ((dma1_enable == 1) && (dma2_enable == 0)) { - write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr | 1); - write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1); - - ctrl_enable_receive_data(adapter, 1); - - return; - } - // enable dma2 - if ((dma1_enable == 0) && (dma2_enable == 1)) { - write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr | 1); - - ctrl_enable_receive_data(adapter, 1); - - return; - } - // start dma - if ((dma1_enable == 0) && (dma2_enable == 0)) { - ctrl_enable_receive_data(adapter, 1); - - return; - } - - } else { - - dprintk("%s: stopping dma\n", __FUNCTION__); - - dma_enable = adapter->dma_status & 0x00000003; - - if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0)) { - dma_enable = dma_enable & 0xfffffffe; - } - - if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0)) { - dma_enable = dma_enable & 0xfffffffd; - } - //stop dma - if ((dma_enable == 0) && ((adapter->dma_status & 4) != 0)) { - ctrl_enable_receive_data(adapter, 0); - - udelay(3000); - } - //disable dma1 - if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0) && (adapter->dmaq1.bus_addr != 0)) { - write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr); - write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1); - - adapter->dma_status = adapter->dma_status & ~0x00000001; - } - //disable dma2 - if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0) && (adapter->dmaq2.bus_addr != 0)) { - write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr); - - adapter->dma_status = adapter->dma_status & ~0x00000002; - } - } -} - -static void open_stream(struct adapter *adapter, u16 pid) -{ - u32 dma_mask; - - ++adapter->capturing; - - filter_enable_mask_filter(adapter, 1); - - add_pid(adapter, pid); - - dprintk("%s: adapter->dma_status=%x\n", __FUNCTION__, adapter->dma_status); - - if ((adapter->dma_status & 7) != 7) { - dma_mask = 0; - - if (((adapter->dma_status & 0x10000000) != 0) && ((adapter->dma_status & 1) == 0)) { - dma_mask = dma_mask | 1; - - adapter->dmaq1.head = 0; - adapter->dmaq1.tail = 0; - - memset(adapter->dmaq1.buffer, 0, adapter->dmaq1.buffer_size); - } - - if (((adapter->dma_status & 0x20000000) != 0) && ((adapter->dma_status & 2) == 0)) { - dma_mask = dma_mask | 2; - - adapter->dmaq2.head = 0; - adapter->dmaq2.tail = 0; - } - - if (dma_mask != 0) { - irq_dma_enable_disable_irq(adapter, 1); - - dma_start_stop(adapter, dma_mask, 1); - } - } -} - -static void close_stream(struct adapter *adapter, u16 pid) -{ - if (adapter->capturing > 0) - --adapter->capturing; - - dprintk("%s: dma_status=%x\n", __FUNCTION__, adapter->dma_status); - - if (adapter->capturing == 0) { - u32 dma_mask = 0; - - if ((adapter->dma_status & 1) != 0) - dma_mask = dma_mask | 0x00000001; - if ((adapter->dma_status & 2) != 0) - dma_mask = dma_mask | 0x00000002; - - if (dma_mask != 0) { - dma_start_stop(adapter, dma_mask, 0); - } - } - remove_pid(adapter, pid); -} - -static void interrupt_service_dma1(struct adapter *adapter) -{ - struct dvb_demux *dvbdmx = &adapter->demux; - - int n_cur_dma_counter; - u32 n_num_bytes_parsed; - u32 n_num_new_bytes_transferred; - u32 dw_default_packet_size = 188; - u8 gb_tmp_buffer[188]; - u8 *pb_dma_buf_cur_pos; - - n_cur_dma_counter = readl(adapter->io_mem + 0x008) - adapter->dmaq1.bus_addr; - n_cur_dma_counter = (n_cur_dma_counter / dw_default_packet_size) * dw_default_packet_size; - - if ((n_cur_dma_counter < 0) || (n_cur_dma_counter > adapter->dmaq1.buffer_size)) { - dprintk("%s: dma counter outside dma buffer\n", __FUNCTION__); - return; - } - - adapter->dmaq1.head = n_cur_dma_counter; - - if (adapter->dmaq1.tail <= n_cur_dma_counter) { - n_num_new_bytes_transferred = n_cur_dma_counter - adapter->dmaq1.tail; - - } else { - - n_num_new_bytes_transferred = (adapter->dmaq1.buffer_size - adapter->dmaq1.tail) + n_cur_dma_counter; - } - - ddprintk("%s: n_cur_dma_counter = %d\n", __FUNCTION__, n_cur_dma_counter); - ddprintk("%s: dmaq1.tail = %d\n", __FUNCTION__, adapter->dmaq1.tail); - ddprintk("%s: bytes_transferred = %d\n", __FUNCTION__, n_num_new_bytes_transferred); - - if (n_num_new_bytes_transferred < dw_default_packet_size) - return; - - n_num_bytes_parsed = 0; - - while (n_num_bytes_parsed < n_num_new_bytes_transferred) { - pb_dma_buf_cur_pos = adapter->dmaq1.buffer + adapter->dmaq1.tail; - - if (adapter->dmaq1.buffer + adapter->dmaq1.buffer_size < adapter->dmaq1.buffer + adapter->dmaq1.tail + 188) { - memcpy(gb_tmp_buffer, adapter->dmaq1.buffer + adapter->dmaq1.tail, - adapter->dmaq1.buffer_size - adapter->dmaq1.tail); - memcpy(gb_tmp_buffer + (adapter->dmaq1.buffer_size - adapter->dmaq1.tail), adapter->dmaq1.buffer, - (188 - (adapter->dmaq1.buffer_size - adapter->dmaq1.tail))); - - pb_dma_buf_cur_pos = gb_tmp_buffer; - } - - if (adapter->capturing != 0) { - dvb_dmx_swfilter_packets(dvbdmx, pb_dma_buf_cur_pos, dw_default_packet_size / 188); - } - - n_num_bytes_parsed = n_num_bytes_parsed + dw_default_packet_size; - - adapter->dmaq1.tail = adapter->dmaq1.tail + dw_default_packet_size; - - if (adapter->dmaq1.tail >= adapter->dmaq1.buffer_size) - adapter->dmaq1.tail = adapter->dmaq1.tail - adapter->dmaq1.buffer_size; - }; -} - -static void interrupt_service_dma2(struct adapter *adapter) -{ - printk("%s:\n", __FUNCTION__); -} - -static irqreturn_t isr(int irq, void *dev_id, struct pt_regs *regs) -{ - struct adapter *tmp = dev_id; - - u32 value; - - ddprintk("%s:\n", __FUNCTION__); - - spin_lock_irq(&tmp->lock); - - if (0 == ((value = read_reg_dw(tmp, 0x20c)) & 0x0f)) { - spin_unlock_irq(&tmp->lock); - return IRQ_NONE; - } - - while (value != 0) { - if ((value & 0x03) != 0) - interrupt_service_dma1(tmp); - if ((value & 0x0c) != 0) - interrupt_service_dma2(tmp); - value = read_reg_dw(tmp, 0x20c) & 0x0f; - } - - spin_unlock_irq(&tmp->lock); - return IRQ_HANDLED; -} - -static int init_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq, - int size, int dmaq_offset) -{ - struct pci_dev *pdev = adapter->pdev; - dma_addr_t dma_addr; - - dmaq->head = 0; - dmaq->tail = 0; - - dmaq->buffer = pci_alloc_consistent(pdev, size + 0x80, &dma_addr); - if (!dmaq->buffer) - return -ENOMEM; - - dmaq->bus_addr = dma_addr; - dmaq->buffer_size = size; - - dma_init_dma(adapter, dmaq_offset); - - ddprintk("%s: allocated dma buffer at 0x%p, length=%d\n", - __FUNCTION__, dmaq->buffer, size); - - return 0; - } - -static int init_dma_queue(struct adapter *adapter) -{ - struct { - struct dmaq *dmaq; - u32 dma_status; - int size; - } dmaq_desc[] = { - { &adapter->dmaq1, 0x10000000, SIZE_OF_BUF_DMA1 }, - { &adapter->dmaq2, 0x20000000, SIZE_OF_BUF_DMA2 } - }, *p = dmaq_desc; - int i; - - for (i = 0; i < 2; i++, p++) { - if (init_dma_queue_one(adapter, p->dmaq, p->size, i) < 0) - adapter->dma_status &= ~p->dma_status; - else - adapter->dma_status |= p->dma_status; - } - return (adapter->dma_status & 0x30000000) ? 0 : -ENOMEM; -} - -static void free_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq) -{ - if (dmaq->buffer) { - pci_free_consistent(adapter->pdev, dmaq->buffer_size + 0x80, - dmaq->buffer, dmaq->bus_addr); - memset(dmaq, 0, sizeof(*dmaq)); - } -} - -static void free_dma_queue(struct adapter *adapter) -{ - struct dmaq *dmaq[] = { - &adapter->dmaq1, - &adapter->dmaq2, - NULL - }, **p; - - for (p = dmaq; *p; p++) - free_dma_queue_one(adapter, *p); - } - -static void release_adapter(struct adapter *adapter) -{ - struct pci_dev *pdev = adapter->pdev; - - iounmap(adapter->io_mem); - pci_disable_device(pdev); - pci_release_region(pdev, 0); - pci_release_region(pdev, 1); -} - -static void free_adapter_object(struct adapter *adapter) -{ - dprintk("%s:\n", __FUNCTION__); - - close_stream(adapter, 0); - free_irq(adapter->irq, adapter); - free_dma_queue(adapter); - release_adapter(adapter); - kfree(adapter); -} - -static struct pci_driver skystar2_pci_driver; - -static int claim_adapter(struct adapter *adapter) -{ - struct pci_dev *pdev = adapter->pdev; - u16 var; - int ret; - - ret = pci_request_region(pdev, 1, skystar2_pci_driver.name); - if (ret < 0) - goto out; - - ret = pci_request_region(pdev, 0, skystar2_pci_driver.name); - if (ret < 0) - goto err_pci_release_1; - - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &adapter->card_revision); - - dprintk("%s: card revision %x \n", __FUNCTION__, adapter->card_revision); - - ret = pci_enable_device(pdev); - if (ret < 0) - goto err_pci_release_0; - - pci_read_config_word(pdev, 4, &var); - - if ((var & 4) == 0) - pci_set_master(pdev); - - adapter->io_port = pdev->resource[1].start; - - adapter->io_mem = ioremap(pdev->resource[0].start, 0x800); - - if (!adapter->io_mem) { - dprintk("%s: can not map io memory\n", __FUNCTION__); - ret = -EIO; - goto err_pci_disable; - } - - dprintk("%s: io memory maped at %p\n", __FUNCTION__, adapter->io_mem); - - ret = 1; -out: - return ret; - -err_pci_disable: - pci_disable_device(pdev); -err_pci_release_0: - pci_release_region(pdev, 0); -err_pci_release_1: - pci_release_region(pdev, 1); - goto out; -} - -/* -static int sll_reset_flexcop(struct adapter *adapter) -{ - write_reg_dw(adapter, 0x208, 0); - write_reg_dw(adapter, 0x210, 0xb2ff); - - return 0; -} -*/ - -static void decide_how_many_hw_filters(struct adapter *adapter) -{ - int hw_filters; - int mod_option_hw_filters; - - // FlexCop IIb & III have 6+32 hw filters - // FlexCop II has 6 hw filters, every other should have at least 6 - switch (adapter->b2c2_revision) { - case 0x82: /* II */ - hw_filters = 6; - break; - case 0xc3: /* IIB */ - hw_filters = 6 + 32; - break; - case 0xc0: /* III */ - hw_filters = 6 + 32; - break; - default: - hw_filters = 6; - break; - } - printk("%s: the chip has %i hardware filters", __FILE__, hw_filters); - - mod_option_hw_filters = 0; - if (enable_hw_filters >= 1) - mod_option_hw_filters += 6; - if (enable_hw_filters >= 2) - mod_option_hw_filters += 32; - - if (mod_option_hw_filters >= hw_filters) { - adapter->useable_hw_filters = hw_filters; - } else { - adapter->useable_hw_filters = mod_option_hw_filters; - printk(", but only %d will be used because of module option", mod_option_hw_filters); - } - printk("\n"); - dprintk("%s: useable_hardware_filters set to %i\n", __FILE__, adapter->useable_hw_filters); -} - -static int driver_initialize(struct pci_dev *pdev) -{ - struct adapter *adapter; - u32 tmp; - int ret = -ENOMEM; - - adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL); - if (!adapter) { - dprintk("%s: out of memory!\n", __FUNCTION__); - goto out; - } - - memset(adapter, 0, sizeof(struct adapter)); - - pci_set_drvdata(pdev,adapter); - - adapter->pdev = pdev; - adapter->irq = pdev->irq; - - ret = claim_adapter(adapter); - if (ret < 0) - goto err_kfree; - - irq_dma_enable_disable_irq(adapter, 0); - - ret = request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter); - if (ret < 0) { - dprintk("%s: unable to allocate irq=%d !\n", __FUNCTION__, pdev->irq); - goto err_release_adapter; - } - - read_reg_dw(adapter, 0x208); - write_reg_dw(adapter, 0x208, 0); - write_reg_dw(adapter, 0x210, 0xb2ff); - write_reg_dw(adapter, 0x208, 0x40); - - ret = init_dma_queue(adapter); - if (ret < 0) - goto err_free_irq; - - adapter->b2c2_revision = (read_reg_dw(adapter, 0x204) >> 0x18); - - switch (adapter->b2c2_revision) { - case 0x82: - printk("%s: FlexCopII(rev.130) chip found\n", __FILE__); - break; - case 0xc3: - printk("%s: FlexCopIIB(rev.195) chip found\n", __FILE__); - break; - case 0xc0: - printk("%s: FlexCopIII(rev.192) chip found\n", __FILE__); - break; - default: - printk("%s: The revision of the FlexCop chip on your card is %d\n", __FILE__, adapter->b2c2_revision); - printk("%s: This driver works only with FlexCopII(rev.130), FlexCopIIB(rev.195) and FlexCopIII(rev.192).\n", __FILE__); - ret = -ENODEV; - goto err_free_dma_queue; - } - - decide_how_many_hw_filters(adapter); - - init_pids(adapter); - - tmp = read_reg_dw(adapter, 0x204); - - write_reg_dw(adapter, 0x204, 0); - mdelay(20); - - write_reg_dw(adapter, 0x204, tmp); - mdelay(10); - - tmp = read_reg_dw(adapter, 0x308); - write_reg_dw(adapter, 0x308, 0x4000 | tmp); - - adapter->dw_sram_type = 0x10000; - - sll_detect_sram_size(adapter); - - dprintk("%s sram length = %d, sram type= %x\n", __FUNCTION__, sram_length(adapter), adapter->dw_sram_type); - - sram_set_media_dest(adapter, 1); - sram_set_net_dest(adapter, 1); - - ctrl_enable_smc(adapter, 0); - - sram_set_cai_dest(adapter, 2); - sram_set_cao_dest(adapter, 2); - - dma_enable_disable_irq(adapter, 1, 0, 0); - - if (eeprom_get_mac_addr(adapter, 0, adapter->mac_addr) != 0) { - printk("%s MAC address = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", __FUNCTION__, adapter->mac_addr[0], - adapter->mac_addr[1], adapter->mac_addr[2], adapter->mac_addr[3], adapter->mac_addr[4], adapter->mac_addr[5], - adapter->mac_addr[6], adapter->mac_addr[7] - ); - - ca_set_mac_dst_addr_filter(adapter, adapter->mac_addr); - ctrl_enable_mac(adapter, 1); - } - - spin_lock_init(&adapter->lock); - -out: - return ret; - -err_free_dma_queue: - free_dma_queue(adapter); -err_free_irq: - free_irq(pdev->irq, adapter); -err_release_adapter: - release_adapter(adapter); -err_kfree: - pci_set_drvdata(pdev, NULL); - kfree(adapter); - goto out; -} - -static void driver_halt(struct pci_dev *pdev) -{ - struct adapter *adapter = pci_get_drvdata(pdev); - - irq_dma_enable_disable_irq(adapter, 0); - - ctrl_enable_receive_data(adapter, 0); - - free_adapter_object(adapter); - - pci_set_drvdata(pdev, NULL); -} - -static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct adapter *adapter = (struct adapter *) dvbdmx->priv; - - dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type); - - open_stream(adapter, dvbdmxfeed->pid); - - return 0; -} - -static int dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct adapter *adapter = (struct adapter *) dvbdmx->priv; - - dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type); - - close_stream(adapter, dvbdmxfeed->pid); - - return 0; -} - -/* lnb control */ -static void set_tuner_tone(struct adapter *adapter, u8 tone) -{ - u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; - u16 ax; - - dprintk("%s: %u\n", __FUNCTION__, tone); - - switch (tone) { - case 1: - ax = wz_half_period_for_45_mhz[0]; - break; - case 2: - ax = wz_half_period_for_45_mhz[1]; - break; - case 3: - ax = wz_half_period_for_45_mhz[2]; - break; - case 4: - ax = wz_half_period_for_45_mhz[3]; - break; - - default: - ax = 0; - } - - if (ax != 0) { - write_reg_dw(adapter, 0x200, ((ax << 0x0f) + (ax & 0x7fff)) | 0x40000000); - - } else { - - write_reg_dw(adapter, 0x200, 0x40ff8000); - } -} - -static void set_tuner_polarity(struct adapter *adapter, u8 polarity) -{ - u32 var; - - dprintk("%s : polarity = %u \n", __FUNCTION__, polarity); - - var = read_reg_dw(adapter, 0x204); - - if (polarity == 0) { - dprintk("%s: LNB power off\n", __FUNCTION__); - var = var | 1; - }; - - if (polarity == 1) { - var = var & ~1; - var = var & ~4; - }; - - if (polarity == 2) { - var = var & ~1; - var = var | 4; - } - - write_reg_dw(adapter, 0x204, var); -} - -static void diseqc_send_bit(struct adapter *adapter, int data) -{ - set_tuner_tone(adapter, 1); - udelay(data ? 500 : 1000); - set_tuner_tone(adapter, 0); - udelay(data ? 1000 : 500); -} - - -static void diseqc_send_byte(struct adapter *adapter, int data) - { - int i, par = 1, d; - - for (i = 7; i >= 0; i--) { - d = (data >> i) & 1; - par ^= d; - diseqc_send_bit(adapter, d); - } - - diseqc_send_bit(adapter, par); - } - - -static int send_diseqc_msg(struct adapter *adapter, int len, u8 *msg, unsigned long burst) -{ - int i; - - set_tuner_tone(adapter, 0); - mdelay(16); - - for (i = 0; i < len; i++) - diseqc_send_byte(adapter, msg[i]); - - mdelay(16); - - if (burst != -1) { - if (burst) - diseqc_send_byte(adapter, 0xff); - else { - set_tuner_tone(adapter, 1); - udelay(12500); - set_tuner_tone(adapter, 0); - } - msleep(20); - } - - return 0; -} - -static int flexcop_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) -{ - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - switch(tone) { - case SEC_TONE_ON: - set_tuner_tone(adapter, 1); - break; - case SEC_TONE_OFF: - set_tuner_tone(adapter, 0); - break; - default: - return -EINVAL; - }; - - return 0; -} - -static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) - { - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - send_diseqc_msg(adapter, cmd->msg_len, cmd->msg, 0); - - return 0; - } - -static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) -{ - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - send_diseqc_msg(adapter, 0, NULL, minicmd); - - return 0; -} - -static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) - { - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); - - switch (voltage) { - case SEC_VOLTAGE_13: - dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13); - set_tuner_polarity(adapter, 1); - return 0; - - case SEC_VOLTAGE_18: - dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18); - set_tuner_polarity(adapter, 2); - return 0; - - default: - return -EINVAL; - } - } - -static int flexcop_sleep(struct dvb_frontend* fe) - { - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - dprintk("%s: FE_SLEEP\n", __FUNCTION__); - set_tuner_polarity(adapter, 0); - - if (adapter->fe_sleep) return adapter->fe_sleep(fe); - return 0; - } - -static u32 flexcop_i2c_func(struct i2c_adapter *adapter) - { - printk("flexcop_i2c_func\n"); - - return I2C_FUNC_I2C; -} - -static struct i2c_algorithm flexcop_algo = { - .name = "flexcop i2c algorithm", - .id = I2C_ALGO_BIT, - .master_xfer = master_xfer, - .functionality = flexcop_i2c_func, -}; - - - - -static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - - if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } - else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } - else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } - else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } - else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } - else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } - - stv0299_writereg (fe, 0x13, aclk); - stv0299_writereg (fe, 0x14, bclk); - stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); - - return 0; -} - -static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - u8 buf[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - div = params->frequency / 125; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x84; // 0xC4 - buf[3] = 0x08; - - if (params->frequency < 1500000) buf[3] |= 0x10; - - if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static u8 samsung_tbmu24112_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7D, - 0x05, 0x35, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0xC3, - 0x0C, 0x00, - 0x0D, 0x81, - 0x0E, 0x23, - 0x0F, 0x12, - 0x10, 0x7E, - 0x11, 0x84, - 0x12, 0xB9, - 0x13, 0x88, - 0x14, 0x89, - 0x15, 0xC9, - 0x16, 0x00, - 0x17, 0x5C, - 0x18, 0x00, - 0x19, 0x00, - 0x1A, 0x00, - 0x1C, 0x00, - 0x1D, 0x00, - 0x1E, 0x00, - 0x1F, 0x3A, - 0x20, 0x2E, - 0x21, 0x80, - 0x22, 0xFF, - 0x23, 0xC1, - 0x28, 0x00, - 0x29, 0x1E, - 0x2A, 0x14, - 0x2B, 0x0F, - 0x2C, 0x09, - 0x2D, 0x05, - 0x31, 0x1F, - 0x32, 0x19, - 0x33, 0xFE, - 0x34, 0x93, - 0xff, 0xff, - }; - -static struct stv0299_config samsung_tbmu24112_config = { - .demod_address = 0x68, - .inittab = samsung_tbmu24112_inittab, - .mclk = 88000000UL, - .invert = 0, - .enhanced_tuning = 0, - .skip_reinit = 0, - .lock_output = STV0229_LOCKOUTPUT_LK, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 100, - .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, - .pll_set = samsung_tbmu24112_pll_set, -}; - - - -static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) -{ - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - return request_firmware(fw, name, &adapter->pdev->dev); -} - - -static struct nxt2002_config samsung_tbmv_config = { - .demod_address = 0x0A, - .request_firmware = nxt2002_request_firmware, -}; - -static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) -{ - static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d }; - static u8 mt352_reset [] = { 0x50, 0x80 }; - static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; - static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; - - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) -{ - u32 div; - unsigned char bs = 0; - - #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; - if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; - if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; - - pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address - pllbuf[1] = div >> 8; - pllbuf[2] = div & 0xff; - pllbuf[3] = 0xcc; - pllbuf[4] = bs; - - return 0; -} - -static struct mt352_config samsung_tdtc9251dh0_config = { - - .demod_address = 0x0f, - .demod_init = samsung_tdtc9251dh0_demod_init, - .pll_set = samsung_tdtc9251dh0_pll_set, -}; - -static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) -{ - u8 buf[4]; - u32 div; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - struct adapter* adapter = (struct adapter*) fe->dvb->priv; - - div = (params->frequency + (125/2)) / 125; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = (div >> 0) & 0xff; - buf[2] = 0x84 | ((div >> 10) & 0x60); - buf[3] = 0x80; - - if (params->frequency < 1550000) - buf[3] |= 0x02; - - if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct mt312_config skystar23_samsung_tbdu18132_config = { - - .demod_address = 0x0e, - .pll_set = skystar23_samsung_tbdu18132_pll_set, -}; - - - - -static void frontend_init(struct adapter *skystar2) -{ - switch(skystar2->pdev->device) { - case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 (DVB-T or ATSC) - - // Attempt to load the Nextwave nxt2002 for ATSC support - skystar2->fe = nxt2002_attach(&samsung_tbmv_config, &skystar2->i2c_adap); - if (skystar2->fe != NULL) { - skystar2->fe_sleep = skystar2->fe->ops->sleep; - skystar2->fe->ops->sleep = flexcop_sleep; - break; - } - - // try the skystar2 v2.6 first (stv0299/Samsung tbmu24112(sl1935)) - skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap); - if (skystar2->fe != NULL) { - skystar2->fe->ops->set_voltage = flexcop_set_voltage; - skystar2->fe_sleep = skystar2->fe->ops->sleep; - skystar2->fe->ops->sleep = flexcop_sleep; - break; -} - - // try the airstar2 (mt352/Samsung tdtc9251dh0(??)) - skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap); - if (skystar2->fe != NULL) { - skystar2->fe->ops->info.frequency_min = 474000000; - skystar2->fe->ops->info.frequency_max = 858000000; - break; - } - - // try the skystar2 v2.3 (vp310/Samsung tbdu18132(tsa5059)) - skystar2->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &skystar2->i2c_adap); - if (skystar2->fe != NULL) { - skystar2->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; - skystar2->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst; - skystar2->fe->ops->set_tone = flexcop_set_tone; - skystar2->fe->ops->set_voltage = flexcop_set_voltage; - skystar2->fe_sleep = skystar2->fe->ops->sleep; - skystar2->fe->ops->sleep = flexcop_sleep; - break; - } - break; - } - - if (skystar2->fe == NULL) { - printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", - skystar2->pdev->vendor, - skystar2->pdev->device, - skystar2->pdev->subsystem_vendor, - skystar2->pdev->subsystem_device); - } else { - if (dvb_register_frontend(&skystar2->dvb_adapter, skystar2->fe)) { - printk("skystar2: Frontend registration failed!\n"); - if (skystar2->fe->ops->release) - skystar2->fe->ops->release(skystar2->fe); - skystar2->fe = NULL; - } - } -} - - -static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct adapter *adapter; - struct dvb_adapter *dvb_adapter; - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - int ret = -ENODEV; - - if (!pdev) - goto out; - - ret = driver_initialize(pdev); - if (ret < 0) - goto out; - - adapter = pci_get_drvdata(pdev); - dvb_adapter = &adapter->dvb_adapter; - - ret = dvb_register_adapter(dvb_adapter, skystar2_pci_driver.name, - THIS_MODULE); - if (ret < 0) { - printk("%s: Error registering DVB adapter\n", __FUNCTION__); - goto err_halt; - } - - dvb_adapter->priv = adapter; - - - init_MUTEX(&adapter->i2c_sem); - - - memset(&adapter->i2c_adap, 0, sizeof(struct i2c_adapter)); - strcpy(adapter->i2c_adap.name, "SkyStar2"); - - i2c_set_adapdata(&adapter->i2c_adap, adapter); - -#ifdef I2C_ADAP_CLASS_TV_DIGITAL - adapter->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL; -#else - adapter->i2c_adap.class = I2C_CLASS_TV_DIGITAL; -#endif - adapter->i2c_adap.algo = &flexcop_algo; - adapter->i2c_adap.algo_data = NULL; - adapter->i2c_adap.id = I2C_ALGO_BIT; - - ret = i2c_add_adapter(&adapter->i2c_adap); - if (ret < 0) - goto err_dvb_unregister; - - dvbdemux = &adapter->demux; - - dvbdemux->priv = adapter; - dvbdemux->filternum = N_PID_SLOTS; - dvbdemux->feednum = N_PID_SLOTS; - dvbdemux->start_feed = dvb_start_feed; - dvbdemux->stop_feed = dvb_stop_feed; - dvbdemux->write_to_decoder = NULL; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); - - ret = dvb_dmx_init(&adapter->demux); - if (ret < 0) - goto err_i2c_del; - - dmx = &dvbdemux->dmx; - - adapter->hw_frontend.source = DMX_FRONTEND_0; - adapter->dmxdev.filternum = N_PID_SLOTS; - adapter->dmxdev.demux = dmx; - adapter->dmxdev.capabilities = 0; - - ret = dvb_dmxdev_init(&adapter->dmxdev, &adapter->dvb_adapter); - if (ret < 0) - goto err_dmx_release; - - ret = dmx->add_frontend(dmx, &adapter->hw_frontend); - if (ret < 0) - goto err_dmxdev_release; - - adapter->mem_frontend.source = DMX_MEMORY_FE; - - ret = dmx->add_frontend(dmx, &adapter->mem_frontend); - if (ret < 0) - goto err_remove_hw_frontend; - - ret = dmx->connect_frontend(dmx, &adapter->hw_frontend); - if (ret < 0) - goto err_remove_mem_frontend; - - dvb_net_init(&adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx); - - frontend_init(adapter); -out: - return ret; - -err_remove_mem_frontend: - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend); -err_remove_hw_frontend: - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend); -err_dmxdev_release: - dvb_dmxdev_release(&adapter->dmxdev); -err_dmx_release: - dvb_dmx_release(&adapter->demux); -err_i2c_del: - i2c_del_adapter(&adapter->i2c_adap); -err_dvb_unregister: - dvb_unregister_adapter(&adapter->dvb_adapter); -err_halt: - driver_halt(pdev); - goto out; -} - -static void skystar2_remove(struct pci_dev *pdev) -{ - struct adapter *adapter = pci_get_drvdata(pdev); - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - - if (!adapter) - return; - - dvb_net_release(&adapter->dvbnet); - dvbdemux = &adapter->demux; - dmx = &dvbdemux->dmx; - - dmx->close(dmx); - dmx->remove_frontend(dmx, &adapter->hw_frontend); - dmx->remove_frontend(dmx, &adapter->mem_frontend); - - dvb_dmxdev_release(&adapter->dmxdev); - dvb_dmx_release(dvbdemux); - - if (adapter->fe != NULL) - dvb_unregister_frontend(adapter->fe); - - dvb_unregister_adapter(&adapter->dvb_adapter); - - i2c_del_adapter(&adapter->i2c_adap); - - driver_halt(pdev); - } - -static struct pci_device_id skystar2_pci_tbl[] = { - {0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, -/* {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */ //FCIII - {0,}, -}; - -MODULE_DEVICE_TABLE(pci, skystar2_pci_tbl); - -static struct pci_driver skystar2_pci_driver = { - .name = "SkyStar2", - .id_table = skystar2_pci_tbl, - .probe = skystar2_probe, - .remove = skystar2_remove, -}; - -static int skystar2_init(void) -{ - return pci_register_driver(&skystar2_pci_driver); -} - -static void skystar2_cleanup(void) -{ - pci_unregister_driver(&skystar2_pci_driver); -} - -module_init(skystar2_init); -module_exit(skystar2_cleanup); - -MODULE_DESCRIPTION("Technisat SkyStar2 DVB PCI Driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 6757ccc57d2cc4ab4e63d8aee97f2e6b9f998990 Mon Sep 17 00:00:00 2001 From: Peter Beutner Date: Thu, 7 Jul 2005 17:57:36 -0700 Subject: [PATCH] dvb: core: fix race condition in FE_READ_STATUS ioctl Fix a race condition where an application which issued a FE_READ_STATUS ioctl directly after FE_SET_FRONTEND would see an old status, i.e. FE_READ_STATUS would be executed before the frontend thread has even seen the tungin request from FE_SET_FRONTEND. Signed-off-by: Peter Beutner Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dvb_frontend.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index f11daae91cd..e561ac1e1b1 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -626,11 +626,21 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, break; } - case FE_READ_STATUS: + case FE_READ_STATUS: { + fe_status_t* status = parg; + + /* if retune was requested but hasn't occured yet, prevent + * that user get signal state from previous tuning */ + if(fepriv->state == FESTATE_RETUNE) { + err=0; + *status = 0; + break; + } + if (fe->ops->read_status) - err = fe->ops->read_status(fe, (fe_status_t*) parg); + err = fe->ops->read_status(fe, status); break; - + } case FE_READ_BER: if (fe->ops->read_ber) err = fe->ops->read_ber(fe, (__u32*) parg); -- cgit v1.2.3 From 4992775c8287145e86b94fe8d19bbb5f20148cc0 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Thu, 7 Jul 2005 17:57:37 -0700 Subject: [PATCH] dvb: core: add workaround for tuning problem Add workaround for signal lock loss issue, where the frontend loses the signal after some hours without any visible reason. Signed-off-by: Andrew de Quincey Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dvb_frontend.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index e561ac1e1b1..a8bc84240b5 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -42,6 +42,8 @@ #include "dvb_frontend.h" #include "dvbdev.h" +// #define DEBUG_LOCKLOSS 1 + static int dvb_frontend_debug; static int dvb_shutdown_timeout = 5; static int dvb_force_auto_inversion; @@ -113,6 +115,7 @@ struct dvb_frontend_private { int exit; int wakeup; fe_status_t status; + fe_sec_tone_mode_t tone; }; @@ -434,9 +437,26 @@ static int dvb_frontend_thread(void *data) /* we're tuned, and the lock is still good... */ if (s & FE_HAS_LOCK) continue; - else { - /* if we _WERE_ tuned, but now don't have a lock, - * need to zigzag */ + else { /* if we _WERE_ tuned, but now don't have a lock */ +#ifdef DEBUG_LOCKLOSS + /* first of all try setting the tone again if it was on - this + * sometimes works around problems with noisy power supplies */ + if (fe->ops->set_tone && (fepriv->tone == SEC_TONE_ON)) { + fe->ops->set_tone(fe, fepriv->tone); + mdelay(100); + s = 0; + fe->ops->read_status(fe, &s); + if (s & FE_HAS_LOCK) { + printk("DVB%i: Lock was lost, but regained by setting " + "the tone. This may indicate your power supply " + "is noisy/slightly incompatable with this DVB-S " + "adapter\n", fe->dvb->num); + fepriv->state = FESTATE_TUNED; + continue; + } + } +#endif + /* some other reason for losing the lock - start zigzagging */ fepriv->state = FESTATE_ZIGZAG_FAST; fepriv->started_auto_step = fepriv->auto_step; check_wrapped = 0; @@ -691,6 +711,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; + fepriv->tone = (fe_sec_tone_mode_t) parg; } break; @@ -893,6 +914,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, init_MUTEX (&fepriv->events.sem); fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; + fepriv->tone = SEC_TONE_OFF; printk ("DVB: registering frontend %i (%s)...\n", fe->dvb->num, -- cgit v1.2.3 From 761979248adf83f5bece22e058ec445511984012 Mon Sep 17 00:00:00 2001 From: Peter Beutner Date: Thu, 7 Jul 2005 17:57:38 -0700 Subject: [PATCH] dvb: core: demux error handling fix In dvb_dmxdev_filter_start if we go out because of an error, release previously allocated demux_feed. Signed-off-by: Peter Beutner Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dmxdev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index c225de7ffd8..1624f4be5ea 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -669,8 +669,10 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) ret = filter->feed.ts->start_filtering(filter->feed.ts); - if (ret < 0) + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); return ret; + } break; } -- cgit v1.2.3 From 3ec4a30771ed9a0ce6f05e637ea83b3781cc61d7 Mon Sep 17 00:00:00 2001 From: Peter Beutner Date: Thu, 7 Jul 2005 17:57:39 -0700 Subject: [PATCH] dvb: core: dmxdev cleanups - remove void casts - not necessary to set filter state twice to STATE_FREE during dvb_dmxdev_init() Signed-off-by: Peter Beutner Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dmxdev.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 1624f4be5ea..68050cd527c 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -42,12 +42,6 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); #define dprintk if (debug) printk -static inline struct dmxdev_filter * -dvb_dmxdev_file_to_filter(struct file *file) -{ - return (struct dmxdev_filter *) file->private_data; -} - static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer) { buffer->data=NULL; @@ -844,7 +838,7 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, static ssize_t dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file); + struct dmxdev_filter *dmxdevfilter= file->private_data; int ret=0; if (down_interruptible(&dmxdevfilter->mutex)) @@ -865,7 +859,7 @@ dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file); + struct dmxdev_filter *dmxdevfilter = file->private_data; struct dmxdev *dmxdev=dmxdevfilter->dev; unsigned long arg=(unsigned long) parg; int ret=0; @@ -962,7 +956,7 @@ static int dvb_demux_ioctl(struct inode *inode, struct file *file, static unsigned int dvb_demux_poll (struct file *file, poll_table *wait) { - struct dmxdev_filter *dmxdevfilter = dvb_dmxdev_file_to_filter(file); + struct dmxdev_filter *dmxdevfilter = file->private_data; unsigned int mask = 0; if (!dmxdevfilter) @@ -987,7 +981,7 @@ static unsigned int dvb_demux_poll (struct file *file, poll_table *wait) static int dvb_demux_release(struct inode *inode, struct file *file) { - struct dmxdev_filter *dmxdevfilter = dvb_dmxdev_file_to_filter(file); + struct dmxdev_filter *dmxdevfilter = file->private_data; struct dmxdev *dmxdev = dmxdevfilter->dev; return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); @@ -1111,7 +1105,6 @@ dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); dmxdev->dvr[i].dev=dmxdev; dmxdev->dvr[i].buffer.data=NULL; - dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE); } -- cgit v1.2.3 From bbf24cec93b5966bdbd4f25be7a8a2d8716570db Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Thu, 7 Jul 2005 17:57:40 -0700 Subject: [PATCH] dvb: frontend: remove unused I2C ids Remove I2C_DRIVERID_DVBFE_ cruft. Signed-off-by: Andrew de Quincey Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-core/dvb_frontend.h | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index d2b02179279..9c2c1d1136b 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -40,28 +40,6 @@ #include "dvbdev.h" -/* FIXME: Move to i2c-id.h */ -#define I2C_DRIVERID_DVBFE_SP8870 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_CX22700 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_AT76C651 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_CX24110 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_CX22702 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_DIB3000MB I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_DST I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_DUMMY I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_L64781 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_MT312 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_MT352 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_NXT6000 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_SP887X I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_STV0299 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_TDA1004X I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_TDA8083 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_VES1820 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_VES1X93 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_TDA80XX I2C_DRIVERID_EXP2 - - struct dvb_frontend_tune_settings { int min_delay_ms; int step_size; -- cgit v1.2.3 From ecb60deb9d5bbcbab6c87ee5fde6f8368197fcac Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Thu, 7 Jul 2005 17:57:40 -0700 Subject: [PATCH] dvb: frontend: tda1004x update o added config options for IF frequency and AGC o support DSP boot from on board eeprom o added pll sleep call Signed-off-by: Hartmut Hackmann Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/tda1004x.c | 193 +++++++++++++++++---------------- drivers/media/dvb/frontends/tda1004x.h | 27 ++++- drivers/media/dvb/ttpci/budget-av.c | 4 + drivers/media/dvb/ttpci/budget-ci.c | 4 + 4 files changed, 130 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 0beb370792a..8428c04914e 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -49,10 +49,8 @@ struct tda1004x_state { /* private demod data */ u8 initialised; enum tda1004x_demod demod_type; - u8 fw_version; }; - static int debug; #define dprintk(args...) \ do { \ @@ -315,20 +313,35 @@ static int tda1004x_do_upload(struct tda1004x_state *state, memcpy(buf + 1, mem + pos, tx_size); fw_msg.len = tx_size + 1; if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) { - printk("tda1004x: Error during firmware upload\n"); + printk(KERN_ERR "tda1004x: Error during firmware upload\n"); return -EIO; } pos += tx_size; dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos); } + // give the DSP a chance to settle 03/10/05 Hac + msleep(100); return 0; } -static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion) +static int tda1004x_check_upload_ok(struct tda1004x_state *state) { u8 data1, data2; + unsigned long timeout; + + if (state->demod_type == TDA1004X_DEMOD_TDA10046) { + timeout = jiffies + 2 * HZ; + while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) { + if (time_after(jiffies, timeout)) { + printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n"); + break; + } + msleep(1); + } + } else + msleep(100); // check upload was OK tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP @@ -336,9 +349,11 @@ static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion) data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1); data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2); - if ((data1 != 0x67) || (data2 != dspVersion)) + if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2a) { + printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2); return -EIO; - + } + printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2); return 0; } @@ -349,14 +364,14 @@ static int tda10045_fwupload(struct dvb_frontend* fe) const struct firmware *fw; /* don't re-upload unless necessary */ - if (tda1004x_check_upload_ok(state, 0x2c) == 0) + if (tda1004x_check_upload_ok(state) == 0) return 0; /* request the firmware, this will block until someone uploads it */ - printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE); + printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE); ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); if (ret) { - printk("tda1004x: no firmware upload (timeout or file not found?)\n"); + printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); return ret; } @@ -372,93 +387,81 @@ static int tda10045_fwupload(struct dvb_frontend* fe) ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN); if (ret) return ret; - printk("tda1004x: firmware upload complete\n"); + printk(KERN_INFO "tda1004x: firmware upload complete\n"); /* wait for DSP to initialise */ /* DSPREADY doesn't seem to work on the TDA10045H */ msleep(100); - return tda1004x_check_upload_ok(state, 0x2c); + return tda1004x_check_upload_ok(state); } -static int tda10046_get_fw_version(struct tda1004x_state *state, - const struct firmware *fw) +static void tda10046_init_plls(struct dvb_frontend* fe) { - const unsigned char pattern[] = { 0x67, 0x00, 0x50, 0x62, 0x5e, 0x18, 0x67 }; - unsigned int i; - - /* area guessed from firmware v20, v21 and v25 */ - for (i = 0x660; i < 0x700; i++) { - if (!memcmp(&fw->data[i], pattern, sizeof(pattern))) { - state->fw_version = fw->data[i + sizeof(pattern)]; - printk(KERN_INFO "tda1004x: using firmware v%02x\n", - state->fw_version); - return 0; - } - } + struct tda1004x_state* state = fe->demodulator_priv; - return -EINVAL; + tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0); + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10 + if (state->config->xtal_freq == TDA10046_XTAL_4M ) { + dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__); + tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 + } else { + dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__); + tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3 + } + tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); + switch (state->config->if_freq) { + case TDA10046_FREQ_3617: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); + break; + case TDA10046_FREQ_3613: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13); + break; + } + tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz } static int tda10046_fwupload(struct dvb_frontend* fe) { struct tda1004x_state* state = fe->demodulator_priv; - unsigned long timeout; int ret; const struct firmware *fw; /* reset + wake up chip */ - tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); + tda1004x_write_byteI(state, TDA1004X_CONFC4, 0); tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); - msleep(100); + /* let the clocks recover from sleep */ + msleep(5); /* don't re-upload unless necessary */ - if (tda1004x_check_upload_ok(state, state->fw_version) == 0) + if (tda1004x_check_upload_ok(state) == 0) return 0; - /* request the firmware, this will block until someone uploads it */ - printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10046_DEFAULT_FIRMWARE); - ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); - if (ret) { - printk("tda1004x: no firmware upload (timeout or file not found?)\n"); - return ret; - } - - if (fw->size < 24478) { /* size of firmware v20, which is the smallest of v20, v21 and v25 */ - printk("tda1004x: firmware file seems to be too small (%d bytes)\n", fw->size); - return -EINVAL; - } - - ret = tda10046_get_fw_version(state, fw); - if (ret < 0) { - printk("tda1004x: unable to find firmware version\n"); - return ret; - } - /* set parameters */ - tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); - tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); - tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); - tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST - - ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); - if (ret) - return ret; - printk("tda1004x: firmware upload complete\n"); - - /* wait for DSP to initialise */ - timeout = jiffies + HZ; - while (!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) { - if (time_after(jiffies, timeout)) { - printk("tda1004x: DSP failed to initialised.\n"); - return -EIO; + tda10046_init_plls(fe); + + if (state->config->request_firmware != NULL) { + /* request the firmware, this will block until someone uploads it */ + printk(KERN_INFO "tda1004x: waiting for firmware upload...\n"); + ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); + if (ret) { + printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n"); + return ret; } - msleep(1); + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST + ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); + if (ret) + return ret; + } else { + /* boot from firmware eeprom */ + /* Hac Note: we might need to do some GPIO Magic here */ + printk(KERN_INFO "tda1004x: booting from eeprom\n"); + tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4); + msleep(300); } - - return tda1004x_check_upload_ok(state, state->fw_version); + return tda1004x_check_upload_ok(state); } static int tda1004x_encode_fec(int fec) @@ -560,12 +563,10 @@ static int tda10046_init(struct dvb_frontend* fe) if (tda10046_fwupload(fe)) { printk("tda1004x: firmware upload failed\n"); - return -EIO; + return -EIO; } - tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); // wake up the chip - - // Init the PLL + // Init the tuner PLL if (state->config->pll_init) { tda1004x_enable_tuner_i2c(state); state->config->pll_init(fe); @@ -574,32 +575,34 @@ static int tda10046_init(struct dvb_frontend* fe) // tda setup tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer - tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0x40); - tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream - tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer - tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10 - tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); // PLL P = N = 0 - tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99 - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221 - tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // } - tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0); // AGC setup - tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities + tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream + tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer + + tda10046_init_plls(fe); + switch (state->config->agc_config) { + case TDA10046_AGC_DEFAULT: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities + break; + case TDA10046_AGC_IFO_AUTO_NEG: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities + break; + } + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // } - tda1004x_write_mask(state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1 - tda1004x_write_mask(state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm + tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config - tda1004x_write_mask(state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config - tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN + tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config + tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config - tda1004x_write_mask(state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select - tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz - - tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); + tda1004x_write_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select state->initialised = 1; return 0; @@ -629,9 +632,6 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, state->config->pll_set(fe, fe_params); tda1004x_disable_tuner_i2c(state); - if (state->demod_type == TDA1004X_DEMOD_TDA10046) - tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 4); - // Hardcoded to use auto as much as possible on the TDA10045 as it // is very unreliable if AUTO mode is _not_ used. if (state->demod_type == TDA1004X_DEMOD_TDA10045) { @@ -1090,6 +1090,8 @@ static int tda1004x_sleep(struct dvb_frontend* fe) case TDA1004X_DEMOD_TDA10046: tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); + if (state->config->pll_sleep != NULL) + state->config->pll_sleep(fe); break; } state->initialised = 0; @@ -1216,7 +1218,6 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); state->initialised = 0; state->demod_type = TDA1004X_DEMOD_TDA10046; - state->fw_version = 0x20; /* dummy default value */ /* check if the demod is there */ if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) { diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h index c8e1d54ff26..103d08ff7b5 100644 --- a/drivers/media/dvb/frontends/tda1004x.h +++ b/drivers/media/dvb/frontends/tda1004x.h @@ -26,6 +26,21 @@ #include #include +enum tda10046_xtal { + TDA10046_XTAL_4M, + TDA10046_XTAL_16M, +}; + +enum tda10046_agc { + TDA10046_AGC_DEFAULT, /* original configuration */ + TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ +}; + +enum tda10046_if { + TDA10046_FREQ_3617, /* original config, 36,166 MHZ */ + TDA10046_FREQ_3613, /* 36,13 MHZ */ +}; + struct tda1004x_config { /* the demodulator's i2c address */ @@ -37,14 +52,22 @@ struct tda1004x_config /* Does the OCLK signal need inverted? */ u8 invert_oclk; - /* value of N_I2C of the CONF_PLL3 register */ - u8 n_i2c; + /* Xtal frequency, 4 or 16MHz*/ + enum tda10046_xtal xtal_freq; + + /* IF frequency */ + enum tda10046_if if_freq; + + /* AGC configuration */ + enum tda10046_agc agc_config; /* PLL maintenance */ int (*pll_init)(struct dvb_frontend* fe); + void (*pll_sleep)(struct dvb_frontend* fe); int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); /* request firmware for device */ + /* set this to NULL if the card has a firmware EEPROM */ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 6e0f5d307c5..9e65bfd59c4 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -695,8 +695,12 @@ static struct tda1004x_config philips_tu1216_config = { .demod_address = 0x8, .invert = 1, .invert_oclk = 1, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, .pll_init = philips_tu1216_pll_init, .pll_set = philips_tu1216_pll_set, + .pll_sleep = NULL, .request_firmware = philips_tu1216_request_firmware, }; diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index dce11611137..075eb40f5c1 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -838,8 +838,12 @@ static struct tda1004x_config philips_tdm1316l_config = { .demod_address = 0x8, .invert = 0, .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, .pll_init = philips_tdm1316l_pll_init, .pll_set = philips_tdm1316l_pll_set, + .pll_sleep = NULL, .request_firmware = philips_tdm1316l_request_firmware, }; -- cgit v1.2.3 From 3faadbb0fde3c53e1c4f13eabb478c0c7cb1e4dd Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Thu, 7 Jul 2005 17:57:42 -0700 Subject: [PATCH] dvb: frontend: bcm3510: fix firmware version check Fix limit for firmware version check was too low for tda10045. Signed-off-by: Hartmut Hackmann Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/tda1004x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 8428c04914e..237edc48612 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -349,7 +349,7 @@ static int tda1004x_check_upload_ok(struct tda1004x_state *state) data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1); data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2); - if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2a) { + if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) { printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2); return -EIO; } -- cgit v1.2.3 From 0c744b010078bd65724477e75261e51712d290a0 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 7 Jul 2005 17:57:42 -0700 Subject: [PATCH] dvb: add missing release_firmware() calls Add missing release_firmware() calls to fix memory leaks. Signed-off-by: Anssi Hannula Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/tda1004x.c | 2 ++ drivers/media/dvb/ttusb-dec/ttusb_dec.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 237edc48612..2d5f56cbf50 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -385,6 +385,7 @@ static int tda10045_fwupload(struct dvb_frontend* fe) tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ); ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN); + release_firmware(fw); if (ret) return ret; printk(KERN_INFO "tda1004x: firmware upload complete\n"); @@ -452,6 +453,7 @@ static int tda10046_fwupload(struct dvb_frontend* fe) } tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); + release_firmware(fw); if (ret) return ret; } else { diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 505bdaff5a7..45c9a9a08e4 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1281,6 +1281,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) if (firmware_size < 60) { printk("%s: firmware size too small for DSP code (%zu < 60).\n", __FUNCTION__, firmware_size); + release_firmware(fw_entry); return -1; } @@ -1294,6 +1295,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) printk("%s: crc32 check of DSP code failed (calculated " "0x%08x != 0x%08x in file), file invalid.\n", __FUNCTION__, crc32_csum, crc32_check); + release_firmware(fw_entry); return -1; } memcpy(idstring, &firmware[36], 20); @@ -1308,15 +1310,19 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); - if (result) + if (result) { + release_firmware(fw_entry); return result; + } trans_count = 0; j = 0; b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL); - if (b == NULL) + if (b == NULL) { + release_firmware(fw_entry); return -ENOMEM; + } for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) { size = firmware_size - i; @@ -1345,6 +1351,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL); + release_firmware(fw_entry); kfree(b); return result; -- cgit v1.2.3 From f03cbea36ab9412dcea58e953be4933b36c9b7be Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Thu, 7 Jul 2005 17:57:43 -0700 Subject: [PATCH] dvb: frontend: tda1004x: support tda827x tuners o added preliminary support for tda827x tuners o set parameters for drift compensation to 0 makes no sense for DVB-T but can prevent lock Signed-off-by: Hartmut Hackmann Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/tda1004x.c | 44 ++++++++++++++++++++++++++++++---- drivers/media/dvb/frontends/tda1004x.h | 4 ++++ 2 files changed, 44 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 2d5f56cbf50..ab0c032472c 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -120,6 +120,8 @@ static int debug; #define TDA10046H_GPIO_OUT_SEL 0x41 #define TDA10046H_GPIO_SELECT 0x42 #define TDA10046H_AGC_CONF 0x43 +#define TDA10046H_AGC_THR 0x44 +#define TDA10046H_AGC_RENORM 0x45 #define TDA10046H_AGC_GAINS 0x46 #define TDA10046H_AGC_TUN_MIN 0x47 #define TDA10046H_AGC_TUN_MAX 0x48 @@ -272,14 +274,26 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state, switch (bandwidth) { case BANDWIDTH_6_MHZ: tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x09); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x4f); + } break; case BANDWIDTH_7_MHZ: tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x79); + } break; case BANDWIDTH_8_MHZ: tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz)); + if (state->config->if_freq == TDA10046_FREQ_045) { + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3); + } break; default: @@ -420,6 +434,14 @@ static void tda10046_init_plls(struct dvb_frontend* fe) tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13); break; + case TDA10046_FREQ_045: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3); + break; + case TDA10046_FREQ_052: + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06); + break; } tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz } @@ -590,6 +612,16 @@ static int tda10046_init(struct dvb_frontend* fe) tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities break; + case TDA10046_AGC_IFO_AUTO_POS: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities + break; + case TDA10046_AGC_TDA827X: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup + tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold + tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x0E); // Gain Renormalize + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities + break; } tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } @@ -1091,9 +1123,12 @@ static int tda1004x_sleep(struct dvb_frontend* fe) break; case TDA1004X_DEMOD_TDA10046: - tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); - if (state->config->pll_sleep != NULL) + if (state->config->pll_sleep != NULL) { + tda1004x_enable_tuner_i2c(state); state->config->pll_sleep(fe); + tda1004x_disable_tuner_i2c(state); + } + tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); break; } state->initialised = 0; @@ -1104,8 +1139,9 @@ static int tda1004x_sleep(struct dvb_frontend* fe) static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { fesettings->min_delay_ms = 800; - fesettings->step_size = 166667; - fesettings->max_drift = 166667*2; + /* Drift compensation makes no sense for DVB-T */ + fesettings->step_size = 0; + fesettings->max_drift = 0; return 0; } diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h index 103d08ff7b5..8659c52647a 100644 --- a/drivers/media/dvb/frontends/tda1004x.h +++ b/drivers/media/dvb/frontends/tda1004x.h @@ -34,11 +34,15 @@ enum tda10046_xtal { enum tda10046_agc { TDA10046_AGC_DEFAULT, /* original configuration */ TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ + TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */ + TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */ }; enum tda10046_if { TDA10046_FREQ_3617, /* original config, 36,166 MHZ */ TDA10046_FREQ_3613, /* 36,13 MHZ */ + TDA10046_FREQ_045, /* low IF, 4.0, 4.5, or 5.0 MHZ */ + TDA10046_FREQ_052, /* low IF, 5.1667 MHZ for tda9889 */ }; struct tda1004x_config -- cgit v1.2.3 From f46dbb050b5c7585c34b9ef717d81d6fee883f9b Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:57:44 -0700 Subject: [PATCH] dvb: frontend: cx22702: support for cxusb Add .get_tune_settings callback (min_delay_ms = 1sec) and output_mode-field (parallel/serial) to support cxusb; minor cleanups. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/cx22702.c | 29 ++++++++++++++++++++--------- drivers/media/dvb/frontends/cx22702.h | 5 +++++ 2 files changed, 25 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index f4aa44136c7..9f639297a9f 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -76,7 +76,6 @@ static u8 init_tab [] = { 0x49, 0x56, 0x6b, 0x1e, 0xc8, 0x02, - 0xf8, 0x02, 0xf9, 0x00, 0xfa, 0x00, 0xfb, 0x00, @@ -203,7 +202,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet struct cx22702_state* state = fe->demodulator_priv; /* set PLL */ - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); + cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); if (state->config->pll_set) { state->config->pll_set(fe, p); } else if (state->config->pll_desc) { @@ -217,7 +216,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet } else { BUG(); } - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); + cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); /* set inversion */ cx22702_set_inversion (state, p->inversion); @@ -256,7 +255,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc ); cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 ); cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */ - printk("%s: Autodetecting\n",__FUNCTION__); + dprintk("%s: Autodetecting\n",__FUNCTION__); return 0; } @@ -347,10 +346,11 @@ static int cx22702_init (struct dvb_frontend* fe) for (i=0; iconfig->output_mode << 1) & 0x02); /* init PLL */ if (state->config->pll_init) { - cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); + cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe); state->config->pll_init(fe); cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); } @@ -440,8 +440,10 @@ static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) /* RS Uncorrectable Packet Count then reset */ _ucblocks = cx22702_readreg (state, 0xE3); - if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks); - else *ucblocks = state->prevUCBlocks - _ucblocks; + if (state->prevUCBlocks < _ucblocks) + *ucblocks = (_ucblocks - state->prevUCBlocks); + else + *ucblocks = state->prevUCBlocks - _ucblocks; state->prevUCBlocks = _ucblocks; return 0; @@ -457,6 +459,12 @@ static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par return cx22702_get_tps (state, &p->u.ofdm); } +static int cx22702_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + static void cx22702_release(struct dvb_frontend* fe) { struct cx22702_state* state = fe->demodulator_priv; @@ -472,7 +480,8 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, /* allocate memory for the internal state */ state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL); - if (state == NULL) goto error; + if (state == NULL) + goto error; /* setup the state */ state->config = config; @@ -481,7 +490,8 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, state->prevUCBlocks = 0; /* check if the demod is there */ - if (cx22702_readreg(state, 0x1f) != 0x3) goto error; + if (cx22702_readreg(state, 0x1f) != 0x3) + goto error; /* create dvb_frontend */ state->frontend.ops = &state->ops; @@ -514,6 +524,7 @@ static struct dvb_frontend_ops cx22702_ops = { .set_frontend = cx22702_set_tps, .get_frontend = cx22702_get_frontend, + .get_tune_settings = cx22702_get_tune_settings, .read_status = cx22702_read_status, .read_ber = cx22702_read_ber, diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h index 559fdb90666..11f86806756 100644 --- a/drivers/media/dvb/frontends/cx22702.h +++ b/drivers/media/dvb/frontends/cx22702.h @@ -35,6 +35,11 @@ struct cx22702_config /* the demodulator's i2c address */ u8 demod_address; + /* serial/parallel output */ +#define CX22702_PARALLEL_OUTPUT 0 +#define CX22702_SERIAL_OUTPUT 1 + u8 output_mode; + /* PLL maintenance */ u8 pll_address; struct dvb_pll_desc *pll_desc; -- cgit v1.2.3 From 80064b803de140a65ca82bba5f0c40309b5a9f5e Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:57:45 -0700 Subject: [PATCH] dvb: frontend: l64781: improve tuning Disable zig-zag and set min_delay_ms = 4000 as suggested by Allan Guild to improve tuning with weak signal. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/l64781.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index 031a1ddc7d1..faaad1ae855 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -474,11 +474,12 @@ static int l64781_init(struct dvb_frontend* fe) return 0; } -static int l64781_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +static int l64781_get_tune_settings(struct dvb_frontend* fe, + struct dvb_frontend_tune_settings* fesettings) { - fesettings->min_delay_ms = 200; - fesettings->step_size = 166667; - fesettings->max_drift = 166667*2; + fesettings->min_delay_ms = 4000; + fesettings->step_size = 0; + fesettings->max_drift = 0; return 0; } -- cgit v1.2.3 From 48e4cc2d210e817e808ac9db598ce3fb5d09c205 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:57:45 -0700 Subject: [PATCH] dvb: DVB update Increase some timeouts by a factor of 10 as suggested by Mikko Hamalainen and Timo Ketolainen, to improve tuning for QAM128 / weak signal. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/stv0297.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index e681263bf07..928aca052af 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -617,7 +617,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* wait for WGAGC lock */ starttime = jiffies; - timeout = jiffies + (200 * HZ) / 1000; + timeout = jiffies + msecs_to_jiffies(2000); while (time_before(jiffies, timeout)) { msleep(10); if (stv0297_readreg(state, 0x43) & 0x08) @@ -629,7 +629,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par msleep(20); /* wait for equaliser partial convergence */ - timeout = jiffies + (50 * HZ) / 1000; + timeout = jiffies + msecs_to_jiffies(500); while (time_before(jiffies, timeout)) { msleep(10); @@ -642,7 +642,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par } /* wait for equaliser full convergence */ - timeout = jiffies + (delay * HZ) / 1000; + timeout = jiffies + msecs_to_jiffies(delay); while (time_before(jiffies, timeout)) { msleep(10); @@ -659,7 +659,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par stv0297_writereg_mask(state, 0x88, 8, 0); /* wait for main lock */ - timeout = jiffies + (20 * HZ) / 1000; + timeout = jiffies + msecs_to_jiffies(20); while (time_before(jiffies, timeout)) { msleep(10); -- cgit v1.2.3 From c7cadb3a02b5803c2f251b5cd84fbdc8fbec05e9 Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Thu, 7 Jul 2005 17:57:46 -0700 Subject: [PATCH] dvb: add Pluto2 driver Add driver for the Satelco Easywatch Mobile DVB-T card (based on Pluto2 chip). Signed-off-by: Andreas Oberritter Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/Kconfig | 4 + drivers/media/dvb/Makefile | 2 +- drivers/media/dvb/pluto2/Kconfig | 16 + drivers/media/dvb/pluto2/Makefile | 3 + drivers/media/dvb/pluto2/pluto2.c | 809 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 833 insertions(+), 1 deletion(-) create mode 100644 drivers/media/dvb/pluto2/Kconfig create mode 100644 drivers/media/dvb/pluto2/Makefile create mode 100644 drivers/media/dvb/pluto2/pluto2.c (limited to 'drivers') diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 01387f883cd..3f0ec6be03a 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -40,6 +40,10 @@ comment "Supported BT878 Adapters" depends on DVB_CORE && PCI source "drivers/media/dvb/bt8xx/Kconfig" +comment "Supported Pluto2 Adapters" + depends on DVB_CORE && PCI +source "drivers/media/dvb/pluto2/Kconfig" + comment "Supported DVB Frontends" depends on DVB_CORE source "drivers/media/dvb/frontends/Kconfig" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index 3c6ff161910..a7ad0841e6f 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -2,4 +2,4 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ +obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig new file mode 100644 index 00000000000..f02842be0d6 --- /dev/null +++ b/drivers/media/dvb/pluto2/Kconfig @@ -0,0 +1,16 @@ +config DVB_PLUTO2 + tristate "Pluto2 cards" + depends on DVB_CORE && PCI + select I2C + select I2C_ALGOBIT + select DVB_TDA1004X + help + Support for PCI cards based on the Pluto2 FPGA like the Satelco + Easywatch Mobile Terrestrial DVB-T Receiver. + + Since these cards have no MPEG decoder onboard, they transmit + only compressed MPEG data over the PCI bus, so you need + an external software decoder to watch TV on your computer. + + Say Y or M if you own such a device and want to use it. + diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile new file mode 100644 index 00000000000..86ca84b2be6 --- /dev/null +++ b/drivers/media/dvb/pluto2/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_DVB_PLUTO2) = pluto2.o + +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c new file mode 100644 index 00000000000..706e0bcb5ed --- /dev/null +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -0,0 +1,809 @@ +/* + * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T] + * + * Copyright (C) 2005 Andreas Oberritter + * + * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/ + * by Dany Salman + * Copyright (c) 2004 TDF + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" +#include "tda1004x.h" + +#define DRIVER_NAME "pluto2" + +#define REG_PIDn(n) ((n) << 2) /* PID n pattern registers */ +#define REG_PCAR 0x0020 /* PC address register */ +#define REG_TSCR 0x0024 /* TS ctrl & status */ +#define REG_MISC 0x0028 /* miscellaneous */ +#define REG_MMAC 0x002c /* MSB MAC address */ +#define REG_IMAC 0x0030 /* ISB MAC address */ +#define REG_LMAC 0x0034 /* LSB MAC address */ +#define REG_SPID 0x0038 /* SPI data */ +#define REG_SLCS 0x003c /* serial links ctrl/status */ + +#define PID0_NOFIL (0x0001 << 16) +#define PIDn_ENP (0x0001 << 15) +#define PID0_END (0x0001 << 14) +#define PID0_AFIL (0x0001 << 13) +#define PIDn_PID (0x1fff << 0) + +#define TSCR_NBPACKETS (0x00ff << 24) +#define TSCR_DEM (0x0001 << 17) +#define TSCR_DE (0x0001 << 16) +#define TSCR_RSTN (0x0001 << 15) +#define TSCR_MSKO (0x0001 << 14) +#define TSCR_MSKA (0x0001 << 13) +#define TSCR_MSKL (0x0001 << 12) +#define TSCR_OVR (0x0001 << 11) +#define TSCR_AFUL (0x0001 << 10) +#define TSCR_LOCK (0x0001 << 9) +#define TSCR_IACK (0x0001 << 8) +#define TSCR_ADEF (0x007f << 0) + +#define MISC_DVR (0x0fff << 4) +#define MISC_ALED (0x0001 << 3) +#define MISC_FRST (0x0001 << 2) +#define MISC_LED1 (0x0001 << 1) +#define MISC_LED0 (0x0001 << 0) + +#define SPID_SPIDR (0x00ff << 0) + +#define SLCS_SCL (0x0001 << 7) +#define SLCS_SDA (0x0001 << 6) +#define SLCS_CSN (0x0001 << 2) +#define SLCS_OVR (0x0001 << 1) +#define SLCS_SWC (0x0001 << 0) + +#define TS_DMA_PACKETS (8) +#define TS_DMA_BYTES (188 * TS_DMA_PACKETS) + +#define I2C_ADDR_TDA10046 0x10 +#define I2C_ADDR_TUA6034 0xc2 +#define NHWFILTERS 8 + +struct pluto { + /* pci */ + struct pci_dev *pdev; + u8 __iomem *io_mem; + + /* dvb */ + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dmxdev dmxdev; + struct dvb_adapter dvb_adapter; + struct dvb_demux demux; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + unsigned int full_ts_users; + unsigned int users; + + /* i2c */ + struct i2c_algo_bit_data i2c_bit; + struct i2c_adapter i2c_adap; + unsigned int i2cbug; + + /* irq */ + unsigned int overflow; + + /* dma */ + dma_addr_t dma_addr; + u8 dma_buf[TS_DMA_BYTES]; + u8 dummy[4096]; +}; + +static inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed) +{ + return container_of(feed->demux, struct pluto, demux); +} + +static inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe) +{ + return container_of(fe->dvb, struct pluto, dvb_adapter); +} + +static inline u32 pluto_readreg(struct pluto *pluto, u32 reg) +{ + return readl(&pluto->io_mem[reg]); +} + +static inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val) +{ + writel(val, &pluto->io_mem[reg]); +} + +static inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits) +{ + u32 val = readl(&pluto->io_mem[reg]); + val &= ~mask; + val |= bits; + writel(val, &pluto->io_mem[reg]); +} + +static void pluto_setsda(void *data, int state) +{ + struct pluto *pluto = data; + + if (state) + pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA); + else + pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0); +} + +static void pluto_setscl(void *data, int state) +{ + struct pluto *pluto = data; + + if (state) + pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL); + else + pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0); + + /* try to detect i2c_inb() to workaround hardware bug: + * reset SDA to high after SCL has been set to low */ + if ((state) && (pluto->i2cbug == 0)) { + pluto->i2cbug = 1; + } else { + if ((!state) && (pluto->i2cbug == 1)) + pluto_setsda(pluto, 1); + pluto->i2cbug = 0; + } +} + +static int pluto_getsda(void *data) +{ + struct pluto *pluto = data; + + return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA; +} + +static int pluto_getscl(void *data) +{ + struct pluto *pluto = data; + + return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL; +} + +static void pluto_reset_frontend(struct pluto *pluto, int reenable) +{ + u32 val = pluto_readreg(pluto, REG_MISC); + + if (val & MISC_FRST) { + val &= ~MISC_FRST; + pluto_writereg(pluto, REG_MISC, val); + } + if (reenable) { + val |= MISC_FRST; + pluto_writereg(pluto, REG_MISC, val); + } +} + +static void pluto_reset_ts(struct pluto *pluto, int reenable) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + if (val & TSCR_RSTN) { + val &= ~TSCR_RSTN; + pluto_writereg(pluto, REG_TSCR, val); + } + if (reenable) { + val |= TSCR_RSTN; + pluto_writereg(pluto, REG_TSCR, val); + } +} + +static void pluto_set_dma_addr(struct pluto *pluto) +{ + pluto_writereg(pluto, REG_PCAR, cpu_to_le32(pluto->dma_addr)); +} + +static int __devinit pluto_dma_map(struct pluto *pluto) +{ + pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + + return pci_dma_mapping_error(pluto->dma_addr); +} + +static void pluto_dma_unmap(struct pluto *pluto) +{ + pci_unmap_single(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); +} + +static int pluto_start_feed(struct dvb_demux_feed *f) +{ + struct pluto *pluto = feed_to_pluto(f); + + /* enable PID filtering */ + if (pluto->users++ == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0); + + if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) + pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid); + else if (pluto->full_ts_users++ == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL); + + return 0; +} + +static int pluto_stop_feed(struct dvb_demux_feed *f) +{ + struct pluto *pluto = feed_to_pluto(f); + + /* disable PID filtering */ + if (--pluto->users == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL); + + if ((f->pid < 0x2000) && (f->index < NHWFILTERS)) + pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff); + else if (--pluto->full_ts_users == 0) + pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0); + + return 0; +} + +static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) +{ + /* synchronize the DMA transfer with the CPU + * first so that we see updated contents. */ + pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); + + /* Workaround for broken hardware: + * [1] On startup NBPACKETS seems to contain an uninitialized value, + * but no packets have been transfered. + * [2] Sometimes (actually very often) NBPACKETS stays at zero + * although one packet has been transfered. + */ + if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) { + unsigned int i = 0, valid; + while (pluto->dma_buf[i] == 0x47) + i += 188; + valid = i / 188; + if (nbpackets != valid) { + dev_err(&pluto->pdev->dev, "nbpackets=%u valid=%u\n", + nbpackets, valid); + nbpackets = valid; + } + } + + dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets); + + /* clear the dma buffer. this is needed to be able to identify + * new valid ts packets above */ + memset(pluto->dma_buf, 0, nbpackets * 188); + + /* reset the dma address */ + pluto_set_dma_addr(pluto); + + /* sync the buffer and give it back to the card */ + pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr, + TS_DMA_BYTES, PCI_DMA_FROMDEVICE); +} + +static irqreturn_t pluto_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pluto *pluto = dev_id; + u32 tscr; + + /* check whether an interrupt occured on this device */ + tscr = pluto_readreg(pluto, REG_TSCR); + if (!(tscr & (TSCR_DE | TSCR_OVR))) + return IRQ_NONE; + + if (tscr == 0xffffffff) { + // FIXME: maybe recover somehow + dev_err(&pluto->pdev->dev, "card hung up :(\n"); + return IRQ_HANDLED; + } + + /* dma end interrupt */ + if (tscr & TSCR_DE) { + pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24); + /* overflow interrupt */ + if (tscr & TSCR_OVR) + pluto->overflow++; + if (pluto->overflow) { + dev_err(&pluto->pdev->dev, "overflow irq (%d)\n", + pluto->overflow); + pluto_reset_ts(pluto, 1); + pluto->overflow = 0; + } + } else if (tscr & TSCR_OVR) { + pluto->overflow++; + } + + /* ACK the interrupt */ + pluto_writereg(pluto, REG_TSCR, tscr | TSCR_IACK); + + return IRQ_HANDLED; +} + +static void __devinit pluto_enable_irqs(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + /* set the number of packets */ + val &= ~TSCR_ADEF; + val |= TS_DMA_PACKETS / 2; + /* disable AFUL and LOCK interrupts */ + val |= (TSCR_MSKA | TSCR_MSKL); + /* enable DMA and OVERFLOW interrupts */ + val &= ~(TSCR_DEM | TSCR_MSKO); + /* clear pending interrupts */ + val |= TSCR_IACK; + + pluto_writereg(pluto, REG_TSCR, val); +} + +static void pluto_disable_irqs(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_TSCR); + + /* disable all interrupts */ + val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL); + /* clear pending interrupts */ + val |= TSCR_IACK; + + pluto_writereg(pluto, REG_TSCR, val); +} + +static int __devinit pluto_hw_init(struct pluto *pluto) +{ + pluto_reset_frontend(pluto, 1); + + /* set automatic LED control by FPGA */ + pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED); + + /* set data endianess */ +#ifdef __LITTLE_ENDIAN + pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END); +#else + pluto_rw(pluto, REG_PIDn(0), PID0_END, 0); +#endif + /* map DMA and set address */ + pluto_dma_map(pluto); + pluto_set_dma_addr(pluto); + + /* enable interrupts */ + pluto_enable_irqs(pluto); + + /* reset TS logic */ + pluto_reset_ts(pluto, 1); + + return 0; +} + +static void pluto_hw_exit(struct pluto *pluto) +{ + /* disable interrupts */ + pluto_disable_irqs(pluto); + + pluto_reset_ts(pluto, 0); + + /* LED: disable automatic control, enable yellow, disable green */ + pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1); + + /* unmap DMA */ + pluto_dma_unmap(pluto); + + pluto_reset_frontend(pluto, 0); +} + +static inline u32 divide(u32 numerator, u32 denominator) +{ + if (denominator == 0) + return ~0; + + return (numerator + denominator / 2) / denominator; +} + +/* LG Innotek TDTE-E001P (Infineon TUA6034) */ +static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct pluto *pluto = frontend_to_pluto(fe); + struct i2c_msg msg; + int ret; + u8 buf[4]; + u32 div; + + // Fref = 166.667 Hz + // Fref * 3 = 500.000 Hz + // IF = 36166667 + // IF / Fref = 217 + //div = divide(p->frequency + 36166667, 166667); + div = divide(p->frequency * 3, 500000) + 217; + buf[0] = (div >> 8) & 0x7f; + buf[1] = (div >> 0) & 0xff; + + if (p->frequency < 611000000) + buf[2] = 0xb4; + else if (p->frequency < 811000000) + buf[2] = 0xbc; + else + buf[2] = 0xf4; + + // VHF: 174-230 MHz + // center: 350 MHz + // UHF: 470-862 MHz + if (p->frequency < 350000000) + buf[3] = 0x02; + else + buf[3] = 0x04; + + if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + buf[3] |= 0x08; + + if (sizeof(buf) == 6) { + buf[4] = buf[2]; + buf[4] &= ~0x1c; + buf[4] |= 0x18; + + buf[5] = (0 << 7) | (2 << 4); + } + + msg.addr = I2C_ADDR_TUA6034 >> 1; + msg.flags = 0; + msg.buf = buf; + msg.len = sizeof(buf); + + ret = i2c_transfer(&pluto->i2c_adap, &msg, 1); + if (ret < 0) + return ret; + else if (ret == 0) + return -EREMOTEIO; + + return 0; +} + +static int pluto2_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct pluto *pluto = frontend_to_pluto(fe); + + return request_firmware(fw, name, &pluto->pdev->dev); +} + +static struct tda1004x_config pluto2_fe_config __devinitdata = { + .demod_address = I2C_ADDR_TDA10046 >> 1, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .pll_set = lg_tdtpe001p_pll_set, + .pll_sleep = NULL, + .request_firmware = pluto2_request_firmware, +}; + +static int __devinit frontend_init(struct pluto *pluto) +{ + int ret; + + pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap); + if (!pluto->fe) { + dev_err(&pluto->pdev->dev, "could not attach frontend\n"); + return -ENODEV; + } + + ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe); + if (ret < 0) { + if (pluto->fe->ops->release) + pluto->fe->ops->release(pluto->fe); + return ret; + } + + return 0; +} + +static void __devinit pluto_read_rev(struct pluto *pluto) +{ + u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR; + dev_info(&pluto->pdev->dev, "board revision %d.%d\n", + (val >> 12) & 0x0f, (val >> 4) & 0xff); +} + +static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac) +{ + u32 val = pluto_readreg(pluto, REG_MMAC); + mac[0] = (val >> 8) & 0xff; + mac[1] = (val >> 0) & 0xff; + + val = pluto_readreg(pluto, REG_IMAC); + mac[2] = (val >> 8) & 0xff; + mac[3] = (val >> 0) & 0xff; + + val = pluto_readreg(pluto, REG_LMAC); + mac[4] = (val >> 8) & 0xff; + mac[5] = (val >> 0) & 0xff; + + dev_info(&pluto->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +static int __devinit pluto_read_serial(struct pluto *pluto) +{ + struct pci_dev *pdev = pluto->pdev; + unsigned int i, j; + u8 __iomem *cis; + + cis = pci_iomap(pdev, 1, 0); + if (!cis) + return -EIO; + + dev_info(&pdev->dev, "S/N "); + + for (i = 0xe0; i < 0x100; i += 4) { + u32 val = readl(&cis[i]); + for (j = 0; j < 32; j += 8) { + if ((val & 0xff) == 0xff) + goto out; + printk("%c", val & 0xff); + val >>= 8; + } + } +out: + printk("\n"); + pci_iounmap(pdev, cis); + + return 0; +} + +static int __devinit pluto2_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct pluto *pluto; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret = -ENOMEM; + + pluto = kmalloc(sizeof(struct pluto), GFP_KERNEL); + if (!pluto) + goto out; + + memset(pluto, 0, sizeof(struct pluto)); + pluto->pdev = pdev; + + ret = pci_enable_device(pdev); + if (ret < 0) + goto err_kfree; + + /* enable interrupts */ + pci_write_config_dword(pdev, 0x6c, 0x8000); + + ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (ret < 0) + goto err_pci_disable_device; + + pci_set_master(pdev); + + ret = pci_request_regions(pdev, DRIVER_NAME); + if (ret < 0) + goto err_pci_disable_device; + + pluto->io_mem = pci_iomap(pdev, 0, 0x40); + if (!pluto->io_mem) { + ret = -EIO; + goto err_pci_release_regions; + } + + pci_set_drvdata(pdev, pluto); + + ret = request_irq(pdev->irq, pluto_irq, SA_SHIRQ, DRIVER_NAME, pluto); + if (ret < 0) + goto err_pci_iounmap; + + ret = pluto_hw_init(pluto); + if (ret < 0) + goto err_free_irq; + + /* i2c */ + i2c_set_adapdata(&pluto->i2c_adap, pluto); + strcpy(pluto->i2c_adap.name, DRIVER_NAME); + pluto->i2c_adap.owner = THIS_MODULE; + pluto->i2c_adap.id = I2C_ALGO_BIT; + pluto->i2c_adap.class = I2C_CLASS_TV_DIGITAL; + pluto->i2c_adap.dev.parent = &pdev->dev; + pluto->i2c_adap.algo_data = &pluto->i2c_bit; + pluto->i2c_bit.data = pluto; + pluto->i2c_bit.setsda = pluto_setsda; + pluto->i2c_bit.setscl = pluto_setscl; + pluto->i2c_bit.getsda = pluto_getsda; + pluto->i2c_bit.getscl = pluto_getscl; + pluto->i2c_bit.udelay = 10; + pluto->i2c_bit.timeout = 10; + + /* Raise SCL and SDA */ + pluto_setsda(pluto, 1); + pluto_setscl(pluto, 1); + + ret = i2c_bit_add_bus(&pluto->i2c_adap); + if (ret < 0) + goto err_pluto_hw_exit; + + /* dvb */ + ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE); + if (ret < 0) + goto err_i2c_bit_del_bus; + + dvb_adapter = &pluto->dvb_adapter; + + pluto_read_rev(pluto); + pluto_read_serial(pluto); + pluto_read_mac(pluto, dvb_adapter->proposed_mac); + + dvbdemux = &pluto->demux; + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = pluto_start_feed; + dvbdemux->stop_feed = pluto_stop_feed; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) + goto err_dvb_unregister_adapter; + + dmx = &dvbdemux->dmx; + + pluto->hw_frontend.source = DMX_FRONTEND_0; + pluto->mem_frontend.source = DMX_MEMORY_FE; + pluto->dmxdev.filternum = NHWFILTERS; + pluto->dmxdev.demux = dmx; + + ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter); + if (ret < 0) + goto err_dvb_dmx_release; + + ret = dmx->add_frontend(dmx, &pluto->hw_frontend); + if (ret < 0) + goto err_dvb_dmxdev_release; + + ret = dmx->add_frontend(dmx, &pluto->mem_frontend); + if (ret < 0) + goto err_remove_hw_frontend; + + ret = dmx->connect_frontend(dmx, &pluto->hw_frontend); + if (ret < 0) + goto err_remove_mem_frontend; + + ret = frontend_init(pluto); + if (ret < 0) + goto err_disconnect_frontend; + + dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx); +out: + return ret; + +err_disconnect_frontend: + dmx->disconnect_frontend(dmx); +err_remove_mem_frontend: + dmx->remove_frontend(dmx, &pluto->mem_frontend); +err_remove_hw_frontend: + dmx->remove_frontend(dmx, &pluto->hw_frontend); +err_dvb_dmxdev_release: + dvb_dmxdev_release(&pluto->dmxdev); +err_dvb_dmx_release: + dvb_dmx_release(dvbdemux); +err_dvb_unregister_adapter: + dvb_unregister_adapter(dvb_adapter); +err_i2c_bit_del_bus: + i2c_bit_del_bus(&pluto->i2c_adap); +err_pluto_hw_exit: + pluto_hw_exit(pluto); +err_free_irq: + free_irq(pdev->irq, pluto); +err_pci_iounmap: + pci_iounmap(pdev, pluto->io_mem); +err_pci_release_regions: + pci_release_regions(pdev); +err_pci_disable_device: + pci_disable_device(pdev); +err_kfree: + pci_set_drvdata(pdev, NULL); + kfree(pluto); + goto out; +} + +static void __devexit pluto2_remove(struct pci_dev *pdev) +{ + struct pluto *pluto = pci_get_drvdata(pdev); + struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter; + struct dvb_demux *dvbdemux = &pluto->demux; + struct dmx_demux *dmx = &dvbdemux->dmx; + + dmx->close(dmx); + dvb_net_release(&pluto->dvbnet); + if (pluto->fe) + dvb_unregister_frontend(pluto->fe); + + dmx->disconnect_frontend(dmx); + dmx->remove_frontend(dmx, &pluto->mem_frontend); + dmx->remove_frontend(dmx, &pluto->hw_frontend); + dvb_dmxdev_release(&pluto->dmxdev); + dvb_dmx_release(dvbdemux); + dvb_unregister_adapter(dvb_adapter); + i2c_bit_del_bus(&pluto->i2c_adap); + pluto_hw_exit(pluto); + free_irq(pdev->irq, pluto); + pci_iounmap(pdev, pluto->io_mem); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + kfree(pluto); +} + +#ifndef PCI_VENDOR_ID_SCM +#define PCI_VENDOR_ID_SCM 0x0432 +#endif +#ifndef PCI_DEVICE_ID_PLUTO2 +#define PCI_DEVICE_ID_PLUTO2 0x0001 +#endif + +static struct pci_device_id pluto2_id_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_SCM, + .device = PCI_DEVICE_ID_PLUTO2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { + /* empty */ + }, +}; + +MODULE_DEVICE_TABLE(pci, pluto2_id_table); + +static struct pci_driver pluto2_driver = { + .name = DRIVER_NAME, + .id_table = pluto2_id_table, + .probe = pluto2_probe, + .remove = __devexit_p(pluto2_remove), +}; + +static int __init pluto2_init(void) +{ + return pci_register_driver(&pluto2_driver); +} + +static void __exit pluto2_exit(void) +{ + pci_unregister_driver(&pluto2_driver); +} + +module_init(pluto2_init); +module_exit(pluto2_exit); + +MODULE_AUTHOR("Andreas Oberritter "); +MODULE_DESCRIPTION("Pluto2 driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 178c6efcd8435644028bf3f079c1e82107e72dfd Mon Sep 17 00:00:00 2001 From: Christophe Lucas Date: Thu, 7 Jul 2005 17:57:47 -0700 Subject: [PATCH] dvb: saa7146: kj pci_module_init cleanup http://kerneljanitors.org/TODO - convert from pci_module_init to pci_register_driver Signed-off-by: Christophe Lucas Signed-off-by: Domen Puncer Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/common/saa7146_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 50e8b865401..77ff2291156 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -512,7 +512,7 @@ int saa7146_register_extension(struct saa7146_extension* ext) ext->driver.remove = saa7146_remove_one; printk("saa7146: register extension '%s'.\n",ext->name); - return pci_module_init(&ext->driver); + return pci_register_driver(&ext->driver); } int saa7146_unregister_extension(struct saa7146_extension* ext) -- cgit v1.2.3 From 2819639b5630cd26d399ee0481be9a752280cf4d Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:57:48 -0700 Subject: [PATCH] dvb: flexcop: add big endian register definitions Add big-endian register definitions for running on a PowerPC. (Thanks to Paavo Hartikainen for testing.) Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-reg.h | 548 +------------------------- drivers/media/dvb/b2c2/flexcop_ibi_value_be.h | 451 +++++++++++++++++++++ drivers/media/dvb/b2c2/flexcop_ibi_value_le.h | 451 +++++++++++++++++++++ 3 files changed, 909 insertions(+), 541 deletions(-) create mode 100644 drivers/media/dvb/b2c2/flexcop_ibi_value_be.h create mode 100644 drivers/media/dvb/b2c2/flexcop_ibi_value_le.h (limited to 'drivers') diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h index 75b50f21afe..4ae1eb5bfe9 100644 --- a/drivers/media/dvb/b2c2/flexcop-reg.h +++ b/drivers/media/dvb/b2c2/flexcop-reg.h @@ -36,555 +36,21 @@ typedef enum { extern const char *flexcop_device_names[]; /* FlexCop IBI Registers */ +#if defined(__LITTLE_ENDIAN) + #include "flexcop_ibi_value_le.h" +#elif defined(__BIG_ENDIAN) + #include "flexcop_ibi_value_be.h" +#else + #error no endian defined +#endif -/* flexcop_ibi_reg - a huge union representing the register structure */ -typedef union { - u32 raw; - -/* DMA 0x000 to 0x01c - * DMA1 0x000 to 0x00c - * DMA2 0x010 to 0x01c - */ - struct { - u32 dma_0start : 1; /* set: data will be delivered to dma1_address0 */ - u32 dma_0No_update : 1; /* set: dma1_cur_address will be updated, unset: no update */ - u32 dma_address0 :30; /* physical/virtual host memory address0 DMA */ - } dma_0x0; - - struct { - u32 DMA_maxpackets : 8; /* (remapped) PCI DMA1 Packet Count Interrupt. This variable - is able to be read and written while bit(1) of register - 0x00c (remap_enable) is set. This variable represents - the number of packets that will be transmitted to the PCI - host using PCI DMA1 before an interrupt to the PCI is - asserted. This functionality may be enabled using bit(20) - of register 0x208. N=0 disables the IRQ. */ - u32 dma_addr_size :24; /* size of memory buffer in DWORDs (bytesize / 4) for DMA */ - } dma_0x4_remap; - - struct { - u32 dma1timer : 7; /* reading PCI DMA1 timer ... when remap_enable is 0 */ - u32 unused : 1; - u32 dma_addr_size :24; - } dma_0x4_read; - - struct { - u32 unused : 1; - u32 dmatimer : 7; /* writing PCI DMA1 timer ... when remap_enable is 0 */ - u32 dma_addr_size :24; - } dma_0x4_write; - - struct { - u32 unused : 2; - u32 dma_cur_addr :30; /* current physical host memory address pointer for DMA */ - } dma_0x8; - - struct { - u32 dma_1start : 1; /* set: data will be delivered to dma_address1, when dma_address0 is full */ - u32 remap_enable : 1; /* remap enable for 0x0x4(7:0) */ - u32 dma_address1 :30; /* Physical/virtual address 1 on DMA */ - } dma_0xc; - -/* Two-wire Serial Master and Clock 0x100-0x110 */ - struct { -// u32 slave_transmitter : 1; /* ???*/ - u32 chipaddr : 7; /* two-line serial address of the target slave */ - u32 reserved1 : 1; - u32 baseaddr : 8; /* address of the location of the read/write operation */ - u32 data1_reg : 8; /* first byte in two-line serial read/write operation */ - u32 working_start : 1; /* when doing a write operation this indicator is 0 when ready - * set to 1 when doing a write operation */ - u32 twoWS_rw : 1; /* read/write indicator (1 = read, 0 write) */ - u32 total_bytes : 2; /* number of data bytes in each two-line serial transaction (0 = 1 byte, 11 = 4byte)*/ - u32 twoWS_port_reg : 2; /* port selection: 01 - Front End/Demod, 10 - EEPROM, 11 - Tuner */ - u32 no_base_addr_ack_error : 1; /* writing: write-req: frame is produced w/o baseaddr, read-req: read-cycles w/o - * preceding address assignment write frame - * ACK_ERROR = 1 when no ACK from slave in the last transaction */ - u32 st_done : 1; /* indicator for transaction is done */ - } tw_sm_c_100; - - struct { - u32 data2_reg : 8; /* 2nd data byte */ - u32 data3_reg : 8; /* 3rd data byte */ - u32 data4_reg : 8; /* 4th data byte */ - u32 exlicit_stops : 1; /* when set, transactions are produced w/o trailing STOP flag, then send isolated STOP flags */ - u32 force_stop : 1; /* isolated stop flag */ - u32 unused : 6; - } tw_sm_c_104; - -/* Clock. The register allows the FCIII to convert an incoming Master clock - * (MCLK) signal into a lower frequency clock through the use of a LowCounter - * (TLO) and a High- Counter (THI). The time counts for THI and TLO are - * measured in MCLK; each count represents 4 MCLK input clock cycles. - * - * The default output for port #1 is set for Front End Demod communication. (0x108) - * The default output for port #2 is set for EEPROM communication. (0x10c) - * The default output for port #3 is set for Tuner communication. (0x110) - */ - struct { - u32 thi1 : 6; /* Thi for port #1 (def: 100110b; 38) */ - u32 reserved1 : 2; - u32 tlo1 : 5; /* Tlo for port #1 (def: 11100b; 28) */ - u32 reserved2 :19; - } tw_sm_c_108; - - struct { - u32 thi1 : 6; /* Thi for port #2 (def: 111001b; 57) */ - u32 reserved1 : 2; - u32 tlo1 : 5; /* Tlo for port #2 (def: 11100b; 28) */ - u32 reserved2 :19; - } tw_sm_c_10c; - - struct { - u32 thi1 : 6; /* Thi for port #3 (def: 111001b; 57) */ - u32 reserved1 : 2; - u32 tlo1 : 5; /* Tlo for port #3 (def: 11100b; 28) */ - u32 reserved2 :19; - } tw_sm_c_110; - -/* LNB Switch Frequency 0x200 - * Clock that creates the LNB switch tone. The default is set to have a fixed - * low output (not oscillating) to the LNB_CTL line. - */ - struct { - u32 LNB_CTLHighCount_sig :15; /* It is the number of pre-scaled clock cycles that will be low. */ - u32 LNB_CTLLowCount_sig :15; /* For example, to obtain a 22KHz output given a 45 Mhz Master - Clock signal (MCLK), set PreScalar=01 and LowCounter value to 0x1ff. */ - u32 LNB_CTLPrescaler_sig : 2; /* pre-scaler divides MCLK: 00 (no division), 01 by 2, 10 by 4, 11 by 12 */ - } lnb_switch_freq_200; - -/* ACPI, Peripheral Reset, LNB Polarity - * ACPI power conservation mode, LNB polarity selection (low or high voltage), - * and peripheral reset. - */ - struct { - u32 ACPI1_sig : 1; /* turn of the power of tuner and LNB, not implemented in FCIII */ - u32 ACPI3_sig : 1; /* turn of power of the complete satelite receiver board (except FCIII) */ - u32 LNB_L_H_sig : 1; /* low or high voltage for LNB. (0 = low, 1 = high) */ - u32 Per_reset_sig : 1; /* misc. init reset (default: 1), to reset set to low and back to high */ - u32 reserved :20; - u32 Rev_N_sig_revision_hi : 4;/* 0xc in case of FCIII */ - u32 Rev_N_sig_reserved1 : 2; - u32 Rev_N_sig_caps : 1; /* if 1, FCIII has 32 PID- and MAC-filters and is capable of IP multicast */ - u32 Rev_N_sig_reserved2 : 1; - } misc_204; - -/* Control and Status 0x208 to 0x21c */ -/* Gross enable and disable control */ - struct { - u32 Stream1_filter_sig : 1; /* Stream1 PID filtering */ - u32 Stream2_filter_sig : 1; /* Stream2 PID filtering */ - u32 PCR_filter_sig : 1; /* PCR PID filter */ - u32 PMT_filter_sig : 1; /* PMT PID filter */ - - u32 EMM_filter_sig : 1; /* EMM PID filter */ - u32 ECM_filter_sig : 1; /* ECM PID filter */ - u32 Null_filter_sig : 1; /* Filters null packets, PID=0x1fff. */ - u32 Mask_filter_sig : 1; /* mask PID filter */ - - u32 WAN_Enable_sig : 1; /* WAN output line through V8 memory space is activated. */ - u32 WAN_CA_Enable_sig : 1; /* not in FCIII */ - u32 CA_Enable_sig : 1; /* not in FCIII */ - u32 SMC_Enable_sig : 1; /* CI stream data (CAI) goes directly to the smart card intf (opposed IBI 0x600 or SC-cmd buf). */ - - u32 Per_CA_Enable_sig : 1; /* not in FCIII */ - u32 Multi2_Enable_sig : 1; /* ? */ - u32 MAC_filter_Mode_sig : 1; /* (MAC_filter_enable) Globally enables MAC filters for Net PID filteres. */ - u32 Rcv_Data_sig : 1; /* PID filtering module enable. When this bit is a one, the PID filter will - examine and process packets according to all other (individual) PID - filtering controls. If it a zero, no packet processing of any kind will - take place. All data from the tuner will be thrown away. */ - - u32 DMA1_IRQ_Enable_sig : 1; /* When set, a DWORD counter is enabled on PCI DMA1 that asserts the PCI - * interrupt after the specified count for filling the buffer. */ - u32 DMA1_Timer_Enable_sig : 1; /* When set, a timer is enabled on PCI DMA1 that asserts the PCI interrupt - after a specified amount of time. */ - u32 DMA2_IRQ_Enable_sig : 1; /* same as DMA1_IRQ_Enable_sig but for DMA2 */ - u32 DMA2_Timer_Enable_sig : 1; /* same as DMA1_Timer_Enable_sig but for DMA2 */ - - u32 DMA1_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA1 that asserts the PCI interrupt. */ - u32 DMA2_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA2 that asserts the PCI interrupt. */ - u32 Mailbox_from_V8_Enable_sig: 1; /* When set, writes to the mailbox register produce an interrupt to the - PCI host to indicate that mailbox data is available. */ - - u32 unused : 9; - } ctrl_208; - -/* General status. When a PCI interrupt occurs, this register is read to - * discover the reason for the interrupt. - */ - struct { - u32 DMA1_IRQ_Status : 1; /* When set(1) the DMA1 counter had generated an IRQ. Read Only. */ - u32 DMA1_Timer_Status : 1; /* When set(1) the DMA1 timer had generated an IRQ. Read Only. */ - u32 DMA2_IRQ_Status : 1; /* When set(1) the DMA2 counter had generated an IRQ. Read Only. */ - u32 DMA2_Timer_Status : 1; /* When set(1) the DMA2 timer had generated an IRQ. Read Only. */ - u32 DMA1_Size_IRQ_Status : 1; /* (Read only). This register is read after an interrupt to */ - u32 DMA2_Size_IRQ_Status : 1; /* find out why we had an IRQ. Reading this register will clear this bit. Packet count*/ - u32 Mailbox_from_V8_Status_sig: 1; /* Same as above. Reading this register will clear this bit. */ - u32 Data_receiver_error : 1; /* 1 indicate an error in the receiver Front End (Tuner module) */ - u32 Continuity_error_flag : 1; /* 1 indicates a continuity error in the TS stream. */ - u32 LLC_SNAP_FLAG_set : 1; /* 1 indicates that the LCC_SNAP_FLAG was set. */ - u32 Transport_Error : 1; /* When set indicates that an unexpected packet was received. */ - u32 reserved :21; - } irq_20c; - - -/* Software reset register */ - struct { - u32 reset_blocks : 8; /* Enabled when Block_reset_enable = 0xB2 and 0x208 bits 15:8 = 0x00. - Each bit location represents a 0x100 block of registers. Writing - a one in a bit location resets that block of registers and the logic - that it controls. */ - u32 Block_reset_enable : 8; /* This variable is set to 0xB2 when the register is written. */ - u32 Special_controls :16; /* Asserts Reset_V8 => 0xC258; Turns on pci encryption => 0xC25A; - Turns off pci encryption => 0xC259 Note: pci_encryption default - at power-up is ON. */ - } sw_reset_210; - - struct { - u32 vuart_oe_sig : 1; /* When clear, the V8 processor has sole control of the serial UART - (RS-232 Smart Card interface). When set, the IBI interface - defined by register 0x600 controls the serial UART. */ - u32 v2WS_oe_sig : 1; /* When clear, the V8 processor has direct control of the Two-line - Serial Master EEPROM target. When set, the Two-line Serial Master - EEPROM target interface is controlled by IBI register 0x100. */ - u32 halt_V8_sig : 1; /* When set, contiguous wait states are applied to the V8-space - bus masters. Once this signal is cleared, normal V8-space - operations resume. */ - u32 section_pkg_enable_sig: 1; /* When set, this signal enables the front end translation circuitry - to process section packed transport streams. */ - u32 s2p_sel_sig : 1; /* Serial to parallel conversion. When set, polarized transport data - within the FlexCop3 front end circuitry is converted from a serial - stream into parallel data before downstream processing otherwise - interprets the data. */ - u32 unused1 : 3; - u32 polarity_PS_CLK_sig: 1; /* This signal is used to invert the input polarity of the tranport - stream CLOCK signal before any processing occurs on the transport - stream within FlexCop3. */ - u32 polarity_PS_VALID_sig: 1; /* This signal is used to invert the input polarity of the tranport - stream VALID signal before any processing occurs on the transport - stream within FlexCop3. */ - u32 polarity_PS_SYNC_sig: 1; /* This signal is used to invert the input polarity of the tranport - stream SYNC signal before any processing occurs on the transport - stream within FlexCop3. */ - u32 polarity_PS_ERR_sig: 1; /* This signal is used to invert the input polarity of the tranport - stream ERROR signal before any processing occurs on the transport - stream within FlexCop3. */ - u32 unused2 :20; - } misc_214; - -/* Mailbox from V8 to host */ - struct { - u32 Mailbox_from_V8 :32; /* When this register is written by either the V8 processor or by an - end host, an interrupt is generated to the PCI host to indicate - that mailbox data is available. Reading register 20c will clear - the IRQ. */ - } mbox_v8_to_host_218; - -/* Mailbox from host to v8 Mailbox_to_V8 - * Mailbox_to_V8 mailbox storage register - * used to send messages from PCI to V8. Writing to this register will send an - * IRQ to the V8. Then it can read the data from here. Reading this register - * will clear the IRQ. If the V8 is halted and bit 31 of this register is set, - * then this register is used instead as a direct interface to access the - * V8space memory. - */ - struct { - u32 sysramaccess_data : 8; /* Data byte written or read from the specified address in V8 SysRAM. */ - u32 sysramaccess_addr :15; /* 15 bit address used to access V8 Sys-RAM. */ - u32 unused : 7; - u32 sysramaccess_write: 1; /* Write flag used to latch data into the V8 SysRAM. */ - u32 sysramaccess_busmuster: 1; /* Setting this bit when the V8 is halted at 0x214 Bit(2) allows - this IBI register interface to directly drive the V8-space memory. */ - } mbox_host_to_v8_21c; - - -/* PIDs, Translation Bit, SMC Filter Select 0x300 to 0x31c */ - struct { - u32 Stream1_PID :13; /* Primary use is receiving Net data, so these 13 bits normally - hold the PID value for the desired network stream. */ - u32 Stream1_trans : 1; /* When set, Net translation will take place for Net data ferried in TS packets. */ - u32 MAC_Multicast_filter : 1; /* When clear, multicast MAC filtering is not allowed for Stream1 and PID_n filters. */ - u32 debug_flag_pid_saved : 1; - u32 Stream2_PID :13; /* 13 bits for Stream 2 PID filter value. General use. */ - u32 Stream2_trans : 1; /* When set Tables/CAI translation will take place for the data ferried in - Stream2_PID TS packets. */ - u32 debug_flag_write_status00 : 1; - u32 debug_fifo_problem : 1; - } pid_filter_300; - - struct { - u32 PCR_PID :13; /* PCR stream PID filter value. Primary use is Program Clock Reference stream filtering. */ - u32 PCR_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ - u32 debug_overrun3 : 1; - u32 debug_overrun2 : 1; - u32 PMT_PID :13; /* stream PID filter value. Primary use is Program Management Table segment filtering. */ - u32 PMT_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ - u32 reserved : 2; - } pid_filter_304; - - struct { - u32 EMM_PID :13; /* EMM PID filter value. Primary use is Entitlement Management Messaging for - conditional access-related data. */ - u32 EMM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ - u32 EMM_filter_4 : 1; /* When set will pass only EMM data possessing the same ID code as the - first four bytes (32 bits) of the end-user s 6-byte Smart Card ID number Select */ - u32 EMM_filter_6 : 1; /* When set will pass only EMM data possessing the same 6-byte code as the end-users - complete 6-byte Smart Card ID number. */ - u32 ECM_PID :13; /* ECM PID filter value. Primary use is Entitlement Control Messaging for conditional - access-related data. */ - u32 ECM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ - u32 reserved : 2; - } pid_filter_308; - - struct { - u32 Group_PID :13; /* PID value for group filtering. */ - u32 Group_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ - u32 unused1 : 2; - u32 Group_mask :13; /* Mask value used in logical "and" equation that defines group filtering */ - u32 unused2 : 3; - } pid_filter_30c_ext_ind_0_7; - - struct { - u32 net_master_read :17; - u32 unused :15; - } pid_filter_30c_ext_ind_1; - - struct { - u32 net_master_write :17; - u32 unused :15; - } pid_filter_30c_ext_ind_2; - - struct { - u32 next_net_master_write :17; - u32 unused :15; - } pid_filter_30c_ext_ind_3; - - struct { - u32 unused1 : 1; - u32 state_write :10; - u32 reserved1 : 6; /* default: 000100 */ - u32 stack_read :10; - u32 reserved2 : 5; /* default: 00100 */ - } pid_filter_30c_ext_ind_4; - - struct { - u32 stack_cnt :10; - u32 unused :22; - } pid_filter_30c_ext_ind_5; - - struct { - u32 pid_fsm_save_reg0 : 2; - u32 pid_fsm_save_reg1 : 2; - u32 pid_fsm_save_reg2 : 2; - u32 pid_fsm_save_reg3 : 2; - u32 pid_fsm_save_reg4 : 2; - u32 pid_fsm_save_reg300 : 2; - u32 write_status1 : 2; - u32 write_status4 : 2; - u32 data_size_reg :12; - u32 unused : 4; - } pid_filter_30c_ext_ind_6; - - struct { - u32 index_reg : 5; /* (Index pointer) Points at an internal PIDn register. A binary code - representing one of 32 internal PIDn registers as well as its - corresponding internal MAC_lown register. */ - u32 extra_index_reg : 3; /* This vector is used to select between sets of debug signals routed to register 0x30c. */ - u32 AB_select : 1; /* Used in conjunction with 0x31c. read/write to the MAC_highA or MAC_highB register - 0=MAC_highB register, 1=MAC_highA */ - u32 pass_alltables : 1; /* 1=Net packets are not filtered against the Network Table ID found in register 0x400. - All types of networks (DVB, ATSC, ISDB) are passed. */ - u32 unused :22; - } index_reg_310; - - struct { - u32 PID :13; /* PID value */ - u32 PID_trans : 1; /* translation will take place for packets filtered */ - u32 PID_enable_bit : 1; /* When set this PID filter is enabled */ - u32 reserved :17; - } pid_n_reg_314; - - struct { - u32 A4_byte : 8; - u32 A5_byte : 8; - u32 A6_byte : 8; - u32 Enable_bit : 1; /* enabled (1) or disabled (1) */ - u32 HighAB_bit : 1; /* use MAC_highA (1) or MAC_highB (0) as MSB */ - u32 reserved : 6; - } mac_low_reg_318; - - struct { - u32 A1_byte : 8; - u32 A2_byte : 8; - u32 A3_byte : 8; - u32 reserved : 8; - } mac_high_reg_31c; - -/* Table, SMCID,MACDestination Filters 0x400 to 0x41c */ - struct { - u32 reserved :16; #define fc_data_Tag_ID_DVB 0x3e #define fc_data_Tag_ID_ATSC 0x3f #define fc_data_Tag_ID_IDSB 0x8b - u32 data_Tag_ID :16; - } data_tag_400; - - struct { - u32 Card_IDbyte6 : 8; - u32 Card_IDbyte5 : 8; - u32 Card_IDbyte4 : 8; - u32 Card_IDbyte3 : 8; - } card_id_408; - - struct { - u32 Card_IDbyte2 : 8; - u32 Card_IDbyte1 : 8; - } card_id_40c; - - /* holding the unique mac address of the receiver which houses the FlexCopIII */ - struct { - u32 MAC1 : 8; - u32 MAC2 : 8; - u32 MAC3 : 8; - u32 MAC6 : 8; - } mac_address_418; - - struct { - u32 MAC7 : 8; - u32 MAC8 : 8; - u32 reserved : 16; - } mac_address_41c; - - struct { - u32 transmitter_data_byte : 8; - u32 ReceiveDataReady : 1; - u32 ReceiveByteFrameError: 1; - u32 txbuffempty : 1; - u32 reserved :21; - } ci_600; - - struct { - u32 pi_d : 8; - u32 pi_ha :20; - u32 pi_rw : 1; - u32 pi_component_reg : 3; - } pi_604; - - struct { - u32 serialReset : 1; - u32 oncecycle_read : 1; - u32 Timer_Read_req : 1; - u32 Timer_Load_req : 1; - u32 timer_data : 7; - u32 unused : 1; /* ??? not mentioned in data book */ - u32 Timer_addr : 5; - u32 reserved : 3; - u32 pcmcia_a_mod_pwr_n : 1; - u32 pcmcia_b_mod_pwr_n : 1; - u32 config_Done_stat : 1; - u32 config_Init_stat : 1; - u32 config_Prog_n : 1; - u32 config_wr_n : 1; - u32 config_cs_n : 1; - u32 config_cclk : 1; - u32 pi_CiMax_IRQ_n : 1; - u32 pi_timeout_status : 1; - u32 pi_wait_n : 1; - u32 pi_busy_n : 1; - } pi_608; - struct { - u32 PID :13; - u32 key_enable : 1; #define fc_key_code_default 0x1 #define fc_key_code_even 0x2 #define fc_key_code_odd 0x3 - u32 key_code : 2; - u32 key_array_col : 3; - u32 key_array_row : 5; - u32 dvb_en : 1; /* 0=TS bypasses the Descrambler */ - u32 rw_flag : 1; - u32 reserved : 6; - } dvb_reg_60c; - -/* SRAM and Output Destination 0x700 to 0x714 */ - struct { - u32 sram_addr :15; - u32 sram_rw : 1; /* 0=write, 1=read */ - u32 sram_data : 8; - u32 sc_xfer_bit : 1; - u32 reserved1 : 3; - u32 oe_pin_reg : 1; - u32 ce_pin_reg : 1; - u32 reserved2 : 1; - u32 start_sram_ibi : 1; - } sram_ctrl_reg_700; - - struct { - u32 net_addr_read :16; - u32 net_addr_write :16; - } net_buf_reg_704; - - struct { - u32 cai_read :11; - u32 reserved1 : 5; - u32 cai_write :11; - u32 reserved2 : 6; - u32 cai_cnt : 4; - } cai_buf_reg_708; - - struct { - u32 cao_read :11; - u32 reserved1 : 5; - u32 cap_write :11; - u32 reserved2 : 6; - u32 cao_cnt : 4; - } cao_buf_reg_70c; - - struct { - u32 media_read :11; - u32 reserved1 : 5; - u32 media_write :11; - u32 reserved2 : 6; - u32 media_cnt : 4; - } media_buf_reg_710; - - struct { - u32 NET_Dest : 2; - u32 CAI_Dest : 2; - u32 CAO_Dest : 2; - u32 MEDIA_Dest : 2; - u32 net_ovflow_error : 1; - u32 media_ovflow_error : 1; - u32 cai_ovflow_error : 1; - u32 cao_ovflow_error : 1; - u32 ctrl_usb_wan : 1; - u32 ctrl_sramdma : 1; - u32 ctrl_maximumfill : 1; - u32 reserved :17; - } sram_dest_reg_714; - - struct { - u32 net_cnt :12; - u32 reserved1 : 4; - u32 net_addr_read : 1; - u32 reserved2 : 3; - u32 net_addr_write : 1; - u32 reserved3 :11; - } net_buf_reg_718; - - struct { - u32 wan_speed_sig : 2; - u32 reserved1 : 6; - u32 wan_wait_state : 8; - u32 sram_chip : 2; - u32 sram_memmap : 2; - u32 reserved2 : 4; - u32 wan_pkt_frame : 4; - u32 reserved3 : 4; - } wan_ctrl_reg_71c; -} flexcop_ibi_value; extern flexcop_ibi_value ibi_zero; diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h new file mode 100644 index 00000000000..bf3cb5a71fb --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h @@ -0,0 +1,451 @@ +/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * register descriptions + * + * see flexcop.c for copyright information. + */ + +/* This file is automatically generated, do not edit things here. */ +#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ +#define __FLEXCOP_IBI_VALUE_INCLUDED__ + +typedef union { + u32 raw; + + struct { + u32 dma_address0 :30; + u32 dma_0No_update : 1; + u32 dma_0start : 1; + } dma_0x0; + + struct { + u32 dma_addr_size :24; + u32 DMA_maxpackets : 8; + } dma_0x4_remap; + + struct { + u32 dma_addr_size :24; + u32 unused : 1; + u32 dma1timer : 7; + } dma_0x4_read; + + struct { + u32 dma_addr_size :24; + u32 dmatimer : 7; + u32 unused : 1; + } dma_0x4_write; + + struct { + u32 dma_cur_addr :30; + u32 unused : 2; + } dma_0x8; + + struct { + u32 dma_address1 :30; + u32 remap_enable : 1; + u32 dma_1start : 1; + } dma_0xc; + + struct { + u32 st_done : 1; + u32 no_base_addr_ack_error : 1; + u32 twoWS_port_reg : 2; + u32 total_bytes : 2; + u32 twoWS_rw : 1; + u32 working_start : 1; + u32 data1_reg : 8; + u32 baseaddr : 8; + u32 reserved1 : 1; + u32 chipaddr : 7; + } tw_sm_c_100; + + struct { + u32 unused : 6; + u32 force_stop : 1; + u32 exlicit_stops : 1; + u32 data4_reg : 8; + u32 data3_reg : 8; + u32 data2_reg : 8; + } tw_sm_c_104; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_108; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_10c; + + struct { + u32 reserved2 :19; + u32 tlo1 : 5; + u32 reserved1 : 2; + u32 thi1 : 6; + } tw_sm_c_110; + + struct { + u32 LNB_CTLPrescaler_sig : 2; + u32 LNB_CTLLowCount_sig :15; + u32 LNB_CTLHighCount_sig :15; + } lnb_switch_freq_200; + + struct { + u32 Rev_N_sig_reserved2 : 1; + u32 Rev_N_sig_caps : 1; + u32 Rev_N_sig_reserved1 : 2; + u32 Rev_N_sig_revision_hi : 4; + u32 reserved :20; + u32 Per_reset_sig : 1; + u32 LNB_L_H_sig : 1; + u32 ACPI3_sig : 1; + u32 ACPI1_sig : 1; + } misc_204; + + struct { + u32 unused : 9; + u32 Mailbox_from_V8_Enable_sig : 1; + u32 DMA2_Size_IRQ_Enable_sig : 1; + u32 DMA1_Size_IRQ_Enable_sig : 1; + u32 DMA2_Timer_Enable_sig : 1; + u32 DMA2_IRQ_Enable_sig : 1; + u32 DMA1_Timer_Enable_sig : 1; + u32 DMA1_IRQ_Enable_sig : 1; + u32 Rcv_Data_sig : 1; + u32 MAC_filter_Mode_sig : 1; + u32 Multi2_Enable_sig : 1; + u32 Per_CA_Enable_sig : 1; + u32 SMC_Enable_sig : 1; + u32 CA_Enable_sig : 1; + u32 WAN_CA_Enable_sig : 1; + u32 WAN_Enable_sig : 1; + u32 Mask_filter_sig : 1; + u32 Null_filter_sig : 1; + u32 ECM_filter_sig : 1; + u32 EMM_filter_sig : 1; + u32 PMT_filter_sig : 1; + u32 PCR_filter_sig : 1; + u32 Stream2_filter_sig : 1; + u32 Stream1_filter_sig : 1; + } ctrl_208; + + struct { + u32 reserved :21; + u32 Transport_Error : 1; + u32 LLC_SNAP_FLAG_set : 1; + u32 Continuity_error_flag : 1; + u32 Data_receiver_error : 1; + u32 Mailbox_from_V8_Status_sig : 1; + u32 DMA2_Size_IRQ_Status : 1; + u32 DMA1_Size_IRQ_Status : 1; + u32 DMA2_Timer_Status : 1; + u32 DMA2_IRQ_Status : 1; + u32 DMA1_Timer_Status : 1; + u32 DMA1_IRQ_Status : 1; + } irq_20c; + + struct { + u32 Special_controls :16; + u32 Block_reset_enable : 8; + u32 reset_blocks : 8; + } sw_reset_210; + + struct { + u32 unused2 :20; + u32 polarity_PS_ERR_sig : 1; + u32 polarity_PS_SYNC_sig : 1; + u32 polarity_PS_VALID_sig : 1; + u32 polarity_PS_CLK_sig : 1; + u32 unused1 : 3; + u32 s2p_sel_sig : 1; + u32 section_pkg_enable_sig : 1; + u32 halt_V8_sig : 1; + u32 v2WS_oe_sig : 1; + u32 vuart_oe_sig : 1; + } misc_214; + + struct { + u32 Mailbox_from_V8 :32; + } mbox_v8_to_host_218; + + struct { + u32 sysramaccess_busmuster : 1; + u32 sysramaccess_write : 1; + u32 unused : 7; + u32 sysramaccess_addr :15; + u32 sysramaccess_data : 8; + } mbox_host_to_v8_21c; + + struct { + u32 debug_fifo_problem : 1; + u32 debug_flag_write_status00 : 1; + u32 Stream2_trans : 1; + u32 Stream2_PID :13; + u32 debug_flag_pid_saved : 1; + u32 MAC_Multicast_filter : 1; + u32 Stream1_trans : 1; + u32 Stream1_PID :13; + } pid_filter_300; + + struct { + u32 reserved : 2; + u32 PMT_trans : 1; + u32 PMT_PID :13; + u32 debug_overrun2 : 1; + u32 debug_overrun3 : 1; + u32 PCR_trans : 1; + u32 PCR_PID :13; + } pid_filter_304; + + struct { + u32 reserved : 2; + u32 ECM_trans : 1; + u32 ECM_PID :13; + u32 EMM_filter_6 : 1; + u32 EMM_filter_4 : 1; + u32 EMM_trans : 1; + u32 EMM_PID :13; + } pid_filter_308; + + struct { + u32 unused2 : 3; + u32 Group_mask :13; + u32 unused1 : 2; + u32 Group_trans : 1; + u32 Group_PID :13; + } pid_filter_30c_ext_ind_0_7; + + struct { + u32 unused :15; + u32 net_master_read :17; + } pid_filter_30c_ext_ind_1; + + struct { + u32 unused :15; + u32 net_master_write :17; + } pid_filter_30c_ext_ind_2; + + struct { + u32 unused :15; + u32 next_net_master_write :17; + } pid_filter_30c_ext_ind_3; + + struct { + u32 reserved2 : 5; + u32 stack_read :10; + u32 reserved1 : 6; + u32 state_write :10; + u32 unused1 : 1; + } pid_filter_30c_ext_ind_4; + + struct { + u32 unused :22; + u32 stack_cnt :10; + } pid_filter_30c_ext_ind_5; + + struct { + u32 unused : 4; + u32 data_size_reg :12; + u32 write_status4 : 2; + u32 write_status1 : 2; + u32 pid_fsm_save_reg300 : 2; + u32 pid_fsm_save_reg4 : 2; + u32 pid_fsm_save_reg3 : 2; + u32 pid_fsm_save_reg2 : 2; + u32 pid_fsm_save_reg1 : 2; + u32 pid_fsm_save_reg0 : 2; + } pid_filter_30c_ext_ind_6; + + struct { + u32 unused :22; + u32 pass_alltables : 1; + u32 AB_select : 1; + u32 extra_index_reg : 3; + u32 index_reg : 5; + } index_reg_310; + + struct { + u32 reserved :17; + u32 PID_enable_bit : 1; + u32 PID_trans : 1; + u32 PID :13; + } pid_n_reg_314; + + struct { + u32 reserved : 6; + u32 HighAB_bit : 1; + u32 Enable_bit : 1; + u32 A6_byte : 8; + u32 A5_byte : 8; + u32 A4_byte : 8; + } mac_low_reg_318; + + struct { + u32 reserved : 8; + u32 A3_byte : 8; + u32 A2_byte : 8; + u32 A1_byte : 8; + } mac_high_reg_31c; + + struct { + u32 data_Tag_ID :16; + u32 reserved :16; + } data_tag_400; + + struct { + u32 Card_IDbyte3 : 8; + u32 Card_IDbyte4 : 8; + u32 Card_IDbyte5 : 8; + u32 Card_IDbyte6 : 8; + } card_id_408; + + struct { + u32 Card_IDbyte1 : 8; + u32 Card_IDbyte2 : 8; + } card_id_40c; + + struct { + u32 MAC6 : 8; + u32 MAC3 : 8; + u32 MAC2 : 8; + u32 MAC1 : 8; + } mac_address_418; + + struct { + u32 reserved :16; + u32 MAC8 : 8; + u32 MAC7 : 8; + } mac_address_41c; + + struct { + u32 reserved :21; + u32 txbuffempty : 1; + u32 ReceiveByteFrameError : 1; + u32 ReceiveDataReady : 1; + u32 transmitter_data_byte : 8; + } ci_600; + + struct { + u32 pi_component_reg : 3; + u32 pi_rw : 1; + u32 pi_ha :20; + u32 pi_d : 8; + } pi_604; + + struct { + u32 pi_busy_n : 1; + u32 pi_wait_n : 1; + u32 pi_timeout_status : 1; + u32 pi_CiMax_IRQ_n : 1; + u32 config_cclk : 1; + u32 config_cs_n : 1; + u32 config_wr_n : 1; + u32 config_Prog_n : 1; + u32 config_Init_stat : 1; + u32 config_Done_stat : 1; + u32 pcmcia_b_mod_pwr_n : 1; + u32 pcmcia_a_mod_pwr_n : 1; + u32 reserved : 3; + u32 Timer_addr : 5; + u32 unused : 1; + u32 timer_data : 7; + u32 Timer_Load_req : 1; + u32 Timer_Read_req : 1; + u32 oncecycle_read : 1; + u32 serialReset : 1; + } pi_608; + + struct { + u32 reserved : 6; + u32 rw_flag : 1; + u32 dvb_en : 1; + u32 key_array_row : 5; + u32 key_array_col : 3; + u32 key_code : 2; + u32 key_enable : 1; + u32 PID :13; + } dvb_reg_60c; + + struct { + u32 start_sram_ibi : 1; + u32 reserved2 : 1; + u32 ce_pin_reg : 1; + u32 oe_pin_reg : 1; + u32 reserved1 : 3; + u32 sc_xfer_bit : 1; + u32 sram_data : 8; + u32 sram_rw : 1; + u32 sram_addr :15; + } sram_ctrl_reg_700; + + struct { + u32 net_addr_write :16; + u32 net_addr_read :16; + } net_buf_reg_704; + + struct { + u32 cai_cnt : 4; + u32 reserved2 : 6; + u32 cai_write :11; + u32 reserved1 : 5; + u32 cai_read :11; + } cai_buf_reg_708; + + struct { + u32 cao_cnt : 4; + u32 reserved2 : 6; + u32 cap_write :11; + u32 reserved1 : 5; + u32 cao_read :11; + } cao_buf_reg_70c; + + struct { + u32 media_cnt : 4; + u32 reserved2 : 6; + u32 media_write :11; + u32 reserved1 : 5; + u32 media_read :11; + } media_buf_reg_710; + + struct { + u32 reserved :17; + u32 ctrl_maximumfill : 1; + u32 ctrl_sramdma : 1; + u32 ctrl_usb_wan : 1; + u32 cao_ovflow_error : 1; + u32 cai_ovflow_error : 1; + u32 media_ovflow_error : 1; + u32 net_ovflow_error : 1; + u32 MEDIA_Dest : 2; + u32 CAO_Dest : 2; + u32 CAI_Dest : 2; + u32 NET_Dest : 2; + } sram_dest_reg_714; + + struct { + u32 reserved3 :11; + u32 net_addr_write : 1; + u32 reserved2 : 3; + u32 net_addr_read : 1; + u32 reserved1 : 4; + u32 net_cnt :12; + } net_buf_reg_718; + + struct { + u32 reserved3 : 4; + u32 wan_pkt_frame : 4; + u32 reserved2 : 4; + u32 sram_memmap : 2; + u32 sram_chip : 2; + u32 wan_wait_state : 8; + u32 reserved1 : 6; + u32 wan_speed_sig : 2; + } wan_ctrl_reg_71c; +} flexcop_ibi_value; + +#endif diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h new file mode 100644 index 00000000000..bd4528d747d --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h @@ -0,0 +1,451 @@ +/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * register descriptions + * + * see flexcop.c for copyright information. + */ + +/* This file is automatically generated, do not edit things here. */ +#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__ +#define __FLEXCOP_IBI_VALUE_INCLUDED__ + +typedef union { + u32 raw; + + struct { + u32 dma_0start : 1; + u32 dma_0No_update : 1; + u32 dma_address0 :30; + } dma_0x0; + + struct { + u32 DMA_maxpackets : 8; + u32 dma_addr_size :24; + } dma_0x4_remap; + + struct { + u32 dma1timer : 7; + u32 unused : 1; + u32 dma_addr_size :24; + } dma_0x4_read; + + struct { + u32 unused : 1; + u32 dmatimer : 7; + u32 dma_addr_size :24; + } dma_0x4_write; + + struct { + u32 unused : 2; + u32 dma_cur_addr :30; + } dma_0x8; + + struct { + u32 dma_1start : 1; + u32 remap_enable : 1; + u32 dma_address1 :30; + } dma_0xc; + + struct { + u32 chipaddr : 7; + u32 reserved1 : 1; + u32 baseaddr : 8; + u32 data1_reg : 8; + u32 working_start : 1; + u32 twoWS_rw : 1; + u32 total_bytes : 2; + u32 twoWS_port_reg : 2; + u32 no_base_addr_ack_error : 1; + u32 st_done : 1; + } tw_sm_c_100; + + struct { + u32 data2_reg : 8; + u32 data3_reg : 8; + u32 data4_reg : 8; + u32 exlicit_stops : 1; + u32 force_stop : 1; + u32 unused : 6; + } tw_sm_c_104; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_108; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_10c; + + struct { + u32 thi1 : 6; + u32 reserved1 : 2; + u32 tlo1 : 5; + u32 reserved2 :19; + } tw_sm_c_110; + + struct { + u32 LNB_CTLHighCount_sig :15; + u32 LNB_CTLLowCount_sig :15; + u32 LNB_CTLPrescaler_sig : 2; + } lnb_switch_freq_200; + + struct { + u32 ACPI1_sig : 1; + u32 ACPI3_sig : 1; + u32 LNB_L_H_sig : 1; + u32 Per_reset_sig : 1; + u32 reserved :20; + u32 Rev_N_sig_revision_hi : 4; + u32 Rev_N_sig_reserved1 : 2; + u32 Rev_N_sig_caps : 1; + u32 Rev_N_sig_reserved2 : 1; + } misc_204; + + struct { + u32 Stream1_filter_sig : 1; + u32 Stream2_filter_sig : 1; + u32 PCR_filter_sig : 1; + u32 PMT_filter_sig : 1; + u32 EMM_filter_sig : 1; + u32 ECM_filter_sig : 1; + u32 Null_filter_sig : 1; + u32 Mask_filter_sig : 1; + u32 WAN_Enable_sig : 1; + u32 WAN_CA_Enable_sig : 1; + u32 CA_Enable_sig : 1; + u32 SMC_Enable_sig : 1; + u32 Per_CA_Enable_sig : 1; + u32 Multi2_Enable_sig : 1; + u32 MAC_filter_Mode_sig : 1; + u32 Rcv_Data_sig : 1; + u32 DMA1_IRQ_Enable_sig : 1; + u32 DMA1_Timer_Enable_sig : 1; + u32 DMA2_IRQ_Enable_sig : 1; + u32 DMA2_Timer_Enable_sig : 1; + u32 DMA1_Size_IRQ_Enable_sig : 1; + u32 DMA2_Size_IRQ_Enable_sig : 1; + u32 Mailbox_from_V8_Enable_sig : 1; + u32 unused : 9; + } ctrl_208; + + struct { + u32 DMA1_IRQ_Status : 1; + u32 DMA1_Timer_Status : 1; + u32 DMA2_IRQ_Status : 1; + u32 DMA2_Timer_Status : 1; + u32 DMA1_Size_IRQ_Status : 1; + u32 DMA2_Size_IRQ_Status : 1; + u32 Mailbox_from_V8_Status_sig : 1; + u32 Data_receiver_error : 1; + u32 Continuity_error_flag : 1; + u32 LLC_SNAP_FLAG_set : 1; + u32 Transport_Error : 1; + u32 reserved :21; + } irq_20c; + + struct { + u32 reset_blocks : 8; + u32 Block_reset_enable : 8; + u32 Special_controls :16; + } sw_reset_210; + + struct { + u32 vuart_oe_sig : 1; + u32 v2WS_oe_sig : 1; + u32 halt_V8_sig : 1; + u32 section_pkg_enable_sig : 1; + u32 s2p_sel_sig : 1; + u32 unused1 : 3; + u32 polarity_PS_CLK_sig : 1; + u32 polarity_PS_VALID_sig : 1; + u32 polarity_PS_SYNC_sig : 1; + u32 polarity_PS_ERR_sig : 1; + u32 unused2 :20; + } misc_214; + + struct { + u32 Mailbox_from_V8 :32; + } mbox_v8_to_host_218; + + struct { + u32 sysramaccess_data : 8; + u32 sysramaccess_addr :15; + u32 unused : 7; + u32 sysramaccess_write : 1; + u32 sysramaccess_busmuster : 1; + } mbox_host_to_v8_21c; + + struct { + u32 Stream1_PID :13; + u32 Stream1_trans : 1; + u32 MAC_Multicast_filter : 1; + u32 debug_flag_pid_saved : 1; + u32 Stream2_PID :13; + u32 Stream2_trans : 1; + u32 debug_flag_write_status00 : 1; + u32 debug_fifo_problem : 1; + } pid_filter_300; + + struct { + u32 PCR_PID :13; + u32 PCR_trans : 1; + u32 debug_overrun3 : 1; + u32 debug_overrun2 : 1; + u32 PMT_PID :13; + u32 PMT_trans : 1; + u32 reserved : 2; + } pid_filter_304; + + struct { + u32 EMM_PID :13; + u32 EMM_trans : 1; + u32 EMM_filter_4 : 1; + u32 EMM_filter_6 : 1; + u32 ECM_PID :13; + u32 ECM_trans : 1; + u32 reserved : 2; + } pid_filter_308; + + struct { + u32 Group_PID :13; + u32 Group_trans : 1; + u32 unused1 : 2; + u32 Group_mask :13; + u32 unused2 : 3; + } pid_filter_30c_ext_ind_0_7; + + struct { + u32 net_master_read :17; + u32 unused :15; + } pid_filter_30c_ext_ind_1; + + struct { + u32 net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_2; + + struct { + u32 next_net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_3; + + struct { + u32 unused1 : 1; + u32 state_write :10; + u32 reserved1 : 6; + u32 stack_read :10; + u32 reserved2 : 5; + } pid_filter_30c_ext_ind_4; + + struct { + u32 stack_cnt :10; + u32 unused :22; + } pid_filter_30c_ext_ind_5; + + struct { + u32 pid_fsm_save_reg0 : 2; + u32 pid_fsm_save_reg1 : 2; + u32 pid_fsm_save_reg2 : 2; + u32 pid_fsm_save_reg3 : 2; + u32 pid_fsm_save_reg4 : 2; + u32 pid_fsm_save_reg300 : 2; + u32 write_status1 : 2; + u32 write_status4 : 2; + u32 data_size_reg :12; + u32 unused : 4; + } pid_filter_30c_ext_ind_6; + + struct { + u32 index_reg : 5; + u32 extra_index_reg : 3; + u32 AB_select : 1; + u32 pass_alltables : 1; + u32 unused :22; + } index_reg_310; + + struct { + u32 PID :13; + u32 PID_trans : 1; + u32 PID_enable_bit : 1; + u32 reserved :17; + } pid_n_reg_314; + + struct { + u32 A4_byte : 8; + u32 A5_byte : 8; + u32 A6_byte : 8; + u32 Enable_bit : 1; + u32 HighAB_bit : 1; + u32 reserved : 6; + } mac_low_reg_318; + + struct { + u32 A1_byte : 8; + u32 A2_byte : 8; + u32 A3_byte : 8; + u32 reserved : 8; + } mac_high_reg_31c; + + struct { + u32 reserved :16; + u32 data_Tag_ID :16; + } data_tag_400; + + struct { + u32 Card_IDbyte6 : 8; + u32 Card_IDbyte5 : 8; + u32 Card_IDbyte4 : 8; + u32 Card_IDbyte3 : 8; + } card_id_408; + + struct { + u32 Card_IDbyte2 : 8; + u32 Card_IDbyte1 : 8; + } card_id_40c; + + struct { + u32 MAC1 : 8; + u32 MAC2 : 8; + u32 MAC3 : 8; + u32 MAC6 : 8; + } mac_address_418; + + struct { + u32 MAC7 : 8; + u32 MAC8 : 8; + u32 reserved :16; + } mac_address_41c; + + struct { + u32 transmitter_data_byte : 8; + u32 ReceiveDataReady : 1; + u32 ReceiveByteFrameError : 1; + u32 txbuffempty : 1; + u32 reserved :21; + } ci_600; + + struct { + u32 pi_d : 8; + u32 pi_ha :20; + u32 pi_rw : 1; + u32 pi_component_reg : 3; + } pi_604; + + struct { + u32 serialReset : 1; + u32 oncecycle_read : 1; + u32 Timer_Read_req : 1; + u32 Timer_Load_req : 1; + u32 timer_data : 7; + u32 unused : 1; + u32 Timer_addr : 5; + u32 reserved : 3; + u32 pcmcia_a_mod_pwr_n : 1; + u32 pcmcia_b_mod_pwr_n : 1; + u32 config_Done_stat : 1; + u32 config_Init_stat : 1; + u32 config_Prog_n : 1; + u32 config_wr_n : 1; + u32 config_cs_n : 1; + u32 config_cclk : 1; + u32 pi_CiMax_IRQ_n : 1; + u32 pi_timeout_status : 1; + u32 pi_wait_n : 1; + u32 pi_busy_n : 1; + } pi_608; + + struct { + u32 PID :13; + u32 key_enable : 1; + u32 key_code : 2; + u32 key_array_col : 3; + u32 key_array_row : 5; + u32 dvb_en : 1; + u32 rw_flag : 1; + u32 reserved : 6; + } dvb_reg_60c; + + struct { + u32 sram_addr :15; + u32 sram_rw : 1; + u32 sram_data : 8; + u32 sc_xfer_bit : 1; + u32 reserved1 : 3; + u32 oe_pin_reg : 1; + u32 ce_pin_reg : 1; + u32 reserved2 : 1; + u32 start_sram_ibi : 1; + } sram_ctrl_reg_700; + + struct { + u32 net_addr_read :16; + u32 net_addr_write :16; + } net_buf_reg_704; + + struct { + u32 cai_read :11; + u32 reserved1 : 5; + u32 cai_write :11; + u32 reserved2 : 6; + u32 cai_cnt : 4; + } cai_buf_reg_708; + + struct { + u32 cao_read :11; + u32 reserved1 : 5; + u32 cap_write :11; + u32 reserved2 : 6; + u32 cao_cnt : 4; + } cao_buf_reg_70c; + + struct { + u32 media_read :11; + u32 reserved1 : 5; + u32 media_write :11; + u32 reserved2 : 6; + u32 media_cnt : 4; + } media_buf_reg_710; + + struct { + u32 NET_Dest : 2; + u32 CAI_Dest : 2; + u32 CAO_Dest : 2; + u32 MEDIA_Dest : 2; + u32 net_ovflow_error : 1; + u32 media_ovflow_error : 1; + u32 cai_ovflow_error : 1; + u32 cao_ovflow_error : 1; + u32 ctrl_usb_wan : 1; + u32 ctrl_sramdma : 1; + u32 ctrl_maximumfill : 1; + u32 reserved :17; + } sram_dest_reg_714; + + struct { + u32 net_cnt :12; + u32 reserved1 : 4; + u32 net_addr_read : 1; + u32 reserved2 : 3; + u32 net_addr_write : 1; + u32 reserved3 :11; + } net_buf_reg_718; + + struct { + u32 wan_speed_sig : 2; + u32 reserved1 : 6; + u32 wan_wait_state : 8; + u32 sram_chip : 2; + u32 sram_memmap : 2; + u32 reserved2 : 4; + u32 wan_pkt_frame : 4; + u32 reserved3 : 4; + } wan_ctrl_reg_71c; +} flexcop_ibi_value; + +#endif -- cgit v1.2.3 From 64221be7b9006338e4a45228f013e467ee4bf045 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:57:49 -0700 Subject: [PATCH] dvb: flexcop: woraround irq stop problem The flexcop chip often stops generating interrupts after some hours of operation. Apparently this can be fixed by resetting register block 0x300 at each channel change (this is not detailed in the flexcop data books). This patch also restructures DMA handling and adds a bit of debug code for the irq problem in case it still happens for someone. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-common.h | 6 +- drivers/media/dvb/b2c2/flexcop-dma.c | 165 +++++++++++++++++--------- drivers/media/dvb/b2c2/flexcop-hw-filter.c | 12 +- drivers/media/dvb/b2c2/flexcop-misc.c | 12 ++ drivers/media/dvb/b2c2/flexcop-pci.c | 122 +++++++++++++------ drivers/media/dvb/b2c2/flexcop.c | 34 +++++- drivers/media/dvb/b2c2/flexcop.h | 1 + drivers/media/dvb/b2c2/flexcop_ibi_value_be.h | 9 +- drivers/media/dvb/b2c2/flexcop_ibi_value_le.h | 9 +- 9 files changed, 274 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h index 773d158032d..a94912ac187 100644 --- a/drivers/media/dvb/b2c2/flexcop-common.h +++ b/drivers/media/dvb/b2c2/flexcop-common.h @@ -108,6 +108,8 @@ void flexcop_device_kfree(struct flexcop_device*); int flexcop_device_initialize(struct flexcop_device*); void flexcop_device_exit(struct flexcop_device *fc); +void flexcop_reset_block_300(struct flexcop_device *fc); + /* from flexcop-dma.c */ int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size); void flexcop_dma_free(struct flexcop_dma *dma); @@ -115,7 +117,8 @@ void flexcop_dma_free(struct flexcop_dma *dma); int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff); -int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index); +int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx); +int flexcop_dma_xfer_control(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, int onoff); int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles); int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets); @@ -151,6 +154,7 @@ int flexcop_sram_init(struct flexcop_device *fc); /* from flexcop-misc.c */ void flexcop_determine_revision(struct flexcop_device *fc); void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix); +void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num); /* from flexcop-hw-filter.c */ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff); diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c index 8d270607536..cf4ed1df608 100644 --- a/drivers/media/dvb/b2c2/flexcop-dma.c +++ b/drivers/media/dvb/b2c2/flexcop-dma.c @@ -37,22 +37,90 @@ void flexcop_dma_free(struct flexcop_dma *dma) } EXPORT_SYMBOL(flexcop_dma_free); -int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +int flexcop_dma_config(struct flexcop_device *fc, + struct flexcop_dma *dma, + flexcop_dma_index_t dma_idx) { - flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + flexcop_ibi_value v0x0,v0x4,v0xc; + v0x0.raw = v0x4.raw = v0xc.raw = 0; - if (no & FC_DMA_1) - v.ctrl_208.DMA1_Timer_Enable_sig = onoff; + v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; + v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; + v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; - if (no & FC_DMA_2) - v.ctrl_208.DMA2_Timer_Enable_sig = onoff; + if ((dma_idx & FC_DMA_1) == dma_idx) { + fc->write_ibi_reg(fc,dma1_000,v0x0); + fc->write_ibi_reg(fc,dma1_004,v0x4); + fc->write_ibi_reg(fc,dma1_00c,v0xc); + } else if ((dma_idx & FC_DMA_2) == dma_idx) { + fc->write_ibi_reg(fc,dma2_010,v0x0); + fc->write_ibi_reg(fc,dma2_014,v0x4); + fc->write_ibi_reg(fc,dma2_01c,v0xc); + } else { + err("either DMA1 or DMA2 can be configured at the within one flexcop_dma_config call."); + return -EINVAL; + } - fc->write_ibi_reg(fc,ctrl_208,v); return 0; } -EXPORT_SYMBOL(flexcop_dma_control_timer_irq); +EXPORT_SYMBOL(flexcop_dma_config); + +/* start the DMA transfers, but not the DMA IRQs */ +int flexcop_dma_xfer_control(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + flexcop_dma_addr_index_t index, + int onoff) +{ + flexcop_ibi_value v0x0,v0xc; + flexcop_ibi_register r0x0,r0xc; + + if ((dma_idx & FC_DMA_1) == dma_idx) { + r0x0 = dma1_000; + r0xc = dma1_00c; + } else if ((dma_idx & FC_DMA_2) == dma_idx) { + r0x0 = dma2_010; + r0xc = dma2_01c; + } else { + err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call."); + return -EINVAL; + } + + v0x0 = fc->read_ibi_reg(fc,r0x0); + v0xc = fc->read_ibi_reg(fc,r0xc); + + deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); + deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); + + if (index & FC_DMA_SUBADDR_0) + v0x0.dma_0x0.dma_0start = onoff; + + if (index & FC_DMA_SUBADDR_1) + v0xc.dma_0xc.dma_1start = onoff; + + fc->write_ibi_reg(fc,r0x0,v0x0); + fc->write_ibi_reg(fc,r0xc,v0xc); + + deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw); + deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_xfer_control); + +static int flexcop_dma_remap(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + int onoff) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + deb_info("%s\n",__FUNCTION__); + v.dma_0xc.remap_enable = onoff; + fc->write_ibi_reg(fc,r,v); + return 0; +} -int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +int flexcop_dma_control_size_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, + int onoff) { flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); @@ -67,75 +135,64 @@ int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t } EXPORT_SYMBOL(flexcop_dma_control_size_irq); -int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +int flexcop_dma_control_timer_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, + int onoff) { flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); if (no & FC_DMA_1) - v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff; + v.ctrl_208.DMA1_Timer_Enable_sig = onoff; if (no & FC_DMA_2) - v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff; + v.ctrl_208.DMA2_Timer_Enable_sig = onoff; fc->write_ibi_reg(fc,ctrl_208,v); return 0; } -EXPORT_SYMBOL(flexcop_dma_control_packet_irq); +EXPORT_SYMBOL(flexcop_dma_control_timer_irq); -int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index) +/* 1 cycles = 1.97 msec */ +int flexcop_dma_config_timer(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + u8 cycles) { + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); - flexcop_ibi_value v0x0,v0x4,v0xc; - v0x0.raw = v0x4.raw = v0xc.raw = 0; - - v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; - v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; - v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; - - if (index & FC_DMA_SUBADDR_0) - v0x0.dma_0x0.dma_0start = 1; - - if (index & FC_DMA_SUBADDR_1) - v0xc.dma_0xc.dma_1start = 1; - - if (dma_idx & FC_DMA_1) { - fc->write_ibi_reg(fc,dma1_000,v0x0); - fc->write_ibi_reg(fc,dma1_004,v0x4); - fc->write_ibi_reg(fc,dma1_00c,v0xc); - } else { /* (dma_idx & FC_DMA_2) */ - fc->write_ibi_reg(fc,dma2_010,v0x0); - fc->write_ibi_reg(fc,dma2_014,v0x4); - fc->write_ibi_reg(fc,dma2_01c,v0xc); - } - - return 0; -} -EXPORT_SYMBOL(flexcop_dma_config); + flexcop_dma_remap(fc,dma_idx,0); -static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff) -{ - flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; - flexcop_ibi_value v = fc->read_ibi_reg(fc,r); - v.dma_0xc.remap_enable = onoff; + deb_info("%s\n",__FUNCTION__); + v.dma_0x4_write.dmatimer = cycles; fc->write_ibi_reg(fc,r,v); return 0; } +EXPORT_SYMBOL(flexcop_dma_config_timer); -/* 1 cycles = 1.97 msec */ -int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles) +/* packet IRQ does not exist in FCII or FCIIb - according to data book and tests */ +int flexcop_dma_control_packet_irq(struct flexcop_device *fc, + flexcop_dma_index_t no, + int onoff) { - flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; - flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); - flexcop_dma_remap(fc,dma_idx,0); + deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw); + if (no & FC_DMA_1) + v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw); - v.dma_0x4_write.dmatimer = cycles >> 1; - fc->write_ibi_reg(fc,r,v); return 0; } -EXPORT_SYMBOL(flexcop_dma_config_timer); +EXPORT_SYMBOL(flexcop_dma_control_packet_irq); -int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets) +int flexcop_dma_config_packet_count(struct flexcop_device *fc, + flexcop_dma_index_t dma_idx, + u8 packets) { flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; flexcop_ibi_value v = fc->read_ibi_reg(fc,r); diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c index 2baf43d3ce8..75cf237196e 100644 --- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c +++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c @@ -10,6 +10,8 @@ static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff) { flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff); + + deb_ts("rcv_data is now: '%s'\n",onoff ? "on" : "off"); } void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) @@ -151,7 +153,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d { int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32; - fc->feedcount += onoff ? 1 : -1; + fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */ if (dvbdmxfeed->index >= max_pid_filter) fc->extra_feedcount += onoff ? 1 : -1; @@ -178,8 +180,14 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d /* if it was the first or last feed request change the stream-status */ if (fc->feedcount == onoff) { flexcop_rcv_data_ctrl(fc,onoff); - if (fc->stream_control) + if (fc->stream_control) /* device specific stream control */ fc->stream_control(fc,onoff); + + /* feeding stopped -> reset the flexcop filter*/ + if (onoff == 0) { + flexcop_reset_block_300(fc); + flexcop_hw_filter_init(fc); + } } return 0; diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c index 23082545651..3a08d38b318 100644 --- a/drivers/media/dvb/b2c2/flexcop-misc.c +++ b/drivers/media/dvb/b2c2/flexcop-misc.c @@ -65,3 +65,15 @@ void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type], flexcop_revision_names[fc->rev],suffix); } + +void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num) +{ + flexcop_ibi_value v; + int i; + for (i = 0; i < num; i++) { + v = fc->read_ibi_reg(fc,reg+4*i); + deb_rdump("0x%03x: %08x, ",reg+4*i, v.raw); + } + deb_rdump("\n"); +} +EXPORT_SYMBOL(flexcop_dump_reg); diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index ed717c0073d..a436d5584ea 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -13,6 +13,10 @@ static int enable_pid_filtering = 1; module_param(enable_pid_filtering, int, 0444); MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1"); +static int irq_chk_intv; +module_param(irq_chk_intv, int, 0644); +MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging)."); + #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG #define dprintk(level,args...) \ do { if ((debug & level)) printk(args); } while (0) @@ -26,6 +30,7 @@ MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported #define deb_reg(args...) dprintk(0x02,args) #define deb_ts(args...) dprintk(0x04,args) #define deb_irq(args...) dprintk(0x08,args) +#define deb_chk(args...) dprintk(0x10,args) static int debug = 0; module_param(debug, int, 0644); @@ -56,6 +61,10 @@ struct flexcop_pci { spinlock_t irq_lock; + unsigned long last_irq; + + struct work_struct irq_check_work; + struct flexcop_device *fc_dev; }; @@ -88,18 +97,55 @@ static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_regi return 0; } +static void flexcop_pci_irq_check_work(void *data) +{ + struct flexcop_pci *fc_pci = data; + struct flexcop_device *fc = fc_pci->fc_dev; + + flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); + + flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4); + + if (v.sram_dest_reg_714.net_ovflow_error) + deb_chk("sram net_ovflow_error\n"); + if (v.sram_dest_reg_714.media_ovflow_error) + deb_chk("sram media_ovflow_error\n"); + if (v.sram_dest_reg_714.cai_ovflow_error) + deb_chk("sram cai_ovflow_error\n"); + if (v.sram_dest_reg_714.cai_ovflow_error) + deb_chk("sram cai_ovflow_error\n"); + + schedule_delayed_work(&fc_pci->irq_check_work, + msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); +} + /* When PID filtering is turned on, we use the timer IRQ, because small amounts * of data need to be passed to the user space instantly as well. When PID * filtering is turned off, we use the page-change-IRQ */ -static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t flexcop_pci_isr(int irq, void *dev_id, struct pt_regs *regs) { struct flexcop_pci *fc_pci = dev_id; struct flexcop_device *fc = fc_pci->fc_dev; - flexcop_ibi_value v = fc->read_ibi_reg(fc,irq_20c); + flexcop_ibi_value v; irqreturn_t ret = IRQ_HANDLED; spin_lock_irq(&fc_pci->irq_lock); + v = fc->read_ibi_reg(fc,irq_20c); + + /* errors */ + if (v.irq_20c.Data_receiver_error) + deb_chk("data receiver error\n"); + if (v.irq_20c.Continuity_error_flag) + deb_chk("Contunuity error flag is set\n"); + if (v.irq_20c.LLC_SNAP_FLAG_set) + deb_chk("LLC_SNAP_FLAG_set is set\n"); + if (v.irq_20c.Transport_Error) + deb_chk("Transport error\n"); + + if ((fc_pci->count % 1000) == 0) + deb_chk("%d valid irq took place so far\n",fc_pci->count); + if (v.irq_20c.DMA1_IRQ_Status == 1) { if (fc_pci->active_dma1_addr == 0) flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188); @@ -115,8 +161,9 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; - deb_irq("irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ", - v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos); + deb_irq("%u irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ", + jiffies_to_usecs(jiffies - fc_pci->last_irq),v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos); + fc_pci->last_irq = jiffies; /* buffer end was reached, restarted from the beginning * pass the data from last_cur_pos to the buffer end to the demux @@ -127,7 +174,6 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos, (fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos); fc_pci->last_dma1_cur_pos = 0; - fc_pci->count = 0; } if (cur_pos > fc_pci->last_dma1_cur_pos) { @@ -139,16 +185,14 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs) deb_irq("\n"); fc_pci->last_dma1_cur_pos = cur_pos; - } else + fc_pci->count++; + } else { + deb_irq("isr for flexcop called, apparently without reason (%08x)\n",v.raw); ret = IRQ_NONE; + } spin_unlock_irq(&fc_pci->irq_lock); -/* packet count would be ideal for hw filtering, but it isn't working. Either - * the data book is wrong, or I'm unable to read it correctly */ - -/* if (v.irq_20c.DMA1_Size_IRQ_Status == 1) { packet counter */ - return ret; } @@ -156,30 +200,35 @@ static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff) { struct flexcop_pci *fc_pci = fc->bus_specific; if (onoff) { - flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1); - flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1); - flexcop_dma_config_timer(fc,FC_DMA_1,1); + flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1); + flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2); - if (fc_pci->fc_dev->pid_filtering) { - fc_pci->last_dma1_cur_pos = 0; - flexcop_dma_control_timer_irq(fc,FC_DMA_1,1); - } else { - fc_pci->active_dma1_addr = 0; - flexcop_dma_control_size_irq(fc,FC_DMA_1,1); - } + flexcop_dma_config_timer(fc,FC_DMA_1,0); -/* flexcop_dma_config_packet_count(fc,FC_DMA_1,0xc0); - flexcop_dma_control_packet_irq(fc,FC_DMA_1,1); */ + flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,1); + deb_irq("DMA xfer enabled\n"); - deb_irq("irqs enabled\n"); + fc_pci->last_dma1_cur_pos = 0; + flexcop_dma_control_timer_irq(fc,FC_DMA_1,1); + deb_irq("IRQ enabled\n"); + +// fc_pci->active_dma1_addr = 0; +// flexcop_dma_control_size_irq(fc,FC_DMA_1,1); + + if (irq_chk_intv > 0) + schedule_delayed_work(&fc_pci->irq_check_work, + msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); } else { - if (fc_pci->fc_dev->pid_filtering) - flexcop_dma_control_timer_irq(fc,FC_DMA_1,0); - else - flexcop_dma_control_size_irq(fc,FC_DMA_1,0); + if (irq_chk_intv > 0) + cancel_delayed_work(&fc_pci->irq_check_work); + + flexcop_dma_control_timer_irq(fc,FC_DMA_1,0); + deb_irq("IRQ disabled\n"); -// flexcop_dma_control_packet_irq(fc,FC_DMA_1,0); - deb_irq("irqs disabled\n"); +// flexcop_dma_control_size_irq(fc,FC_DMA_1,0); + + flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,0); + deb_irq("DMA xfer disabled\n"); } return 0; @@ -198,6 +247,7 @@ static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci) flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2); fc_pci->init_state |= FC_PCI_DMA_INIT; + goto success; dma1_free: flexcop_dma_free(&fc_pci->dma[0]); @@ -244,7 +294,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) pci_set_drvdata(fc_pci->pdev, fc_pci); - if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_irq, + if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr, SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0) goto err_pci_iounmap; @@ -324,6 +374,8 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if ((ret = flexcop_pci_dma_init(fc_pci)) != 0) goto err_fc_exit; + INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci); + goto success; err_fc_exit: flexcop_device_exit(fc); @@ -350,17 +402,17 @@ static void flexcop_pci_remove(struct pci_dev *pdev) static struct pci_device_id flexcop_pci_tbl[] = { { PCI_DEVICE(0x13d0, 0x2103) }, -/* { PCI_DEVICE(0x13d0, 0x2200) }, PCI FlexCopIII ? */ +/* { PCI_DEVICE(0x13d0, 0x2200) }, ? */ { }, }; MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl); static struct pci_driver flexcop_pci_driver = { - .name = "Technisat/B2C2 FlexCop II/IIb/III PCI", + .name = "Technisat/B2C2 FlexCop II/IIb PCI", .id_table = flexcop_pci_tbl, - .probe = flexcop_pci_probe, - .remove = flexcop_pci_remove, + .probe = flexcop_pci_probe, + .remove = flexcop_pci_remove, }; static int __init flexcop_pci_module_init(void) diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 8b5d14dd36e..12873d43540 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -46,7 +46,7 @@ int b2c2_flexcop_debug; module_param_named(debug, b2c2_flexcop_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram (|-able))." DEBSTATUS); +MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." DEBSTATUS); #undef DEBSTATUS /* global zero for ibi values */ @@ -173,9 +173,20 @@ static void flexcop_reset(struct flexcop_device *fc) fc->write_ibi_reg(fc,ctrl_208,ibi_zero); v210.raw = 0; - v210.sw_reset_210.reset_blocks = 0xff; + v210.sw_reset_210.reset_block_000 = 1; + v210.sw_reset_210.reset_block_100 = 1; + v210.sw_reset_210.reset_block_200 = 1; + v210.sw_reset_210.reset_block_300 = 1; + v210.sw_reset_210.reset_block_400 = 1; + v210.sw_reset_210.reset_block_500 = 1; + v210.sw_reset_210.reset_block_600 = 1; + v210.sw_reset_210.reset_block_700 = 1; v210.sw_reset_210.Block_reset_enable = 0xb2; + + v210.sw_reset_210.Special_controls = 0xc259; + fc->write_ibi_reg(fc,sw_reset_210,v210); + msleep(1); /* reset the periphical devices */ @@ -186,6 +197,25 @@ static void flexcop_reset(struct flexcop_device *fc) fc->write_ibi_reg(fc,misc_204,v204); } +void flexcop_reset_block_300(struct flexcop_device *fc) +{ + flexcop_ibi_value v208_save = fc->read_ibi_reg(fc,ctrl_208), + v210 = fc->read_ibi_reg(fc,sw_reset_210); + + deb_rdump("208: %08x, 210: %08x\n",v208_save.raw,v210.raw); + + fc->write_ibi_reg(fc,ctrl_208,ibi_zero); + + v210.sw_reset_210.reset_block_300 = 1; + v210.sw_reset_210.Block_reset_enable = 0xb2; + + fc->write_ibi_reg(fc,sw_reset_210,v210); + msleep(1); + + fc->write_ibi_reg(fc,ctrl_208,v208_save); +} +EXPORT_SYMBOL(flexcop_reset_block_300); + struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) { void *bus; diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h index caa343a97bd..0cebe1d92e0 100644 --- a/drivers/media/dvb/b2c2/flexcop.h +++ b/drivers/media/dvb/b2c2/flexcop.h @@ -26,5 +26,6 @@ extern int b2c2_flexcop_debug; #define deb_i2c(args...) dprintk(0x04,args) #define deb_ts(args...) dprintk(0x08,args) #define deb_sram(args...) dprintk(0x10,args) +#define deb_rdump(args...) dprintk(0x20,args) #endif diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h index bf3cb5a71fb..ed9a6756b19 100644 --- a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h +++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h @@ -152,7 +152,14 @@ typedef union { struct { u32 Special_controls :16; u32 Block_reset_enable : 8; - u32 reset_blocks : 8; + u32 reset_block_700 : 1; + u32 reset_block_600 : 1; + u32 reset_block_500 : 1; + u32 reset_block_400 : 1; + u32 reset_block_300 : 1; + u32 reset_block_200 : 1; + u32 reset_block_100 : 1; + u32 reset_block_000 : 1; } sw_reset_210; struct { diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h index bd4528d747d..49f2315b6e5 100644 --- a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h +++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h @@ -150,7 +150,14 @@ typedef union { } irq_20c; struct { - u32 reset_blocks : 8; + u32 reset_block_000 : 1; + u32 reset_block_100 : 1; + u32 reset_block_200 : 1; + u32 reset_block_300 : 1; + u32 reset_block_400 : 1; + u32 reset_block_500 : 1; + u32 reset_block_600 : 1; + u32 reset_block_700 : 1; u32 Block_reset_enable : 8; u32 Special_controls :16; } sw_reset_210; -- cgit v1.2.3 From 7d53421c6adce47d067b834c605daeafe1ff9356 Mon Sep 17 00:00:00 2001 From: Manu Abraham Date: Thu, 7 Jul 2005 17:57:50 -0700 Subject: [PATCH] dvb: Twinhan DST: frontend fixes o Make the inversion setting specific, ie, only for the 200103A DVB-S This should not be flagged on other cards. o Make the frequency setting card specific o Make the bandwidth setting generic such that it supports more DVB-T cards o Set QAM size for DVB-C cards that do not autodetect QAM size o Fix a bug that caused the polarization not to be set. Set polarization for cards that do not autodetect polarization o Fix a bogus frontend signal lock, that caused a tuning delay as well. o Make the Symbolrate setting card specific Signed-off-by: Manu Abraham Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 227 ++++++++++++++--------- drivers/media/dvb/bt8xx/dst_ca.c | 349 +++++++++++++---------------------- drivers/media/dvb/bt8xx/dst_common.h | 3 + 3 files changed, 272 insertions(+), 307 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 1339912c308..1f97c37fe9a 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -258,10 +258,10 @@ int write_dst(struct dst_state *state, u8 *data, u8 len) if (debug && (verbose > 4)) { u8 i; if (verbose > 4) { - dprintk("%s writing", __FUNCTION__); + dprintk("%s writing [ ", __FUNCTION__); for (i = 0; i < len; i++) - dprintk(" %02x", data[i]); - dprintk("\n"); + dprintk("%02x ", data[i]); + dprintk("]\n"); } } for (cnt = 0; cnt < 2; cnt++) { @@ -320,10 +320,29 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len) } EXPORT_SYMBOL(read_dst); -static int dst_set_freq(struct dst_state *state, u32 freq) +static int dst_set_polarization(struct dst_state *state) { - u8 *val; + switch (state->voltage) { + case SEC_VOLTAGE_13: // vertical + printk("%s: Polarization=[Vertical]\n", __FUNCTION__); + state->tx_tuna[8] |= 0x40; //1 + break; + + case SEC_VOLTAGE_18: // horizontal + printk("%s: Polarization=[Horizontal]\n", __FUNCTION__); + state->tx_tuna[8] =~ 0x40; // 0 + break; + case SEC_VOLTAGE_OFF: + + break; + } + + return 0; +} + +static int dst_set_freq(struct dst_state *state, u32 freq) +{ state->frequency = freq; if (debug > 4) dprintk("%s: set Frequency %u\n", __FUNCTION__, freq); @@ -332,46 +351,30 @@ static int dst_set_freq(struct dst_state *state, u32 freq) freq = freq / 1000; if (freq < 950 || freq > 2150) return -EINVAL; - val = &state->tx_tuna[0]; - val[2] = (freq >> 8) & 0x7f; - val[3] = (u8) freq; - val[4] = 1; - val[8] &= ~4; - if (freq < 1531) - val[8] |= 4; + + state->tx_tuna[2] = (freq >> 8); + state->tx_tuna[3] = (u8) freq; + state->tx_tuna[4] = 0x01; + state->tx_tuna[8] &= ~0x04; + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { + if (freq < 1531) + state->tx_tuna[8] |= 0x04; + } + } else if (state->dst_type == DST_TYPE_IS_TERR) { freq = freq / 1000; if (freq < 137000 || freq > 858000) return -EINVAL; - val = &state->tx_tuna[0]; - val[2] = (freq >> 16) & 0xff; - val[3] = (freq >> 8) & 0xff; - val[4] = (u8) freq; - val[5] = 0; - switch (state->bandwidth) { - case BANDWIDTH_6_MHZ: - val[6] = 6; - break; - - case BANDWIDTH_7_MHZ: - case BANDWIDTH_AUTO: - val[6] = 7; - break; - case BANDWIDTH_8_MHZ: - val[6] = 8; - break; - } + state->tx_tuna[2] = (freq >> 16) & 0xff; + state->tx_tuna[3] = (freq >> 8) & 0xff; + state->tx_tuna[4] = (u8) freq; - val[7] = 0; - val[8] = 0; } else if (state->dst_type == DST_TYPE_IS_CABLE) { - /* guess till will get one */ - freq = freq / 1000; - val = &state->tx_tuna[0]; - val[2] = (freq >> 16) & 0xff; - val[3] = (freq >> 8) & 0xff; - val[4] = (u8) freq; + state->tx_tuna[2] = (freq >> 16) & 0xff; + state->tx_tuna[3] = (freq >> 8) & 0xff; + state->tx_tuna[4] = (u8) freq; + } else return -EINVAL; return 0; @@ -379,51 +382,58 @@ static int dst_set_freq(struct dst_state *state, u32 freq) static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth) { - u8 *val; - state->bandwidth = bandwidth; if (state->dst_type != DST_TYPE_IS_TERR) return 0; - val = &state->tx_tuna[0]; switch (bandwidth) { - case BANDWIDTH_6_MHZ: - val[6] = 6; - break; + case BANDWIDTH_6_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x06; + else { + state->tx_tuna[6] = 0x06; + state->tx_tuna[7] = 0x00; + } + break; - case BANDWIDTH_7_MHZ: - val[6] = 7; - break; + case BANDWIDTH_7_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x07; + else { + state->tx_tuna[6] = 0x07; + state->tx_tuna[7] = 0x00; + } + break; - case BANDWIDTH_8_MHZ: - val[6] = 8; - break; + case BANDWIDTH_8_MHZ: + if (state->dst_hw_cap & DST_TYPE_HAS_CA) + state->tx_tuna[7] = 0x08; + else { + state->tx_tuna[6] = 0x08; + state->tx_tuna[7] = 0x00; + } + break; - default: - return -EINVAL; + default: + return -EINVAL; } return 0; } static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion) { - u8 *val; - state->inversion = inversion; - - val = &state->tx_tuna[0]; - - val[8] &= ~0x80; - switch (inversion) { - case INVERSION_OFF: - break; - case INVERSION_ON: - val[8] |= 0x80; - break; - default: - return -EINVAL; + case INVERSION_OFF: // Inversion = Normal + state->tx_tuna[8] &= ~0x80; + break; + + case INVERSION_ON: + state->tx_tuna[8] |= 0x80; + break; + default: + return -EINVAL; } return 0; } @@ -478,6 +488,52 @@ static int dst_set_symbolrate(struct dst_state* state, u32 srate) return 0; } + +static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) +{ + if (state->dst_type != DST_TYPE_IS_CABLE) + return 0; + + state->modulation = modulation; + switch (modulation) { + case QAM_16: + state->tx_tuna[8] = 0x10; + break; + + case QAM_32: + state->tx_tuna[8] = 0x20; + break; + + case QAM_64: + state->tx_tuna[8] = 0x40; + break; + + case QAM_128: + state->tx_tuna[8] = 0x80; + break; + + case QAM_256: + state->tx_tuna[8] = 0x00; + break; + + case QPSK: + case QAM_AUTO: + case VSB_8: + case VSB_16: + default: + return -EINVAL; + + } + + return 0; +} + +static fe_modulation_t dst_get_modulation(struct dst_state *state) +{ + return state->modulation; +} + + u8 dst_check_sum(u8 * buf, u32 len) { u32 i; @@ -577,7 +633,7 @@ struct dst_types dst_tlist[] = { .device_id = "200103A", .offset = 0, .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, + .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS, .dst_feature = 0 }, /* obsolete */ @@ -626,7 +682,7 @@ struct dst_types dst_tlist[] = { .device_id = "DSTMCI", .offset = 1, .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, + .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT, .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC }, @@ -872,7 +928,7 @@ static int dst_get_signal(struct dst_state* state) { int retval; u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; - + printk("%s: Getting Signal strength and other parameters !!!!!!!!\n", __FUNCTION__); if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { state->decode_lock = state->decode_strength = state->decode_snr = 0; return 0; @@ -954,15 +1010,8 @@ static int dst_get_tuna(struct dst_state* state) state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; state->decode_lock = 1; - /* - dst->decode_n1 = (dst->rx_tuna[4] << 8) + - (dst->rx_tuna[5]); - - dst->decode_n2 = (dst->rx_tuna[8] << 8) + - (dst->rx_tuna[7]); - */ state->diseq_flags |= HAS_LOCK; - /* dst->cur_jiff = jiffies; */ + return 1; } @@ -1145,7 +1194,8 @@ static int dst_init(struct dvb_frontend* fe) static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - state->inversion = INVERSION_ON; +// state->inversion = INVERSION_ON; + state->inversion = INVERSION_OFF; state->voltage = SEC_VOLTAGE_13; state->tone = SEC_TONE_OFF; state->symbol_rate = 29473000; @@ -1174,7 +1224,7 @@ static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status) *status = 0; if (state->diseq_flags & HAS_LOCK) { - dst_get_signal(state); +// dst_get_signal(state); // don't require(?) to ask MCU if (state->decode_lock) *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; } @@ -1208,20 +1258,25 @@ static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet dst_set_freq(state, p->frequency); if (verbose > 4) - dprintk("Set Frequency = [%d]\n", p->frequency); + dprintk("Set Frequency=[%d]\n", p->frequency); - dst_set_inversion(state, p->inversion); +// dst_set_inversion(state, p->inversion); if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + dst_set_inversion(state, p->inversion); + dst_set_fec(state, p->u.qpsk.fec_inner); dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + dst_set_polarization(state); if (verbose > 4) - dprintk("Set Symbolrate = [%d]\n", p->u.qpsk.symbol_rate); + dprintk("Set Symbolrate=[%d]\n", p->u.qpsk.symbol_rate); } else if (state->dst_type == DST_TYPE_IS_TERR) { dst_set_bandwidth(state, p->u.ofdm.bandwidth); } else if (state->dst_type == DST_TYPE_IS_CABLE) { dst_set_fec(state, p->u.qam.fec_inner); dst_set_symbolrate(state, p->u.qam.symbol_rate); + dst_set_modulation(state, p->u.qam.modulation); } dst_write_tuna(fe); @@ -1233,8 +1288,11 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet struct dst_state* state = fe->demodulator_priv; p->frequency = state->decode_freq; - p->inversion = state->inversion; +// p->inversion = state->inversion; if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + p->inversion = state->inversion; + p->u.qpsk.symbol_rate = state->symbol_rate; p->u.qpsk.fec_inner = dst_get_fec(state); } else if (state->dst_type == DST_TYPE_IS_TERR) { @@ -1242,7 +1300,8 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet } else if (state->dst_type == DST_TYPE_IS_CABLE) { p->u.qam.symbol_rate = state->symbol_rate; p->u.qam.fec_inner = dst_get_fec(state); - p->u.qam.modulation = QAM_AUTO; +// p->u.qam.modulation = QAM_AUTO; + p->u.qam.modulation = dst_get_modulation(state); } return 0; diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index d781504cc2f..bfaacd5fc20 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -32,7 +32,7 @@ #include "dst_ca.h" #include "dst_common.h" -static unsigned int verbose = 1; +static unsigned int verbose = 5; module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); @@ -295,34 +295,28 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, return 0; } -static int handle_en50221_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) +static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length) { if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) { hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */ hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */ } else { + hw_buffer->msg[0] = (length & 0xff) + 7; + hw_buffer->msg[1] = 0x40; hw_buffer->msg[2] = 0x03; hw_buffer->msg[3] = 0x00; + hw_buffer->msg[4] = 0x03; + hw_buffer->msg[5] = length & 0xff; + hw_buffer->msg[6] = 0x00; } return 0; } -static int debug_8820_buffer(struct ca_msg *hw_buffer) -{ - unsigned int i; - - dprintk("%s:Debug=[", __FUNCTION__); - for (i = 0; i < (hw_buffer->msg[0] + 1); i++) - dprintk(" %02x", hw_buffer->msg[i]); - dprintk("]\n"); - - return 0; -} -static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 reply) +static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply) { - if ((dst_put_ci(state, hw_buffer->msg, (hw_buffer->length + 1), hw_buffer->msg, reply)) < 0) { + if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) { dprintk("%s: DST-CI Command failed.\n", __FUNCTION__); dprintk("%s: Resetting DST.\n", __FUNCTION__); rdc_reset_state(state); @@ -334,234 +328,141 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 r return 0; } - -static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) +u32 asn_1_decode(u8 *asn_1_array) { - u32 hw_offset, buf_offset, i, k; - u32 program_info_length = 0, es_info_length = 0, length = 0, words = 0; - u8 found_prog_ca_desc = 0, found_stream_ca_desc = 0, error_condition = 0, hw_buffer_length = 0; - - if (verbose > 3) - dprintk("%s, p_ca_message length %d (0x%x)\n", __FUNCTION__,p_ca_message->length,p_ca_message->length ); - - handle_en50221_tag(state, p_ca_message, hw_buffer); /* EN50221 tag */ - - /* Handle the length field (variable) */ - if (!(p_ca_message->msg[3] & 0x80)) { /* Length = 1 */ - length = p_ca_message->msg[3] & 0x7f; - words = 0; /* domi's suggestion */ - } - else { /* Length = words */ - words = p_ca_message->msg[3] & 0x7f; - for (i = 0; i < words; i++) { - length = length << 8; - length = length | p_ca_message->msg[4 + i]; + u8 length_field = 0, word_count = 0, count = 0; + u32 length = 0; + + length_field = asn_1_array[0]; + dprintk("%s: Length field=[%02x]\n", __FUNCTION__, length_field); + if (length_field < 0x80) { + length = length_field & 0x7f; + dprintk("%s: Length=[%02x]\n", __FUNCTION__, length); + } else { + word_count = length_field & 0x7f; + for (count = 0; count < word_count; count++) { + length = (length | asn_1_array[count + 1]) << 8; + dprintk("%s: Length=[%04x]\n", __FUNCTION__, length); } } - if (verbose > 4) { - dprintk("%s:Length=[%d (0x%x)], Words=[%d]\n", __FUNCTION__, length,length, words); - - /* Debug Input string */ - for (i = 0; i < length; i++) - dprintk(" %02x", p_ca_message->msg[i]); - dprintk("]\n"); - } - - hw_offset = 7; - buf_offset = words + 4; - - /* Program Header */ - if (verbose > 4) - dprintk("\n%s:Program Header=[", __FUNCTION__); - for (i = 0; i < 6; i++) { - hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; - if (verbose > 4) - dprintk(" %02x", p_ca_message->msg[buf_offset]); - hw_offset++, buf_offset++, hw_buffer_length++; - } - if (verbose > 4) - dprintk("]\n"); + return length; +} - program_info_length = 0; - program_info_length = (((program_info_length | p_ca_message->msg[words + 8]) & 0x0f) << 8) | p_ca_message->msg[words + 9]; - if (verbose > 4) - dprintk("%s:Program info Length=[%d][%02x], hw_offset=[%d], buf_offset=[%d] \n", - __FUNCTION__, program_info_length, program_info_length, hw_offset, buf_offset); +static int init_buffer(u8 *buffer, u32 length) +{ + u32 i; + for (i = 0; i < length; i++) + buffer[i] = 0; - if (program_info_length && (program_info_length < 256)) { /* If program_info_length */ - hw_buffer->msg[11] = hw_buffer->msg[11] & 0x0f; /* req only 4 bits */ - hw_buffer->msg[12] = hw_buffer->msg[12] + 1; /* increment! ASIC bug! */ + return 0; +} - if (p_ca_message->msg[buf_offset + 1] == 0x09) { /* Check CA descriptor */ - found_prog_ca_desc = 1; - if (verbose > 4) - dprintk("%s: Found CA descriptor @ Program level\n", __FUNCTION__); - } +static int debug_string(u8 *msg, u32 length, u32 offset) +{ + u32 i; - if (found_prog_ca_desc) { /* Command only if CA descriptor */ - hw_buffer->msg[13] = p_ca_message->msg[buf_offset]; /* CA PMT command ID */ - hw_offset++, buf_offset++, hw_buffer_length++; - } + dprintk(" String=[ "); + for (i = offset; i < length; i++) + dprintk("%02x ", msg[i]); + dprintk("]\n"); - /* Program descriptors */ - if (verbose > 4) { - dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset); - dprintk("%s:Program descriptors=[", __FUNCTION__); - } - while (program_info_length && !error_condition) { /* Copy prog descriptors */ - if (program_info_length > p_ca_message->length) { /* Error situation */ - dprintk ("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d]\n", - __FUNCTION__, __LINE__, program_info_length); - dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__); - error_condition = 1; - break; - } + return 0; +} - hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; - dprintk(" %02x", p_ca_message->msg[buf_offset]); - hw_offset++, buf_offset++, hw_buffer_length++, program_info_length--; - } - if (verbose > 4) { - dprintk("]\n"); - dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset); - } - if (found_prog_ca_desc) { - if (!reply) { - hw_buffer->msg[13] = 0x01; /* OK descrambling */ - if (verbose > 1) - dprintk("CA PMT Command = OK Descrambling\n"); - } - else { - hw_buffer->msg[13] = 0x02; /* Ok MMI */ - if (verbose > 1) - dprintk("CA PMT Command = Ok MMI\n"); - } - if (query) { - hw_buffer->msg[13] = 0x03; /* Query */ - if (verbose > 1) - dprintk("CA PMT Command = CA PMT query\n"); - } - } - } - else { - hw_buffer->msg[11] = hw_buffer->msg[11] & 0xf0; /* Don't write to ASIC */ - hw_buffer->msg[12] = hw_buffer->msg[12] = 0x00; +static int copy_string(u8 *destination, u8 *source, u32 dest_offset, u32 source_offset, u32 length) +{ + u32 i; + dprintk("%s: Copying [", __FUNCTION__); + for (i = 0; i < length; i++) { + destination[i + dest_offset] = source[i + source_offset]; + dprintk(" %02x", source[i + source_offset]); } - if (verbose > 4) - dprintk("%s:**********>p_ca_message->length=[%d], buf_offset=[%d], hw_offset=[%d]\n", - __FUNCTION__, p_ca_message->length, buf_offset, hw_offset); - - while ((buf_offset < p_ca_message->length) && !error_condition) { - /* Bail out in case of an indefinite loop */ - if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) { - dprintk("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d], buf_offset=[%d]\n", - __FUNCTION__, __LINE__, program_info_length, buf_offset); - - dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__); - error_condition = 1; - break; - } - - /* Stream Header */ - - for (k = 0; k < 5; k++) { - hw_buffer->msg[hw_offset + k] = p_ca_message->msg[buf_offset + k]; - } + dprintk("]\n"); - es_info_length = 0; - es_info_length = (es_info_length | (p_ca_message->msg[buf_offset + 3] & 0x0f)) << 8 | p_ca_message->msg[buf_offset + 4]; + return i; +} - if (verbose > 4) { - dprintk("\n%s:----->Stream header=[%02x %02x %02x %02x %02x]\n", __FUNCTION__, - p_ca_message->msg[buf_offset + 0], p_ca_message->msg[buf_offset + 1], - p_ca_message->msg[buf_offset + 2], p_ca_message->msg[buf_offset + 3], - p_ca_message->msg[buf_offset + 4]); +static int modify_4_bits(u8 *message, u32 pos) +{ + message[pos] &= 0x0f; - dprintk("%s:----->Stream type=[%02x], es length=[%d (0x%x)], Chars=[%02x] [%02x], buf_offset=[%d]\n", __FUNCTION__, - p_ca_message->msg[buf_offset + 0], es_info_length, es_info_length, - p_ca_message->msg[buf_offset + 3], p_ca_message->msg[buf_offset + 4], buf_offset); - } + return 0; +} - hw_buffer->msg[hw_offset + 3] &= 0x0f; /* req only 4 bits */ - if (found_prog_ca_desc) { - hw_buffer->msg[hw_offset + 3] = 0x00; - hw_buffer->msg[hw_offset + 4] = 0x00; - } - hw_offset += 5, buf_offset += 5, hw_buffer_length += 5; +static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) +{ + u32 length = 0, count = 0; + u8 asn_1_words, program_header_length; + u16 program_info_length = 0, es_info_length = 0; + u32 hw_offset = 0, buf_offset = 0, i; + u8 dst_tag_length; - /* Check for CA descriptor */ - if (p_ca_message->msg[buf_offset + 1] == 0x09) { - if (verbose > 4) - dprintk("%s:Found CA descriptor @ Stream level\n", __FUNCTION__); - found_stream_ca_desc = 1; - } + length = asn_1_decode(&p_ca_message->msg[3]); + dprintk("%s: CA Message length=[%d]\n", __FUNCTION__, length); + dprintk("%s: ASN.1 ", __FUNCTION__); + debug_string(&p_ca_message->msg[4], length, 0); // length does not include tag and length - /* ES descriptors */ - - if (es_info_length && !error_condition && !found_prog_ca_desc && found_stream_ca_desc) { -// if (!ca_pmt_done) { - hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; /* CA PMT cmd(es) */ - if (verbose > 4) - printk("%s:----->CA PMT Command ID=[%02x]\n", __FUNCTION__, p_ca_message->msg[buf_offset]); -// hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--, ca_pmt_done = 1; - hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--; -// } - if (verbose > 4) - dprintk("%s:----->ES descriptors=[", __FUNCTION__); - - while (es_info_length && !error_condition) { /* ES descriptors */ - if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) { - if (verbose > 4) { - dprintk("%s:\"WARNING\" ES Length error, line=[%d], es_info_length=[%d], buf_offset=[%d]\n", - __FUNCTION__, __LINE__, es_info_length, buf_offset); - - dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__); - } - error_condition = 1; - break; - } + init_buffer(hw_buffer->msg, length); + handle_dst_tag(state, p_ca_message, hw_buffer, length); - hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; - if (verbose > 3) - dprintk("%02x ", hw_buffer->msg[hw_offset]); - hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--; - } - found_stream_ca_desc = 0; /* unset for new streams */ - dprintk("]\n"); + hw_offset = 7; + asn_1_words = 1; // just a hack to test, should compute this one + buf_offset = 3; + program_header_length = 6; + dst_tag_length = 7; + +// debug_twinhan_ca_params(state, p_ca_message, hw_buffer, reply, query, length, hw_offset, buf_offset); +// dprintk("%s: Program Header(BUF)", __FUNCTION__); +// debug_string(&p_ca_message->msg[4], program_header_length, 0); +// dprintk("%s: Copying Program header\n", __FUNCTION__); + copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + asn_1_words), program_header_length); + buf_offset += program_header_length, hw_offset += program_header_length; + modify_4_bits(hw_buffer->msg, (hw_offset - 2)); + if (state->type_flags & DST_TYPE_HAS_INC_COUNT) { // workaround + dprintk("%s: Probably an ASIC bug !!!\n", __FUNCTION__); + debug_string(hw_buffer->msg, (hw_offset + program_header_length), 0); + hw_buffer->msg[hw_offset - 1] += 1; + } + +// dprintk("%s: Program Header(HW), Count=[%d]", __FUNCTION__, count); +// debug_string(hw_buffer->msg, hw_offset, 0); + + program_info_length = ((program_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset]; + dprintk("%s: Program info length=[%02x]\n", __FUNCTION__, program_info_length); + if (program_info_length) { + count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + 1), (program_info_length + 1) ); // copy next elem, not current + buf_offset += count, hw_offset += count; +// dprintk("%s: Program level ", __FUNCTION__); +// debug_string(hw_buffer->msg, hw_offset, 0); + } + + buf_offset += 1;// hw_offset += 1; + for (i = buf_offset; i < length; i++) { +// dprintk("%s: Stream Header ", __FUNCTION__); + count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, buf_offset, 5); + modify_4_bits(hw_buffer->msg, (hw_offset + 3)); + + hw_offset += 5, buf_offset += 5, i += 4; +// debug_string(hw_buffer->msg, hw_offset, (hw_offset - 5)); + es_info_length = ((es_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset]; + dprintk("%s: ES info length=[%02x]\n", __FUNCTION__, es_info_length); + if (es_info_length) { + // copy descriptors @ STREAM level + dprintk("%s: Descriptors @ STREAM level...!!! \n", __FUNCTION__); } - } - - /* MCU Magic words */ - - hw_buffer_length += 7; - hw_buffer->msg[0] = hw_buffer_length; - hw_buffer->msg[1] = 64; - hw_buffer->msg[4] = 3; - hw_buffer->msg[5] = hw_buffer->msg[0] - 7; - hw_buffer->msg[6] = 0; - - /* Fix length */ - hw_buffer->length = hw_buffer->msg[0]; - - put_checksum(&hw_buffer->msg[0], hw_buffer->msg[0]); - /* Do the actual write */ - if (verbose > 4) { - dprintk("%s:======================DEBUGGING================================\n", __FUNCTION__); - dprintk("%s: Actual Length=[%d]\n", __FUNCTION__, hw_buffer_length); } - /* Only for debugging! */ - if (verbose > 2) - debug_8820_buffer(hw_buffer); - if (verbose > 3) - dprintk("%s: Reply = [%d]\n", __FUNCTION__, reply); - write_to_8820(state, hw_buffer, reply); + hw_buffer->msg[length + dst_tag_length] = dst_check_sum(hw_buffer->msg, (length + dst_tag_length)); +// dprintk("%s: Total length=[%d], Checksum=[%02x]\n", __FUNCTION__, (length + dst_tag_length), hw_buffer->msg[length + dst_tag_length]); + debug_string(hw_buffer->msg, (length + dst_tag_length + 1), 0); // dst tags also + write_to_8820(state, hw_buffer, (length + dst_tag_length + 1), reply); // checksum return 0; } + /* Board supports CA PMT reply ? */ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer) { @@ -605,7 +506,7 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer; if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { - printk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk("%s: Memory allocation failure\n", __FUNCTION__); return -ENOMEM; } if (verbose > 3) @@ -630,8 +531,10 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, switch (command) { case CA_PMT: if (verbose > 3) +// dprintk("Command = SEND_CA_PMT\n"); dprintk("Command = SEND_CA_PMT\n"); - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { +// if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started dprintk("%s: -->CA_PMT Failed !\n", __FUNCTION__); return -1; } @@ -664,7 +567,7 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, return -1; } if (verbose > 3) - printk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__); + dprintk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__); break; } @@ -681,17 +584,17 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct ca_msg *p_ca_message; if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { - printk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk("%s: Memory allocation failure\n", __FUNCTION__); return -ENOMEM; } if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) { - printk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk("%s: Memory allocation failure\n", __FUNCTION__); return -ENOMEM; } if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) { - printk("%s: Memory allocation failure\n", __FUNCTION__); + dprintk("%s: Memory allocation failure\n", __FUNCTION__); return -ENOMEM; } diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index 0b3da29245f..ef532a6acea 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -47,6 +47,8 @@ #define DST_TYPE_HAS_FW_2 16 #define DST_TYPE_HAS_FW_3 32 #define DST_TYPE_HAS_FW_BUILD 64 +#define DST_TYPE_HAS_OBS_REGS 128 +#define DST_TYPE_HAS_INC_COUNT 256 /* Card capability list */ @@ -110,6 +112,7 @@ struct dst_state { u32 dst_hw_cap; u8 dst_fw_version; fe_sec_mini_cmd_t minicmd; + fe_modulation_t modulation; u8 messages[256]; }; -- cgit v1.2.3 From 3dff919425dd79954447e6ab39807b4c27ba3089 Mon Sep 17 00:00:00 2001 From: Allan Stirling Date: Thu, 7 Jul 2005 17:57:51 -0700 Subject: [PATCH] dvb: Twinhan DST: frontend polarization fix Fix a bug that caused the polarization (V/H) to be interchanged. Signed-off-by: Allan Stirling Signed-off-by: Manu Abraham Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 1f97c37fe9a..d8f4200065e 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -325,12 +325,12 @@ static int dst_set_polarization(struct dst_state *state) switch (state->voltage) { case SEC_VOLTAGE_13: // vertical printk("%s: Polarization=[Vertical]\n", __FUNCTION__); - state->tx_tuna[8] |= 0x40; //1 + state->tx_tuna[8] &= ~0x40; //1 break; case SEC_VOLTAGE_18: // horizontal printk("%s: Polarization=[Horizontal]\n", __FUNCTION__); - state->tx_tuna[8] =~ 0x40; // 0 + state->tx_tuna[8] |= 0x40; // 0 break; case SEC_VOLTAGE_OFF: -- cgit v1.2.3 From 771e71570ce4da549fe89978de0a29e3299d7fb7 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 7 Jul 2005 17:57:52 -0700 Subject: [PATCH] dvb: ttusb-dec: kfree cleanup The Coverity checker discovered that these two kfree's can never be executed. Signed-off-by: Adrian Bunk Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttusb-dec/ttusbdecfe.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c index 1699cc9f6bb..725af3af5b2 100644 --- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c @@ -157,7 +157,8 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf /* allocate memory for the internal state */ state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (state == NULL) + return NULL; /* setup the state */ state->config = config; @@ -167,10 +168,6 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops ttusbdecfe_dvbs_ops; @@ -181,7 +178,8 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf /* allocate memory for the internal state */ state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (state == NULL) + return NULL; /* setup the state */ state->config = config; @@ -193,10 +191,6 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { -- cgit v1.2.3 From 96bf2f2b549aab918f4225841df54c3d58896822 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Thu, 7 Jul 2005 17:57:53 -0700 Subject: [PATCH] dvb: ttpci: add support for Technotrend/Hauppauge DVB-S SE Add support for s5h1420 frontend (new Technotrend/Hauppauge DVB-S SE). Signed-off-by: Andrew de Quincey Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/Kconfig | 6 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/s5h1420.c | 800 ++++++++++++++++++++++++++++++++++ drivers/media/dvb/frontends/s5h1420.h | 41 ++ drivers/media/dvb/ttpci/Kconfig | 9 +- drivers/media/dvb/ttpci/budget.c | 99 +++++ 6 files changed, 952 insertions(+), 4 deletions(-) create mode 100644 drivers/media/dvb/frontends/s5h1420.c create mode 100644 drivers/media/dvb/frontends/s5h1420.h (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index b4fddf513eb..5c695937e2a 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -40,6 +40,12 @@ config DVB_VES1X93 help A DVB-S tuner module. Say Y when you want to support this frontend. +config DVB_S5H1420 + tristate "Samsung S5H1420 based" + depends on DVB_CORE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + comment "DVB-T (terrestrial) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 91d6d3576d3..8d46dd721f4 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_DVB_NXT2002) += nxt2002.o obj-$(CONFIG_DVB_OR51211) += or51211.o obj-$(CONFIG_DVB_OR51132) += or51132.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o +obj-$(CONFIG_DVB_S5H1420) += s5h1420.o diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c new file mode 100644 index 00000000000..4f396ac8de7 --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -0,0 +1,800 @@ +/* +Driver for Samsung S5H1420 QPSK Demodulator + +Copyright (C) 2005 Andrew de Quincey + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "s5h1420.h" + + + +#define TONE_FREQ 22000 + +struct s5h1420_state { + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; + const struct s5h1420_config* config; + struct dvb_frontend frontend; + + u8 postlocked:1; + u32 fclk; + u32 tunedfreq; + fe_code_rate_t fec_inner; + u32 symbol_rate; +}; + +static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); +static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings); + + +static int debug = 0; +#define dprintk if (debug) printk + +static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data) +{ + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + int err; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +static u8 s5h1420_readreg (struct s5h1420_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg1 = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }; + struct i2c_msg msg2 = { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }; + + if ((ret = i2c_transfer (state->i2c, &msg1, 1)) != 1) + return ret; + + if ((ret = i2c_transfer (state->i2c, &msg2, 1)) != 1) + return ret; + + return b1[0]; +} + +static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + switch(voltage) { + case SEC_VOLTAGE_13: + s5h1420_writereg(state, 0x3c, (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02); + break; + + case SEC_VOLTAGE_18: + s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03); + break; + + case SEC_VOLTAGE_OFF: + s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd); + break; + } + + return 0; +} + +static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + switch(tone) { + case SEC_TONE_ON: + s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08); + break; + + case SEC_TONE_OFF: + s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01); + break; + } + + return 0; +} + +static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + int i; + unsigned long timeout; + int result = 0; + + /* setup for DISEQC */ + val = s5h1420_readreg(state, 0x3b); + s5h1420_writereg(state, 0x3b, 0x02); + msleep(15); + + /* write the DISEQC command bytes */ + for(i=0; i< cmd->msg_len; i++) { + s5h1420_writereg(state, 0x3c + i, cmd->msg[i]); + } + + /* kick off transmission */ + s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | ((cmd->msg_len-1) << 4) | 0x08); + + /* wait for transmission to complete */ + timeout = jiffies + ((100*HZ) / 1000); + while(time_before(jiffies, timeout)) { + if (s5h1420_readreg(state, 0x3b) & 0x08) + break; + + msleep(5); + } + if (time_after(jiffies, timeout)) + result = -ETIMEDOUT; + + /* restore original settings */ + s5h1420_writereg(state, 0x3b, val); + msleep(15); + return result; +} + +static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + int i; + int length; + unsigned long timeout; + int result = 0; + + /* setup for DISEQC recieve */ + val = s5h1420_readreg(state, 0x3b); + s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */ + msleep(15); + + /* wait for reception to complete */ + timeout = jiffies + ((reply->timeout*HZ) / 1000); + while(time_before(jiffies, timeout)) { + if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */ + break; + + msleep(5); + } + if (time_after(jiffies, timeout)) { + result = -ETIMEDOUT; + goto exit; + } + + /* check error flag - FIXME: not sure what this does - docs do not describe + * beyond "error flag for diseqc receive data :( */ + if (s5h1420_readreg(state, 0x49)) { + result = -EIO; + goto exit; + } + + /* check length */ + length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4; + if (length > sizeof(reply->msg)) { + result = -EOVERFLOW; + goto exit; + } + reply->msg_len = length; + + /* extract data */ + for(i=0; i< length; i++) { + reply->msg[i] = s5h1420_readreg(state, 0x3c + i); + } + +exit: + /* restore original settings */ + s5h1420_writereg(state, 0x3b, val); + msleep(15); + return result; +} + +static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + int result = 0; + unsigned long timeout; + + /* setup for tone burst */ + val = s5h1420_readreg(state, 0x3b); + s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01); + + /* set value for B position if requested */ + if (minicmd == SEC_MINI_B) { + s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04); + } + msleep(15); + + /* start transmission */ + s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08); + + /* wait for transmission to complete */ + timeout = jiffies + ((20*HZ) / 1000); + while(time_before(jiffies, timeout)) { + if (!(s5h1420_readreg(state, 0x3b) & 0x08)) + break; + + msleep(5); + } + if (time_after(jiffies, timeout)) + result = -ETIMEDOUT; + + /* restore original settings */ + s5h1420_writereg(state, 0x3b, val); + msleep(15); + return result; +} + +static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state) +{ + u8 val; + fe_status_t status = 0; + + val = s5h1420_readreg(state, 0x14); + if (val & 0x02) + status |= FE_HAS_SIGNAL; // FIXME: not sure if this is right + if (val & 0x01) + status |= FE_HAS_CARRIER; // FIXME: not sure if this is right + val = s5h1420_readreg(state, 0x36); + if (val & 0x01) + status |= FE_HAS_VITERBI; + if (val & 0x20) + status |= FE_HAS_SYNC; + if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC)) + status |= FE_HAS_LOCK; + + return status; +} + +static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u8 val; + + if (status == NULL) + return -EINVAL; + + /* determine lock state */ + *status = s5h1420_get_status_bits(state); + + /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert the inversion, + wait a bit and check again */ + if (*status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI)) { + val = s5h1420_readreg(state, 0x32); + if ((val & 0x07) == 0x03) { + if (val & 0x08) + s5h1420_writereg(state, 0x31, 0x13); + else + s5h1420_writereg(state, 0x31, 0x1b); + + /* wait a bit then update lock status */ + mdelay(200); + *status = s5h1420_get_status_bits(state); + } + } + + /* perform post lock setup */ + if ((*status & FE_HAS_LOCK) && (!state->postlocked)) { + + /* calculate the data rate */ + u32 tmp = s5h1420_getsymbolrate(state); + switch(s5h1420_readreg(state, 0x32) & 0x07) { + case 0: + tmp = (tmp * 2 * 1) / 2; + break; + + case 1: + tmp = (tmp * 2 * 2) / 3; + break; + + case 2: + tmp = (tmp * 2 * 3) / 4; + break; + + case 3: + tmp = (tmp * 2 * 5) / 6; + break; + + case 4: + tmp = (tmp * 2 * 6) / 7; + break; + + case 5: + tmp = (tmp * 2 * 7) / 8; + break; + } + tmp = state->fclk / tmp; + + /* set the MPEG_CLK_INTL for the calculated data rate */ + if (tmp < 4) + val = 0x00; + else if (tmp < 8) + val = 0x01; + else if (tmp < 12) + val = 0x02; + else if (tmp < 16) + val = 0x03; + else if (tmp < 24) + val = 0x04; + else if (tmp < 32) + val = 0x05; + else + val = 0x06; + s5h1420_writereg(state, 0x22, val); + + /* DC freeze */ + s5h1420_writereg(state, 0x1f, s5h1420_readreg(state, 0x1f) | 0x01); + + /* kicker disable + remove DC offset */ + s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) & 0x6f); + + /* post-lock processing has been done! */ + state->postlocked = 1; + } + + return 0; +} + +static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + s5h1420_writereg(state, 0x46, 0x1d); + mdelay(25); + return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); +} + +static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + u8 val = 0xff - s5h1420_readreg(state, 0x15); + + return (int) ((val << 8) | val); +} + +static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + s5h1420_writereg(state, 0x46, 0x1f); + mdelay(25); + return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); +} + +static void s5h1420_reset(struct s5h1420_state* state) +{ + s5h1420_writereg (state, 0x01, 0x08); + s5h1420_writereg (state, 0x01, 0x00); + udelay(10); +} + +static void s5h1420_setsymbolrate(struct s5h1420_state* state, struct dvb_frontend_parameters *p) +{ + u64 val; + + val = (p->u.qpsk.symbol_rate / 1000) * (1<<24); + if (p->u.qpsk.symbol_rate <= 21000000) { + val *= 2; + } + do_div(val, (state->fclk / 1000)); + + s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f); + s5h1420_writereg(state, 0x11, val >> 16); + s5h1420_writereg(state, 0x12, val >> 8); + s5h1420_writereg(state, 0x13, val & 0xff); + s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80); +} + +static u32 s5h1420_getsymbolrate(struct s5h1420_state* state) +{ + u64 val; + int sampling = 2; + + if (s5h1420_readreg(state, 0x05) & 0x2) + sampling = 1; + + s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08); + val = s5h1420_readreg(state, 0x11) << 16; + val |= s5h1420_readreg(state, 0x12) << 8; + val |= s5h1420_readreg(state, 0x13); + s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7); + + val *= (state->fclk / 1000); + do_div(val, ((1<<24) * sampling)); + + return (u32) (val * 1000); +} + +static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset) +{ + int val; + + /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so + * divide fclk by 1000000 to get the correct value. */ + val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000)); + + s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0xbf); + s5h1420_writereg(state, 0x0e, val >> 16); + s5h1420_writereg(state, 0x0f, val >> 8); + s5h1420_writereg(state, 0x10, val & 0xff); + s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x40); +} + +static int s5h1420_getfreqoffset(struct s5h1420_state* state) +{ + int val; + + s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08); + val = s5h1420_readreg(state, 0x0e) << 16; + val |= s5h1420_readreg(state, 0x0f) << 8; + val |= s5h1420_readreg(state, 0x10); + s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7); + + if (val & 0x800000) + val |= 0xff000000; + + /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so + * divide fclk by 1000000 to get the correct value. */ + val = - ((val * (state->fclk/1000000)) / (1<<24)); + + return val; +} + +static void s5h1420_setfec(struct s5h1420_state* state, struct dvb_frontend_parameters *p) +{ + if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { + s5h1420_writereg(state, 0x31, 0x00); + s5h1420_writereg(state, 0x30, 0x3f); + } else { + switch(p->u.qpsk.fec_inner) { + case FEC_1_2: + s5h1420_writereg(state, 0x31, 0x10); + s5h1420_writereg(state, 0x30, 0x01); + break; + + case FEC_2_3: + s5h1420_writereg(state, 0x31, 0x11); + s5h1420_writereg(state, 0x30, 0x02); + break; + + case FEC_3_4: + s5h1420_writereg(state, 0x31, 0x12); + s5h1420_writereg(state, 0x30, 0x04); + break; + + case FEC_5_6: + s5h1420_writereg(state, 0x31, 0x13); + s5h1420_writereg(state, 0x30, 0x08); + break; + + case FEC_6_7: + s5h1420_writereg(state, 0x31, 0x14); + s5h1420_writereg(state, 0x30, 0x10); + break; + + case FEC_7_8: + s5h1420_writereg(state, 0x31, 0x15); + s5h1420_writereg(state, 0x30, 0x20); + break; + + default: + return; + } + } +} + +static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) +{ + switch(s5h1420_readreg(state, 0x32) & 0x07) { + case 0: + return FEC_1_2; + + case 1: + return FEC_2_3; + + case 2: + return FEC_3_4; + + case 3: + return FEC_5_6; + + case 4: + return FEC_6_7; + + case 5: + return FEC_7_8; + } + + return FEC_NONE; +} + +static void s5h1420_setinversion(struct s5h1420_state* state, struct dvb_frontend_parameters *p) +{ + if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { + s5h1420_writereg(state, 0x31, 0x00); + s5h1420_writereg(state, 0x30, 0x3f); + } else { + u8 tmp = s5h1420_readreg(state, 0x31) & 0xf7; + tmp |= 0x10; + + if (p->inversion == INVERSION_ON) + tmp |= 0x80; + + s5h1420_writereg(state, 0x31, tmp); + } +} + +static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) +{ + if (s5h1420_readreg(state, 0x32) & 0x08) + return INVERSION_ON; + + return INVERSION_OFF; +} + +static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct s5h1420_state* state = fe->demodulator_priv; + u32 frequency_delta; + struct dvb_frontend_tune_settings fesettings; + + /* check if we should do a fast-tune */ + memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); + s5h1420_get_tune_settings(fe, &fesettings); + frequency_delta = p->frequency - state->tunedfreq; + if ((frequency_delta > -fesettings.max_drift) && (frequency_delta < fesettings.max_drift) && + (frequency_delta != 0) && + (state->fec_inner == p->u.qpsk.fec_inner) && + (state->symbol_rate == p->u.qpsk.symbol_rate)) { + + s5h1420_setfreqoffset(state, frequency_delta); + return 0; + } + + /* first of all, software reset */ + s5h1420_reset(state); + + /* set tuner PLL */ + if (state->config->pll_set) { + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); + state->config->pll_set(fe, p, &state->tunedfreq); + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe); + } + + /* set s5h1420 fclk PLL according to desired symbol rate */ + if (p->u.qpsk.symbol_rate > 28000000) { + state->fclk = 88000000; + s5h1420_writereg(state, 0x03, 0x50); + s5h1420_writereg(state, 0x04, 0x40); + s5h1420_writereg(state, 0x05, 0xae); + } else if (p->u.qpsk.symbol_rate > 21000000) { + state->fclk = 59000000; + s5h1420_writereg(state, 0x03, 0x33); + s5h1420_writereg(state, 0x04, 0x40); + s5h1420_writereg(state, 0x05, 0xae); + } else { + state->fclk = 88000000; + s5h1420_writereg(state, 0x03, 0x50); + s5h1420_writereg(state, 0x04, 0x40); + s5h1420_writereg(state, 0x05, 0xac); + } + + /* set misc registers */ + s5h1420_writereg(state, 0x02, 0x00); + s5h1420_writereg(state, 0x07, 0xb0); + s5h1420_writereg(state, 0x0a, 0x67); + s5h1420_writereg(state, 0x0b, 0x78); + s5h1420_writereg(state, 0x0c, 0x48); + s5h1420_writereg(state, 0x0d, 0x6b); + s5h1420_writereg(state, 0x2e, 0x8e); + s5h1420_writereg(state, 0x35, 0x33); + s5h1420_writereg(state, 0x38, 0x01); + s5h1420_writereg(state, 0x39, 0x7d); + s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); + s5h1420_writereg(state, 0x3c, 0x00); + s5h1420_writereg(state, 0x45, 0x61); + s5h1420_writereg(state, 0x46, 0x1d); + + /* start QPSK */ + s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1); + + /* set the frequency offset to adjust for PLL inaccuracy */ + s5h1420_setfreqoffset(state, p->frequency - state->tunedfreq); + + /* set the reset of the parameters */ + s5h1420_setsymbolrate(state, p); + s5h1420_setinversion(state, p); + s5h1420_setfec(state, p); + + state->fec_inner = p->u.qpsk.fec_inner; + state->symbol_rate = p->u.qpsk.symbol_rate; + state->postlocked = 0; + return 0; +} + +static int s5h1420_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state); + p->inversion = s5h1420_getinversion(state); + p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state); + p->u.qpsk.fec_inner = s5h1420_getfec(state); + + return 0; +} + +static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { + fesettings->min_delay_ms = 50; + fesettings->step_size = 2000; + fesettings->max_drift = 8000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1500; + fesettings->max_drift = 9000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 1000; + fesettings->max_drift = 8000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { + fesettings->min_delay_ms = 100; + fesettings->step_size = 500; + fesettings->max_drift = 7000; + } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->max_drift = 14 * fesettings->step_size; + } else { + fesettings->min_delay_ms = 200; + fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->max_drift = 18 * fesettings->step_size; + } + + return 0; +} + +static int s5h1420_init (struct dvb_frontend* fe) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + /* disable power down and do reset */ + s5h1420_writereg(state, 0x02, 0x10); + msleep(10); + s5h1420_reset(state); + + /* init PLL */ + if (state->config->pll_init) { + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); + state->config->pll_init(fe); + s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe); + } + + return 0; +} + +static int s5h1420_sleep(struct dvb_frontend* fe) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + return s5h1420_writereg(state, 0x02, 0x12); +} + +static void s5h1420_release(struct dvb_frontend* fe) +{ + struct s5h1420_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops s5h1420_ops; + +struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, struct i2c_adapter* i2c) +{ + struct s5h1420_state* state = NULL; + u8 identity; + + /* allocate memory for the internal state */ + state = kmalloc(sizeof(struct s5h1420_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops)); + state->postlocked = 0; + state->fclk = 88000000; + state->tunedfreq = 0; + state->fec_inner = FEC_NONE; + state->symbol_rate = 0; + + /* check if the demod is there + identify it */ + identity = s5h1420_readreg(state, 0x00); + if (identity != 0x03) + goto error; + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static struct dvb_frontend_ops s5h1420_ops = { + + .info = { + .name = "Samsung S5H1420 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + /* .symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = s5h1420_release, + + .init = s5h1420_init, + .sleep = s5h1420_sleep, + + .set_frontend = s5h1420_set_frontend, + .get_frontend = s5h1420_get_frontend, + .get_tune_settings = s5h1420_get_tune_settings, + + .read_status = s5h1420_read_status, + .read_ber = s5h1420_read_ber, + .read_signal_strength = s5h1420_read_signal_strength, + .read_ucblocks = s5h1420_read_ucblocks, + + .diseqc_send_master_cmd = s5h1420_send_master_cmd, + .diseqc_recv_slave_reply = s5h1420_recv_slave_reply, + .diseqc_send_burst = s5h1420_send_burst, + .set_tone = s5h1420_set_tone, + .set_voltage = s5h1420_set_voltage, +}; + +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("Samsung S5H1420 DVB-S Demodulator driver"); +MODULE_AUTHOR("Andrew de Quincey"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(s5h1420_attach); diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h new file mode 100644 index 00000000000..b687fc77ceb --- /dev/null +++ b/drivers/media/dvb/frontends/s5h1420.h @@ -0,0 +1,41 @@ +/* + Driver for S5H1420 QPSK Demodulators + + Copyright (C) 2005 Andrew de Quincey + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef S5H1420_H +#define S5H1420_H + +#include + +struct s5h1420_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout); +}; + +extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, + struct i2c_adapter* i2c); + +#endif // S5H1420_H diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 7ffa2c7315b..bf3c011d2cf 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -12,7 +12,7 @@ config DVB_AV7110 select DVB_STV0297 select DVB_L64781 help - Support for SAA7146 and AV7110 based DVB cards as produced + Support for SAA7146 and AV7110 based DVB cards as produced by Fujitsu-Siemens, Technotrend, Hauppauge and others. This driver only supports the fullfeatured cards with @@ -33,7 +33,7 @@ config DVB_AV7110_FIRMWARE If you want to compile the firmware into the driver you need to say Y here and provide the correct path of the firmware. You need this option if you want to compile the whole driver statically into the - kernel. + kernel. All other people say N. @@ -66,6 +66,7 @@ config DVB_BUDGET select DVB_L64781 select DVB_TDA8083 select DVB_TDA10021 + select DVB_S5H1420 help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard @@ -119,9 +120,9 @@ config DVB_BUDGET_PATCH select DVB_VES1X93 select DVB_TDA8083 help - Support for Budget Patch (full TS) modification on + Support for Budget Patch (full TS) modification on SAA7146+AV7110 based cards (DVB-S cards). This - driver doesn't use onboard MPEG2 decoder. The + driver doesn't use onboard MPEG2 decoder. The card is driven in Budget-only mode. Card is required to have loaded firmware to tune properly. Firmware can be loaded by insertion and removal of diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 083fd44e5f9..9961917e8a7 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -40,6 +40,7 @@ #include "ves1820.h" #include "l64781.h" #include "tda8083.h" +#include "s5h1420.h" static void Set22K (struct budget *budget, int state) { @@ -177,6 +178,62 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m return 0; } +static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u8 buf; + struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) }; + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + switch(voltage) { + case SEC_VOLTAGE_13: + buf = (buf & 0xf7) | 0x04; + break; + + case SEC_VOLTAGE_18: + buf = (buf & 0xf7) | 0x0c; + break; + + case SEC_VOLTAGE_OFF: + buf = buf & 0xf0; + break; + } + + msg.flags = 0; + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + return 0; +} + +static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u8 buf; + struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) }; + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + if (arg) { + buf = buf | 0x10; + } else { + buf = buf & 0xef; + } + + msg.flags = 0; + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + return 0; +} + +static void lnbp21_init(struct budget* budget) +{ + u8 buf = 0x00; + struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) }; + + i2c_transfer (&budget->i2c_adap, &msg, 1); +} + static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct budget* budget = (struct budget*) fe->dvb->priv; @@ -395,6 +452,38 @@ static struct tda8083_config grundig_29504_451_config = { .pll_set = grundig_29504_451_pll_set, }; +static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = params->frequency / 1000; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xc2; + + if (div < 1450) + data[3] = 0x00; + else if (div < 1850) + data[3] = 0x40; + else if (div < 2000) + data[3] = 0x80; + else + data[3] = 0xc0; + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + + *freqout = div * 1000; + return 0; +} + +static struct s5h1420_config s5h1420_config = { + .demod_address = 0x53, + .pll_set = s5h1420_pll_set, +}; + static u8 read_pwm(struct budget* budget) { u8 b = 0xff; @@ -459,6 +548,15 @@ static void frontend_init(struct budget *budget) break; } break; + + case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260)) + budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage; + budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; + lnbp21_init(budget); + break; + } } if (budget->dvb_frontend == NULL) { @@ -532,6 +630,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), + MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016), MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), { -- cgit v1.2.3 From dd2bbb179326d23577ff8201c4f20e0db3e87f7b Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Thu, 7 Jul 2005 17:57:54 -0700 Subject: [PATCH] dvb: ttpci: support for new TT DVB-T-CI Support for new TT DVB-T-CI, thanks to Andre Weidemann Signed-off-by: Andrew de Quincey Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/budget-ci.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 075eb40f5c1..a1267054bc0 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -69,6 +69,7 @@ struct budget_ci { int slot_status; struct dvb_ca_en50221 ca; char ir_dev_name[50]; + u8 tuner_pll_address; /* used for philips_tdm1316l configs */ }; /* from reading the following remotes: @@ -723,7 +724,7 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe) struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; - struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = td1316_init,.len = + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len = sizeof(td1316_init) }; // setup PLL configuration @@ -746,7 +747,7 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend { struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; + struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; int tuner_frequency = 0; u8 band, cp, filter; @@ -869,12 +870,22 @@ static void frontend_init(struct budget_ci *budget_ci) break; case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) + budget_ci->tuner_pll_address = 0x63; budget_ci->budget.dvb_frontend = tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap); if (budget_ci->budget.dvb_frontend) { break; } break; + + case 0x1012: // Hauppauge/TT Nova-T CI budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) + budget_ci->tuner_pll_address = 0x60; + budget_ci->budget.dvb_frontend = + tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + break; + } + break; } if (budget_ci->budget.dvb_frontend == NULL) { @@ -954,11 +965,13 @@ static struct saa7146_extension budget_extension; MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), + MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), { .vendor = 0, } -- cgit v1.2.3 From c9090ebb247999354f80d45d45b3d5a804a94f7f Mon Sep 17 00:00:00 2001 From: Wolfgang Rohdewald Date: Thu, 7 Jul 2005 17:57:55 -0700 Subject: [PATCH] dvb: ttpci: fix error handling for firmware communication o make sure ERESTARTSYS will be propagated o ReleaseBitmap: starting with Firmware 261e, also release when BMP_LOADING o removes unused #define BMP_LOADINGS o in many cases changed the return value from -1 to something more meaningful like ETIMEDOUT, EINVAL o changed syslog message timeout waiting for COMMAND such that it indicates what command did not complete o reduce # of arguments for LoadBitmap and BlitBitmap o av7110_osd_cmd: remove the out: label Signed-off-by: Wolfgang Rohdewald Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110.h | 3 +- drivers/media/dvb/ttpci/av7110_hw.c | 309 +++++++++++++++++++----------------- 2 files changed, 163 insertions(+), 149 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 4f69b4d0147..e54222d9b3f 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -119,8 +119,7 @@ struct av7110 { volatile int bmp_state; #define BMP_NONE 0 #define BMP_LOADING 1 -#define BMP_LOADINGS 2 -#define BMP_LOADED 3 +#define BMP_LOADED 2 wait_queue_head_t bmpq; diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 7fa4a0ebe13..7d2bdd791c9 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -137,7 +137,7 @@ static int waitdebi(struct av7110 *av7110, int adr, int state) return 0; udelay(5); } - return -1; + return -ETIMEDOUT; } static int load_dram(struct av7110 *av7110, u32 *data, int len) @@ -155,7 +155,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len) for (i = 0; i < blocks; i++) { if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i); - return -1; + return -ETIMEDOUT; } dprintk(4, "writing DRAM block %d\n", i); mwdebi(av7110, DEBISWAB, bootblock, @@ -170,7 +170,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len) if (rest > 0) { if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n"); - return -1; + return -ETIMEDOUT; } if (rest > 4) mwdebi(av7110, DEBISWAB, bootblock, @@ -185,13 +185,13 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len) } if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n"); - return -1; + return -ETIMEDOUT; } iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2); iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0) { printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n"); - return -1; + return -ETIMEDOUT; } return 0; } @@ -263,7 +263,7 @@ int av7110_bootarm(struct av7110 *av7110) if (saa7146_wait_for_debi_done(av7110->dev, 1)) { printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " "saa7146_wait_for_debi_done() timed out\n"); - return -1; + return -ETIMEDOUT; } saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); mdelay(1); @@ -284,7 +284,7 @@ int av7110_bootarm(struct av7110 *av7110) if (saa7146_wait_for_debi_done(av7110->dev, 1)) { printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " "saa7146_wait_for_debi_done() timed out after loading DRAM\n"); - return -1; + return -ETIMEDOUT; } saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); msleep(30); /* the firmware needs some time to initialize */ @@ -328,7 +328,7 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n", __FUNCTION__, stat & flags); - return -1; + return -ETIMEDOUT; } msleep(1); } @@ -412,7 +412,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n", __FUNCTION__, type); - return -1; + return -ETIMEDOUT; } msleep(1); } @@ -435,8 +435,10 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) { msleep(1); if (time_after(jiffies, start + ARM_WAIT_FREE)) { - printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND to complete\n", - __FUNCTION__); + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", + __FUNCTION__, + (buf[0] >> 8) & 0xff + ); return -ETIMEDOUT; } } @@ -470,7 +472,7 @@ static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) ret = __av7110_send_fw_cmd(av7110, buf, length); up(&av7110->dcomlock); - if (ret) + if (ret && ret!=-ERESTARTSYS) printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n", __FUNCTION__, ret); return ret; @@ -495,7 +497,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...) } ret = av7110_send_fw_cmd(av7110, buf, num + 2); - if (ret) + if (ret && ret != -ERESTARTSYS) printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret); return ret; } @@ -518,7 +520,7 @@ int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len) } ret = av7110_send_fw_cmd(av7110, cmd, 18); - if (ret) + if (ret && ret != -ERESTARTSYS) printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret); return ret; } @@ -558,7 +560,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__); up(&av7110->dcomlock); - return -1; + return -ETIMEDOUT; } } @@ -569,7 +571,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); - return -1; + return -ETIMEDOUT; } } #endif @@ -667,10 +669,10 @@ int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long bu for (i = 0; i < len; i++) buf[i + 4] = msg[i]; - if ((ret = av7110_send_fw_cmd(av7110, buf, 18))) + ret = av7110_send_fw_cmd(av7110, buf, 18); + if (ret && ret!=-ERESTARTSYS) printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret); - - return 0; + return ret; } @@ -715,7 +717,7 @@ static int FlushText(struct av7110 *av7110) printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); - return -1; + return -ETIMEDOUT; } } up(&av7110->dcomlock); @@ -739,7 +741,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); - return -1; + return -ETIMEDOUT; } } #ifndef _NOHANDSHAKE @@ -750,7 +752,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); - return -1; + return -ETIMEDOUT; } } #endif @@ -761,7 +763,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2); ret = __av7110_send_fw_cmd(av7110, cbuf, 5); up(&av7110->dcomlock); - if (ret) + if (ret && ret!=-ERESTARTSYS) printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret); return ret; } @@ -816,9 +818,25 @@ static osd_raw_window_t bpp2bit[8] = { OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8 }; -static inline int LoadBitmap(struct av7110 *av7110, u16 format, +static inline int WaitUntilBmpLoaded(struct av7110 *av7110) +{ + int ret = wait_event_interruptible_timeout(av7110->bmpq, + av7110->bmp_state != BMP_LOADING, 10*HZ); + if (ret == -ERESTARTSYS) + return ret; + if (ret == 0) { + printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", + ret, av7110->bmp_state); + av7110->bmp_state = BMP_NONE; + return -ETIMEDOUT; + } + return 0; +} + +static inline int LoadBitmap(struct av7110 *av7110, u16 dx, u16 dy, int inc, u8 __user * data) { + u16 format; int bpp; int i; int d, delta; @@ -827,14 +845,7 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format, dprintk(4, "%p\n", av7110); - ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ); - if (ret == -ERESTARTSYS || ret == 0) { - printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", - ret, av7110->bmp_state); - av7110->bmp_state = BMP_NONE; - return -1; - } - BUG_ON (av7110->bmp_state == BMP_LOADING); + format = bpp2bit[av7110->osdbpp[av7110->osdwin]]; av7110->bmp_state = BMP_LOADING; if (format == OSD_BITMAP8) { @@ -847,18 +858,18 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format, bpp=1; delta = 8; } else { av7110->bmp_state = BMP_NONE; - return -1; + return -EINVAL; } av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8; av7110->bmpp = 0; if (av7110->bmplen > 32768) { av7110->bmp_state = BMP_NONE; - return -1; + return -EINVAL; } for (i = 0; i < dy; i++) { if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) { av7110->bmp_state = BMP_NONE; - return -1; + return -EINVAL; } } if (format != OSD_BITMAP8) { @@ -873,37 +884,27 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format, } av7110->bmplen += 1024; dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen); - return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); + ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); + if (!ret) + ret = WaitUntilBmpLoaded(av7110); + return ret; } -static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans) +static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y) { - int ret; - dprintk(4, "%p\n", av7110); - BUG_ON (av7110->bmp_state == BMP_NONE); - - ret = wait_event_interruptible_timeout(av7110->bmpq, - av7110->bmp_state != BMP_LOADING, 10*HZ); - if (ret == -ERESTARTSYS || ret == 0) { - printk("dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d\n", - ret, av7110->bmp_state); - av7110->bmp_state = BMP_NONE; - return (ret == 0) ? -ETIMEDOUT : ret; - } - - BUG_ON (av7110->bmp_state != BMP_LOADED); - - return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans); + return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0); } static inline int ReleaseBitmap(struct av7110 *av7110) { dprintk(4, "%p\n", av7110); - if (av7110->bmp_state != BMP_LOADED) + if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e) return -1; + if (av7110->bmp_state == BMP_LOADING) + dprintk(1,"ReleaseBitmap called while BMP_LOADING\n"); av7110->bmp_state = BMP_NONE; return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0); } @@ -924,18 +925,22 @@ static u32 RGB2YUV(u16 R, u16 G, u16 B) return Cr | (Cb << 16) | (Y << 8); } -static void OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend) +static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend) { + int ret; + u16 ch, cl; u32 yuv; yuv = blend ? RGB2YUV(r,g,b) : 0; cl = (yuv & 0xffff); ch = ((yuv >> 16) & 0xffff); - SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], - color, ch, cl); - SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], - color, ((blend >> 4) & 0x0f)); + ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], + color, ch, cl); + if (!ret) + ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], + color, ((blend >> 4) & 0x0f)); + return ret; } static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) @@ -968,14 +973,14 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, { uint w, h, bpp, bpl, size, lpb, bnum, brest; int i; - int rc; + int rc,release_rc; w = x1 - x0 + 1; h = y1 - y0 + 1; if (inc <= 0) inc = w; if (w <= 0 || w > 720 || h <= 0 || h > 576) - return -1; + return -EINVAL; bpp = av7110->osdbpp[av7110->osdwin] + 1; bpl = ((w * bpp + 7) & ~7) / 8; size = h * bpl; @@ -983,176 +988,186 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, bnum = size / (lpb * bpl); brest = size - bnum * lpb * bpl; - for (i = 0; i < bnum; i++) { - rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]], - w, lpb, inc, data); - if (rc) - return rc; - rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0); + if (av7110->bmp_state == BMP_LOADING) { + /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */ + BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e); + rc = WaitUntilBmpLoaded(av7110); if (rc) return rc; - data += lpb * inc; + /* just continue. This should work for all fw versions + * if bnum==1 && !brest && LoadBitmap was successful + */ } - if (brest) { - rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]], - w, brest / bpl, inc, data); + + rc = 0; + for (i = 0; i < bnum; i++) { + rc = LoadBitmap(av7110, w, lpb, inc, data); if (rc) - return rc; - rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0); + break; + rc = BlitBitmap(av7110, x0, y0 + i * lpb); if (rc) - return rc; + break; + data += lpb * inc; } - ReleaseBitmap(av7110); - return 0; + if (!rc && brest) { + rc = LoadBitmap(av7110, w, brest / bpl, inc, data); + if (!rc) + rc = BlitBitmap(av7110, x0, y0 + bnum * lpb); + } + release_rc = ReleaseBitmap(av7110); + if (!rc) + rc = release_rc; + if (rc) + dprintk(1,"returns %d\n",rc); + return rc; } int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc) { int ret; - ret = down_interruptible(&av7110->osd_sema); - if (ret) + if (down_interruptible(&av7110->osd_sema)) return -ERESTARTSYS; - /* stupid, but OSD functions don't provide a return code anyway */ - ret = 0; - switch (dc->cmd) { case OSD_Close: - DestroyOSDWindow(av7110, av7110->osdwin); - goto out; + ret = DestroyOSDWindow(av7110, av7110->osdwin); + break; case OSD_Open: av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7; - CreateOSDWindow(av7110, av7110->osdwin, + ret = CreateOSDWindow(av7110, av7110->osdwin, bpp2bit[av7110->osdbpp[av7110->osdwin]], dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); + if (ret) + break; if (!dc->data) { - MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - SetColorBlend(av7110, av7110->osdwin); + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (ret) + break; + ret = SetColorBlend(av7110, av7110->osdwin); } - goto out; + break; case OSD_Show: - MoveWindowRel(av7110, av7110->osdwin, 0, 0); - goto out; + ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0); + break; case OSD_Hide: - HideWindow(av7110, av7110->osdwin); - goto out; + ret = HideWindow(av7110, av7110->osdwin); + break; case OSD_Clear: - DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0); - goto out; + ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0); + break; case OSD_Fill: - DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color); - goto out; + ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color); + break; case OSD_SetColor: - OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1); - goto out; + ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1); + break; case OSD_SetPalette: - { - if (FW_VERSION(av7110->arm_app) >= 0x2618) { + if (FW_VERSION(av7110->arm_app) >= 0x2618) ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0); - goto out; - } else { + else { int i, len = dc->x0-dc->color+1; u8 __user *colors = (u8 __user *)dc->data; u8 r, g, b, blend; - + ret = 0; for (i = 0; icolor + i, r, g, b, blend); + ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend); + if (ret) + break; } } - ret = 0; - goto out; - } - case OSD_SetTrans: - goto out; + break; case OSD_SetPixel: - DrawLine(av7110, av7110->osdwin, + ret = DrawLine(av7110, av7110->osdwin, dc->x0, dc->y0, 0, 0, dc->color); - goto out; - case OSD_GetPixel: - goto out; + break; case OSD_SetRow: dc->y1 = dc->y0; /* fall through */ case OSD_SetBlock: ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data); - goto out; + break; case OSD_FillRow: - DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, + ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, dc->x1-dc->x0+1, dc->y1, dc->color); - goto out; + break; case OSD_FillBlock: - DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, + ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color); - goto out; + break; case OSD_Line: - DrawLine(av7110, av7110->osdwin, + ret = DrawLine(av7110, av7110->osdwin, dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color); - goto out; - case OSD_Query: - goto out; - case OSD_Test: - goto out; + break; case OSD_Text: { char textbuf[240]; if (strncpy_from_user(textbuf, dc->data, 240) < 0) { ret = -EFAULT; - goto out; + break; } textbuf[239] = 0; if (dc->x1 > 3) dc->x1 = 3; - SetFont(av7110, av7110->osdwin, dc->x1, + ret = SetFont(av7110, av7110->osdwin, dc->x1, (u16) (dc->color & 0xffff), (u16) (dc->color >> 16)); - FlushText(av7110); - WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf); - goto out; + if (!ret) + ret = FlushText(av7110); + if (!ret) + ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf); + break; } case OSD_SetWindow: - if (dc->x0 < 1 || dc->x0 > 7) { + if (dc->x0 < 1 || dc->x0 > 7) ret = -EINVAL; - goto out; + else { + av7110->osdwin = dc->x0; + ret = 0; } - av7110->osdwin = dc->x0; - goto out; + break; case OSD_MoveWindow: - MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - SetColorBlend(av7110, av7110->osdwin); - goto out; + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (!ret) + ret = SetColorBlend(av7110, av7110->osdwin); + break; case OSD_OpenRaw: if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) { ret = -EINVAL; - goto out; + break; } - if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) { + if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1; - } - else { + else av7110->osdbpp[av7110->osdwin] = 0; - } - CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color, + ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color, dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); + if (ret) + break; if (!dc->data) { - MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); - SetColorBlend(av7110, av7110->osdwin); + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (!ret) + ret = SetColorBlend(av7110, av7110->osdwin); } - goto out; + break; default: ret = -EINVAL; - goto out; + break; } -out: up(&av7110->osd_sema); + if (ret==-ERESTARTSYS) + dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd); + else if (ret) + dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret); + return ret; } -- cgit v1.2.3 From 7d87bc39b98e0bf927acd14611976f710bd9a783 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:57:56 -0700 Subject: [PATCH] dvb: ttpci: fix bug in timeout handling Fix bug in timeout handling. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_hw.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index 7d2bdd791c9..aa1efce6cb3 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -352,11 +352,11 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) start = jiffies; while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__); return -ETIMEDOUT; } + msleep(1); } wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); @@ -364,11 +364,11 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) #ifndef _NOHANDSHAKE start = jiffies; while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); return -ETIMEDOUT; } + msleep(1); } #endif @@ -433,7 +433,6 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) #ifdef COM_DEBUG start = jiffies; while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", __FUNCTION__, @@ -441,6 +440,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) ); return -ETIMEDOUT; } + msleep(1); } stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); @@ -554,25 +554,25 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, start = jiffies; while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) { -#ifdef _NOHANDSHAKE - msleep(1); -#endif if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; } +#ifdef _NOHANDSHAKE + msleep(1); +#endif } #ifndef _NOHANDSHAKE start = jiffies; while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; } + msleep(1); } #endif @@ -712,13 +712,13 @@ static int FlushText(struct av7110 *av7110) return -ERESTARTSYS; start = jiffies; while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_OSD)) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; } + msleep(1); } up(&av7110->dcomlock); return 0; @@ -736,24 +736,24 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) start = jiffies; while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_OSD)) { printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; } + msleep(1); } #ifndef _NOHANDSHAKE start = jiffies; while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) { - msleep(1); if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; } + msleep(1); } #endif for (i = 0; i < length / 2; i++) -- cgit v1.2.3 From c3d7b5aeb32668732ffc1968d12b804a98ef4fdd Mon Sep 17 00:00:00 2001 From: "Dr. Werner Fink" Date: Thu, 7 Jul 2005 17:57:57 -0700 Subject: [PATCH] dvb: ttpci: fix AUDUIO_CONTINUE ioctl Fixed typo in AUDUIO_CONTINUE ioctl: AUDIO_CMD_MUTE -> AUDIO_CMD_UNMUTE Signed-off-by: "Dr. Werner Fink" Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_av.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index ccf946125d0..13c506ea0bb 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -1200,7 +1200,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, case AUDIO_CONTINUE: if (av7110->audiostate.play_state == AUDIO_PAUSED) { av7110->audiostate.play_state = AUDIO_PLAYING; - audcom(av7110, AUDIO_CMD_MUTE | AUDIO_CMD_PCM16); + audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16); } break; -- cgit v1.2.3 From eef5764d6806e29a768a632abce113c15264c5d6 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:57:58 -0700 Subject: [PATCH] dvb: ttpci: budget-av / tu1216 fix for QAM128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix for QAM128 in VHF band suggested by Timo Helkiö. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/budget-av.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 9e65bfd59c4..b65f4b0a481 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -570,9 +570,9 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; - buf[2] = 0x8e; - buf[3] = (params->frequency < 174500000 ? 0xa1 : - params->frequency < 454000000 ? 0x92 : 0x34); + buf[2] = 0x86; + buf[3] = (params->frequency < 150000000 ? 0x01 : + params->frequency < 445000000 ? 0x02 : 0x04); if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) return -EIO; -- cgit v1.2.3 From ce18a223607b0e8cc9a8375abc64281a13ac423c Mon Sep 17 00:00:00 2001 From: Wolfgang Rohdewald Date: Thu, 7 Jul 2005 17:57:59 -0700 Subject: [PATCH] dvb: ttpci: more error handling for firmware communication o propagate more errors back to caller or log them, mainly in av7110.c and av7110_av.c o fix error message in StartHWFilter o do not StopHWFilter for handle 0xffff Signed-off-by: Wolfgang Rohdewald Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110.c | 237 ++++++++++++++++++++++-------------- drivers/media/dvb/ttpci/av7110.h | 4 +- drivers/media/dvb/ttpci/av7110_av.c | 210 +++++++++++++++++++------------- drivers/media/dvb/ttpci/av7110_av.h | 4 +- drivers/media/dvb/ttpci/av7110_hw.h | 12 +- 5 files changed, 280 insertions(+), 187 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 8e33a850e13..e21deee9a98 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -116,13 +116,18 @@ static int av7110_num = 0; static void init_av7110_av(struct av7110 *av7110) { + int ret; struct saa7146_dev *dev = av7110->dev; /* set internal volume control to maximum */ av7110->adac_type = DVB_ADAC_TI; - av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + if (ret<0) + printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret); - av7710_set_video_mode(av7110, vidmode); + ret = av7710_set_video_mode(av7110, vidmode); + if (ret<0) + printk("dvb-ttpci:cannot set video mode:%d\n",ret); /* handle different card types */ /* remaining inits according to card and frontend type */ @@ -156,8 +161,12 @@ static void init_av7110_av(struct av7110 *av7110) if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) { // switch DVB SCART on - av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); - av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1); + ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); + if (ret<0) + printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret); + ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1); + if (ret<0) + printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret); if (rgb_on && (av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) { saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16 @@ -165,8 +174,12 @@ static void init_av7110_av(struct av7110 *av7110) } } - av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); - av7110_setup_irc_config(av7110, 0); + ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + if (ret<0) + printk("dvb-ttpci:cannot set volume :%d\n",ret); + ret = av7110_setup_irc_config(av7110, 0); + if (ret<0) + printk("dvb-ttpci:cannot setup irc config :%d\n",ret); } static void recover_arm(struct av7110 *av7110) @@ -258,8 +271,9 @@ static int arm_thread(void *data) * * If we want to support multiple controls we would have to do much more... */ -void av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) +int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) { + int ret = 0; static struct av7110 *last; dprintk(4, "%p\n", av7110); @@ -270,9 +284,10 @@ void av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config) last = av7110; if (av7110) { - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config); av7110->ir_config = ir_config; } + return ret; } static void (*irc_handler)(u32); @@ -765,13 +780,14 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, pcrpid, vpid, apid, ttpid, subpid); } -void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, +int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid) { + int ret = 0; dprintk(4, "%p\n", av7110); if (down_interruptible(&av7110->pid_mutex)) - return; + return -ERESTARTSYS; if (!(vpid & 0x8000)) av7110->pids[DMX_PES_VIDEO] = vpid; @@ -786,10 +802,11 @@ void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, if (av7110->fe_synced) { pcrpid = av7110->pids[DMX_PES_PCR]; - SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid); + ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid); } up(&av7110->pid_mutex); + return ret; } @@ -832,11 +849,13 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) ret = av7110_fw_request(av7110, buf, 20, &handle, 1); if (ret != 0 || handle >= 32) { printk("dvb-ttpci: %s error buf %04x %04x %04x %04x " - "ret %x handle %04x\n", + "ret %d handle %04x\n", __FUNCTION__, buf[0], buf[1], buf[2], buf[3], ret, handle); dvbdmxfilter->hw_handle = 0xffff; - return -1; + if (!ret) + ret = -1; + return ret; } av7110->handle2filter[handle] = dvbdmxfilter; @@ -859,7 +878,7 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) if (handle >= 32) { printk("%s tried to stop invalid filter %04x, filter type = %x\n", __FUNCTION__, handle, dvbdmxfilter->type); - return 0; + return -EINVAL; } av7110->handle2filter[handle] = NULL; @@ -873,18 +892,20 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) "resp %04x %04x pid %d\n", __FUNCTION__, buf[0], buf[1], buf[2], ret, answ[0], answ[1], dvbdmxfilter->feed->pid); - ret = -1; + if (!ret) + ret = -1; } return ret; } -static void dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) +static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv; u16 *pid = dvbdmx->pids, npids[5]; int i; + int ret = 0; dprintk(4, "%p\n", av7110); @@ -893,36 +914,49 @@ static void dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) { npids[i] = 0; - ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); - StartHWFilter(dvbdmxfeed->filter); - return; + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (!ret) + ret = StartHWFilter(dvbdmxfeed->filter); + return ret; + } + if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) { + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (ret) + return ret; } - if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) - ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); if (dvbdmxfeed->pes_type < 2 && npids[0]) if (av7110->fe_synced) - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + { + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + if (ret) + return ret; + } if ((dvbdmxfeed->ts_type & TS_PACKET)) { if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) - av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); + ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) - av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed); + ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed); } + return ret; } -static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) +static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv; u16 *pid = dvbdmx->pids, npids[5]; int i; + int ret = 0; + dprintk(4, "%p\n", av7110); if (dvbdmxfeed->pes_type <= 1) { - av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO); + ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO); + if (ret) + return ret; if (!av7110->rec_mode) dvbdmx->recording = 0; if (!av7110->playing) @@ -933,24 +967,27 @@ static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) switch (i) { case 2: //teletext if (dvbdmxfeed->ts_type & TS_PACKET) - StopHWFilter(dvbdmxfeed->filter); + ret = StopHWFilter(dvbdmxfeed->filter); npids[2] = 0; break; case 0: case 1: case 4: if (!pids_off) - return; + return 0; npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; break; } - ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (!ret) + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + return ret; } static int av7110_start_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct av7110 *av7110 = demux->priv; + int ret = 0; dprintk(4, "%p\n", av7110); @@ -971,21 +1008,22 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) !(demux->pids[1] & 0x8000)) { dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - av7110_av_start_play(av7110,RP_AV); - demux->playing = 1; + ret = av7110_av_start_play(av7110,RP_AV); + if (!ret) + demux->playing = 1; } break; default: - dvb_feed_start_pid(feed); + ret = dvb_feed_start_pid(feed); break; } } else if ((feed->ts_type & TS_PACKET) && (demux->dmx.frontend->source != DMX_MEMORY_FE)) { - StartHWFilter(feed->filter); + ret = StartHWFilter(feed->filter); } } - if (feed->type == DMX_TYPE_SEC) { + else if (feed->type == DMX_TYPE_SEC) { int i; for (i = 0; i < demux->filternum; i++) { @@ -996,12 +1034,15 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) if (demux->filter[i].filter.parent != &feed->feed.sec) continue; demux->filter[i].state = DMX_STATE_GO; - if (demux->dmx.frontend->source != DMX_MEMORY_FE) - StartHWFilter(&demux->filter[i]); + if (demux->dmx.frontend->source != DMX_MEMORY_FE) { + ret = StartHWFilter(&demux->filter[i]); + if (ret) + break; + } } } - return 0; + return ret; } @@ -1010,6 +1051,7 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) struct dvb_demux *demux = feed->demux; struct av7110 *av7110 = demux->priv; + int ret = 0; dprintk(4, "%p\n", av7110); if (feed->type == DMX_TYPE_TS) { @@ -1022,26 +1064,29 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) } if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER) { - dvb_feed_stop_pid(feed); + ret = dvb_feed_stop_pid(feed); } else if ((feed->ts_type & TS_PACKET) && (demux->dmx.frontend->source != DMX_MEMORY_FE)) - StopHWFilter(feed->filter); + ret = StopHWFilter(feed->filter); } - if (feed->type == DMX_TYPE_SEC) { + if (!ret && feed->type == DMX_TYPE_SEC) { int i; for (i = 0; ifilternum; i++) if (demux->filter[i].state == DMX_STATE_GO && demux->filter[i].filter.parent == &feed->feed.sec) { demux->filter[i].state = DMX_STATE_READY; - if (demux->dmx.frontend->source != DMX_MEMORY_FE) - StopHWFilter(&demux->filter[i]); + if (demux->dmx.frontend->source != DMX_MEMORY_FE) { + ret = StopHWFilter(&demux->filter[i]); + if (ret) + break; + } } } - return 0; + return ret; } @@ -1093,7 +1138,7 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num, ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4); if (ret) { printk(KERN_ERR "%s: av7110_fw_request error\n", __FUNCTION__); - return -EIO; + return ret; } dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n", fwstc[0], fwstc[1], fwstc[2], fwstc[3]); @@ -1119,18 +1164,14 @@ static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) switch (tone) { case SEC_TONE_ON: - Set22K(av7110, 1); - break; + return Set22K(av7110, 1); case SEC_TONE_OFF: - Set22K(av7110, 0); - break; + return Set22K(av7110, 0); default: return -EINVAL; } - - return 0; } static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, @@ -1138,9 +1179,7 @@ static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, { struct av7110* av7110 = fe->dvb->priv; - av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); - - return 0; + return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); } static int av7110_diseqc_send_burst(struct dvb_frontend* fe, @@ -1148,9 +1187,7 @@ static int av7110_diseqc_send_burst(struct dvb_frontend* fe, { struct av7110* av7110 = fe->dvb->priv; - av7110_diseqc_send(av7110, 0, NULL, minicmd); - - return 0; + return av7110_diseqc_send(av7110, 0, NULL, minicmd); } /* simplified code from budget-core.c */ @@ -1992,76 +2029,84 @@ static struct l64781_config grundig_29504_401_config = { -static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) +static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) { + int ret = 0; int synced = (status & FE_HAS_LOCK) ? 1 : 0; av7110->fe_status = status; if (av7110->fe_synced == synced) - return; + return 0; av7110->fe_synced = synced; if (av7110->playing) - return; + return 0; if (down_interruptible(&av7110->pid_mutex)) - return; + return -ERESTARTSYS; if (av7110->fe_synced) { - SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], + ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], av7110->pids[DMX_PES_AUDIO], av7110->pids[DMX_PES_TELETEXT], 0, av7110->pids[DMX_PES_PCR]); - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + if (!ret) + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); } else { - SetPIDs(av7110, 0, 0, 0, 0, 0); - av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0); - av7110_wait_msgstate(av7110, GPMQBusy); + ret = SetPIDs(av7110, 0, 0, 0, 0, 0); + if (!ret) { + ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0); + if (!ret) + ret = av7110_wait_msgstate(av7110, GPMQBusy); + } } up(&av7110->pid_mutex); + return ret; } static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_set_frontend(fe, params); + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_set_frontend(fe, params); + return ret; } static int av7110_fe_init(struct dvb_frontend* fe) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_init(fe); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_init(fe); + return ret; } static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) { struct av7110* av7110 = fe->dvb->priv; - int ret; /* call the real implementation */ - ret = av7110->fe_read_status(fe, status); - if (ret) - return ret; - - if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) { - av7110_fe_lock_fix(av7110, *status); - } - - return 0; + int ret = av7110->fe_read_status(fe, status); + if (!ret) + if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) + ret = av7110_fe_lock_fix(av7110, *status); + return ret; } static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_diseqc_reset_overload(fe); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_diseqc_reset_overload(fe); + return ret; } static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, @@ -2069,40 +2114,50 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_diseqc_send_master_cmd(fe, cmd); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); + return ret; } static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_diseqc_send_burst(fe, minicmd); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_diseqc_send_burst(fe, minicmd); + return ret; } static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_set_tone(fe, tone); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_set_tone(fe, tone); + return ret; } static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_set_voltage(fe, voltage); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_set_voltage(fe, voltage); + return ret; } static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd) { struct av7110* av7110 = fe->dvb->priv; - av7110_fe_lock_fix(av7110, 0); - return av7110->fe_dishnetwork_send_legacy_command(fe, cmd); + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd); + return ret; } static u8 read_pwm(struct av7110* av7110) diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index e54222d9b3f..508b7739c60 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -254,12 +254,12 @@ struct av7110 { }; -extern void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, +extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid); extern void av7110_register_irc_handler(void (*func)(u32)); extern void av7110_unregister_irc_handler(void (*func)(u32)); -extern void av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config); +extern int av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config); extern int av7110_ir_init (void); extern void av7110_ir_exit (void); diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 13c506ea0bb..bbfad6def47 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -121,6 +121,7 @@ static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data) int av7110_av_start_record(struct av7110 *av7110, int av, struct dvb_demux_feed *dvbdmxfeed) { + int ret = 0; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed); @@ -137,7 +138,7 @@ int av7110_av_start_record(struct av7110 *av7110, int av, dvbdmx->pesfilter[0]->pid, dvb_filter_pes2ts_cb, (void *) dvbdmx->pesfilter[0]); - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); break; case RP_VIDEO: @@ -145,7 +146,7 @@ int av7110_av_start_record(struct av7110 *av7110, int av, dvbdmx->pesfilter[1]->pid, dvb_filter_pes2ts_cb, (void *) dvbdmx->pesfilter[1]); - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); break; case RP_AV: @@ -157,14 +158,15 @@ int av7110_av_start_record(struct av7110 *av7110, int av, dvbdmx->pesfilter[1]->pid, dvb_filter_pes2ts_cb, (void *) dvbdmx->pesfilter[1]); - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); break; } - return 0; + return ret; } int av7110_av_start_play(struct av7110 *av7110, int av) { + int ret = 0; dprintk(2, "av7110:%p, \n", av7110); if (av7110->rec_mode) @@ -182,54 +184,57 @@ int av7110_av_start_play(struct av7110 *av7110, int av) av7110->playing |= av; switch (av7110->playing) { case RP_AUDIO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); break; case RP_VIDEO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); av7110->sinfo = 0; break; case RP_AV: av7110->sinfo = 0; - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); break; } - return av7110->playing; + if (!ret) + ret = av7110->playing; + return ret; } -void av7110_av_stop(struct av7110 *av7110, int av) +int av7110_av_stop(struct av7110 *av7110, int av) { + int ret = 0; dprintk(2, "av7110:%p, \n", av7110); if (!(av7110->playing & av) && !(av7110->rec_mode & av)) - return; - + return 0; av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); if (av7110->playing) { av7110->playing &= ~av; switch (av7110->playing) { case RP_AUDIO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); break; case RP_VIDEO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); break; case RP_NONE: - av7110_set_vidmode(av7110, av7110->vidmode); + ret = av7110_set_vidmode(av7110, av7110->vidmode); break; } } else { av7110->rec_mode &= ~av; switch (av7110->rec_mode) { case RP_AUDIO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); break; case RP_VIDEO: - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); break; case RP_NONE: break; } } + return ret; } @@ -317,19 +322,22 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) return 0; } -void av7110_set_vidmode(struct av7110 *av7110, int mode) +int av7110_set_vidmode(struct av7110 *av7110, int mode) { + int ret; dprintk(2, "av7110:%p, \n", av7110); - av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode); + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode); - if (!av7110->playing) { - ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO], + if (!ret && !av7110->playing) { + ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO], av7110->pids[DMX_PES_AUDIO], av7110->pids[DMX_PES_TELETEXT], 0, av7110->pids[DMX_PES_PCR]); - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + if (!ret) + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); } + return ret; } @@ -340,17 +348,18 @@ static int sw2mode[16] = { VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, }; -static void get_video_format(struct av7110 *av7110, u8 *buf, int count) +static int get_video_format(struct av7110 *av7110, u8 *buf, int count) { int i; int hsize, vsize; int sw; u8 *p; + int ret = 0; dprintk(2, "av7110:%p, \n", av7110); if (av7110->sinfo) - return; + return 0; for (i = 7; i < count - 10; i++) { p = buf + i; if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3) @@ -359,11 +368,14 @@ static void get_video_format(struct av7110 *av7110, u8 *buf, int count) hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4); vsize = ((p[1] &0x0F) << 8) | (p[2]); sw = (p[3] & 0x0F); - av7110_set_vidmode(av7110, sw2mode[sw]); - dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw); - av7110->sinfo = 1; + ret = av7110_set_vidmode(av7110, sw2mode[sw]); + if (!ret) { + dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw); + av7110->sinfo = 1; + } break; } + return ret; } @@ -974,7 +986,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, unsigned long arg = (unsigned long) parg; int ret = 0; - dprintk(2, "av7110:%p, \n", av7110); + dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); if ((file->f_flags & O_ACCMODE) == O_RDONLY) { if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT && @@ -987,49 +999,57 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, case VIDEO_STOP: av7110->videostate.play_state = VIDEO_STOPPED; if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) - av7110_av_stop(av7110, RP_VIDEO); + ret = av7110_av_stop(av7110, RP_VIDEO); else - vidcom(av7110, VIDEO_CMD_STOP, + ret = vidcom(av7110, VIDEO_CMD_STOP, av7110->videostate.video_blank ? 0 : 1); - av7110->trickmode = TRICK_NONE; + if (!ret) + av7110->trickmode = TRICK_NONE; break; case VIDEO_PLAY: av7110->trickmode = TRICK_NONE; if (av7110->videostate.play_state == VIDEO_FREEZED) { av7110->videostate.play_state = VIDEO_PLAYING; - vidcom(av7110, VIDEO_CMD_PLAY, 0); + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); + if (ret) + break; } if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) { if (av7110->playing == RP_AV) { - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + if (ret) + break; av7110->playing &= ~RP_VIDEO; } - av7110_av_start_play(av7110, RP_VIDEO); - vidcom(av7110, VIDEO_CMD_PLAY, 0); - } else { - //av7110_av_stop(av7110, RP_VIDEO); - vidcom(av7110, VIDEO_CMD_PLAY, 0); + ret = av7110_av_start_play(av7110, RP_VIDEO); } - av7110->videostate.play_state = VIDEO_PLAYING; + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); + if (!ret) + av7110->videostate.play_state = VIDEO_PLAYING; break; case VIDEO_FREEZE: av7110->videostate.play_state = VIDEO_FREEZED; if (av7110->playing & RP_VIDEO) - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); else - vidcom(av7110, VIDEO_CMD_FREEZE, 1); - av7110->trickmode = TRICK_FREEZE; + ret = vidcom(av7110, VIDEO_CMD_FREEZE, 1); + if (!ret) + av7110->trickmode = TRICK_FREEZE; break; case VIDEO_CONTINUE: if (av7110->playing & RP_VIDEO) - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); - vidcom(av7110, VIDEO_CMD_PLAY, 0); - av7110->videostate.play_state = VIDEO_PLAYING; - av7110->trickmode = TRICK_NONE; + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); + if (!ret) { + av7110->videostate.play_state = VIDEO_PLAYING; + av7110->trickmode = TRICK_NONE; + } break; case VIDEO_SELECT_SOURCE: @@ -1045,7 +1065,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, break; case VIDEO_GET_EVENT: - ret=dvb_video_get_event(av7110, parg, file->f_flags); + ret = dvb_video_get_event(av7110, parg, file->f_flags); break; case VIDEO_GET_SIZE: @@ -1105,25 +1125,32 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, case VIDEO_FAST_FORWARD: //note: arg is ignored by firmware if (av7110->playing & RP_VIDEO) - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Scan_I, 2, AV_PES, 0); else - vidcom(av7110, VIDEO_CMD_FFWD, arg); - av7110->trickmode = TRICK_FAST; - av7110->videostate.play_state = VIDEO_PLAYING; + ret = vidcom(av7110, VIDEO_CMD_FFWD, arg); + if (!ret) { + av7110->trickmode = TRICK_FAST; + av7110->videostate.play_state = VIDEO_PLAYING; + } break; case VIDEO_SLOWMOTION: if (av7110->playing&RP_VIDEO) { - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); - vidcom(av7110, VIDEO_CMD_SLOW, arg); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); } else { - vidcom(av7110, VIDEO_CMD_PLAY, 0); - vidcom(av7110, VIDEO_CMD_STOP, 0); - vidcom(av7110, VIDEO_CMD_SLOW, arg); + ret = vidcom(av7110, VIDEO_CMD_PLAY, 0); + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_STOP, 0); + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); + } + if (!ret) { + av7110->trickmode = TRICK_SLOW; + av7110->videostate.play_state = VIDEO_PLAYING; } - av7110->trickmode = TRICK_SLOW; - av7110->videostate.play_state = VIDEO_PLAYING; break; case VIDEO_GET_CAPABILITIES: @@ -1136,18 +1163,21 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, av7110_ipack_reset(&av7110->ipack[1]); if (av7110->playing == RP_AV) { - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); + if (ret) + break; if (av7110->trickmode == TRICK_FAST) - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Scan_I, 2, AV_PES, 0); if (av7110->trickmode == TRICK_SLOW) { - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); - vidcom(av7110, VIDEO_CMD_SLOW, arg); + if (!ret) + ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); } if (av7110->trickmode == TRICK_FREEZE) - vidcom(av7110, VIDEO_CMD_STOP, 1); + ret = vidcom(av7110, VIDEO_CMD_STOP, 1); } break; @@ -1170,7 +1200,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, unsigned long arg = (unsigned long) parg; int ret = 0; - dprintk(2, "av7110:%p, \n", av7110); + dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); if (((file->f_flags & O_ACCMODE) == O_RDONLY) && (cmd != AUDIO_GET_STATUS)) @@ -1179,28 +1209,32 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, switch (cmd) { case AUDIO_STOP: if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) - av7110_av_stop(av7110, RP_AUDIO); + ret = av7110_av_stop(av7110, RP_AUDIO); else - audcom(av7110, AUDIO_CMD_MUTE); - av7110->audiostate.play_state = AUDIO_STOPPED; + ret = audcom(av7110, AUDIO_CMD_MUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_STOPPED; break; case AUDIO_PLAY: if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) - av7110_av_start_play(av7110, RP_AUDIO); - audcom(av7110, AUDIO_CMD_UNMUTE); - av7110->audiostate.play_state = AUDIO_PLAYING; + ret = av7110_av_start_play(av7110, RP_AUDIO); + if (!ret) + ret = audcom(av7110, AUDIO_CMD_UNMUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_PLAYING; break; case AUDIO_PAUSE: - audcom(av7110, AUDIO_CMD_MUTE); - av7110->audiostate.play_state = AUDIO_PAUSED; + ret = audcom(av7110, AUDIO_CMD_MUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_PAUSED; break; case AUDIO_CONTINUE: if (av7110->audiostate.play_state == AUDIO_PAUSED) { av7110->audiostate.play_state = AUDIO_PLAYING; - audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16); + ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16); } break; @@ -1210,14 +1244,15 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, case AUDIO_SET_MUTE: { - audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE); - av7110->audiostate.mute_state = (int) arg; + ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE); + if (!ret) + av7110->audiostate.mute_state = (int) arg; break; } case AUDIO_SET_AV_SYNC: av7110->audiostate.AV_sync_state = (int) arg; - audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF); + ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF); break; case AUDIO_SET_BYPASS_MODE: @@ -1229,21 +1264,24 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, switch(av7110->audiostate.channel_select) { case AUDIO_STEREO: - audcom(av7110, AUDIO_CMD_STEREO); - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x49); + ret = audcom(av7110, AUDIO_CMD_STEREO); + if (!ret) + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x49); break; case AUDIO_MONO_LEFT: - audcom(av7110, AUDIO_CMD_MONO_L); - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x4a); + ret = audcom(av7110, AUDIO_CMD_MONO_L); + if (!ret) + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x4a); break; case AUDIO_MONO_RIGHT: - audcom(av7110, AUDIO_CMD_MONO_R); - if (av7110->adac_type == DVB_ADAC_CRYSTAL) - i2c_writereg(av7110, 0x20, 0x02, 0x45); + ret = audcom(av7110, AUDIO_CMD_MONO_R); + if (!ret) + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x45); break; default: @@ -1264,7 +1302,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); av7110_ipack_reset(&av7110->ipack[0]); if (av7110->playing == RP_AV) - av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); break; case AUDIO_SET_ID: @@ -1274,7 +1312,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, { struct audio_mixer *amix = (struct audio_mixer *)parg; - av7110_set_volume(av7110, amix->volume_left, amix->volume_right); + ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right); break; } case AUDIO_SET_STREAMTYPE: diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h index cc5e7a7e87c..45dc144b8b4 100644 --- a/drivers/media/dvb/ttpci/av7110_av.h +++ b/drivers/media/dvb/ttpci/av7110_av.h @@ -3,14 +3,14 @@ struct av7110; -extern void av7110_set_vidmode(struct av7110 *av7110, int mode); +extern int av7110_set_vidmode(struct av7110 *av7110, int mode); extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len); extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright); -extern void av7110_av_stop(struct av7110 *av7110, int av); +extern int av7110_av_stop(struct av7110 *av7110, int av); extern int av7110_av_start_record(struct av7110 *av7110, int av, struct dvb_demux_feed *dvbdmxfeed); extern int av7110_av_start_play(struct av7110 *av7110, int av); diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h index 52061e17c6d..fedd20f9815 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.h +++ b/drivers/media/dvb/ttpci/av7110_hw.h @@ -458,27 +458,27 @@ static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data) return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data); } -static inline void av7710_set_video_mode(struct av7110 *av7110, int mode) +static inline int av7710_set_video_mode(struct av7110 *av7110, int mode) { - av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode); + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode); } -static int inline vidcom(struct av7110 *av7110, u32 com, u32 arg) +static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg) { return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4, (com>>16), (com&0xffff), (arg>>16), (arg&0xffff)); } -static int inline audcom(struct av7110 *av7110, u32 com) +static inline int audcom(struct av7110 *av7110, u32 com) { return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2, (com>>16), (com&0xffff)); } -static inline void Set22K(struct av7110 *av7110, int state) +static inline int Set22K(struct av7110 *av7110, int state) { - av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0); + return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0); } -- cgit v1.2.3 From 12ba05049f9060e21ed1f95e876d8d063d2575b2 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:58:00 -0700 Subject: [PATCH] dvb: ttpci: error handling fix Change error handling in av7110_stop_feed() to stop as many filters as possible in case of errors. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index e21deee9a98..87767af7207 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -1050,8 +1050,7 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct av7110 *av7110 = demux->priv; - - int ret = 0; + int i, rc, ret = 0; dprintk(4, "%p\n", av7110); if (feed->type == DMX_TYPE_TS) { @@ -1072,17 +1071,17 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) } if (!ret && feed->type == DMX_TYPE_SEC) { - int i; - - for (i = 0; ifilternum; i++) + for (i = 0; ifilternum; i++) { if (demux->filter[i].state == DMX_STATE_GO && demux->filter[i].filter.parent == &feed->feed.sec) { demux->filter[i].state = DMX_STATE_READY; if (demux->dmx.frontend->source != DMX_MEMORY_FE) { - ret = StopHWFilter(&demux->filter[i]); - if (ret) - break; + rc = StopHWFilter(&demux->filter[i]); + if (!ret) + ret = rc; + /* keep going, stop as many filters as possible */ } + } } } -- cgit v1.2.3 From 7a2fa90fa8084846937aa194f8a40abfa99c692f Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:58:01 -0700 Subject: [PATCH] dvb: ttpci: cleanup indentation + whitespace Fix indentation and add some whitepsace between operators. Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110.c | 12 ++++++------ drivers/media/dvb/ttpci/av7110_av.c | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 87767af7207..ab4f77d73ed 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -122,11 +122,11 @@ static void init_av7110_av(struct av7110 *av7110) /* set internal volume control to maximum */ av7110->adac_type = DVB_ADAC_TI; ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret); ret = av7710_set_video_mode(av7110, vidmode); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot set video mode:%d\n",ret); /* handle different card types */ @@ -162,10 +162,10 @@ static void init_av7110_av(struct av7110 *av7110) if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) { // switch DVB SCART on ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret); ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret); if (rgb_on && (av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) { @@ -175,10 +175,10 @@ static void init_av7110_av(struct av7110 *av7110) } ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot set volume :%d\n",ret); ret = av7110_setup_irc_config(av7110, 0); - if (ret<0) + if (ret < 0) printk("dvb-ttpci:cannot setup irc config :%d\n",ret); } diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index bbfad6def47..0696a5a4f85 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -1126,7 +1126,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, //note: arg is ignored by firmware if (av7110->playing & RP_VIDEO) ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Scan_I, 2, AV_PES, 0); + __Scan_I, 2, AV_PES, 0); else ret = vidcom(av7110, VIDEO_CMD_FFWD, arg); if (!ret) { @@ -1164,15 +1164,15 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file, if (av7110->playing == RP_AV) { ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Play, 2, AV_PES, 0); + __Play, 2, AV_PES, 0); if (ret) break; if (av7110->trickmode == TRICK_FAST) ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Scan_I, 2, AV_PES, 0); + __Scan_I, 2, AV_PES, 0); if (av7110->trickmode == TRICK_SLOW) { ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Slow, 2, 0, 0); + __Slow, 2, 0, 0); if (!ret) ret = vidcom(av7110, VIDEO_CMD_SLOW, arg); } @@ -1303,7 +1303,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, av7110_ipack_reset(&av7110->ipack[0]); if (av7110->playing == RP_AV) ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, - __Play, 2, AV_PES, 0); + __Play, 2, AV_PES, 0); break; case AUDIO_SET_ID: -- cgit v1.2.3 From 34612157b48d38e85ff72d65291b9eecb44dd0a6 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Thu, 7 Jul 2005 17:58:02 -0700 Subject: [PATCH] dvb: ttpci: make av7110_fe_lock_fix() retryable av7110_fe_lock_fix() modified in a way that it can be retried after -ERESTARTSYS Signed-off-by: Oliver Endriss Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index ab4f77d73ed..e4c6e87f6c5 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -2038,15 +2038,13 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) if (av7110->fe_synced == synced) return 0; - av7110->fe_synced = synced; - if (av7110->playing) return 0; if (down_interruptible(&av7110->pid_mutex)) return -ERESTARTSYS; - if (av7110->fe_synced) { + if (synced) { ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], av7110->pids[DMX_PES_AUDIO], av7110->pids[DMX_PES_TELETEXT], 0, @@ -2062,6 +2060,9 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) } } + if (!ret) + av7110->fe_synced = synced; + up(&av7110->pid_mutex); return ret; } -- cgit v1.2.3 From 80887a59c255f4a6c348dfc679501b3679d1070f Mon Sep 17 00:00:00 2001 From: Christophe Lucas Date: Thu, 7 Jul 2005 17:58:03 -0700 Subject: [PATCH] dvb: ttpci: kj printk fix printk() calls should include appropriate KERN_* constant. Signed-off-by: Christophe Lucas Signed-off-by: Domen Puncer Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/av7110_ipack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/av7110_ipack.c b/drivers/media/dvb/ttpci/av7110_ipack.c index 24664074188..699ef8b5b99 100644 --- a/drivers/media/dvb/ttpci/av7110_ipack.c +++ b/drivers/media/dvb/ttpci/av7110_ipack.c @@ -24,7 +24,7 @@ int av7110_ipack_init(struct ipack *p, int size, void (*func)(u8 *buf, int size, void *priv)) { if (!(p->buf = vmalloc(size*sizeof(u8)))) { - printk ("Couldn't allocate memory for ipack\n"); + printk(KERN_WARNING "Couldn't allocate memory for ipack\n"); return -ENOMEM; } p->size = size; -- cgit v1.2.3 From 53936391741dee735304e997e2289500adf970c7 Mon Sep 17 00:00:00 2001 From: Gavin Hamill Date: Thu, 7 Jul 2005 17:58:04 -0700 Subject: [PATCH] dvb: ttpci: add support for Hauppauge/TT DVB-C budget Add support for Hauppauge/TT DVB-C budget. Signed-off-by: Gavin Hamill Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttusb-budget/Kconfig | 1 + drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 50 ++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig index 4aa714ab4c2..c6c1d41a2ef 100644 --- a/drivers/media/dvb/ttusb-budget/Kconfig +++ b/drivers/media/dvb/ttusb-budget/Kconfig @@ -3,6 +3,7 @@ config DVB_TTUSB_BUDGET depends on DVB_CORE && USB select DVB_CX22700 select DVB_TDA1004X + select DVB_VES1820 select DVB_TDA8083 select DVB_STV0299 help diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index afa0e7a0e50..2c17a5f5834 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -24,6 +24,7 @@ #include "dmxdev.h" #include "dvb_demux.h" #include "dvb_net.h" +#include "ves1820.h" #include "cx22700.h" #include "tda1004x.h" #include "stv0299.h" @@ -1367,6 +1368,47 @@ static struct tda8083_config ttusb_novas_grundig_29504_491_config = { .pll_set = ttusb_novas_grundig_29504_491_pll_set, }; +static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct ttusb* ttusb = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (params->frequency + 35937500 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85 | ((div >> 10) & 0x60); + data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + + if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1) + return -EIO; + + return 0; +} + + +static struct ves1820_config alps_tdbe2_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, + .pll_set = alps_tdbe2_pll_set, +}; + +static u8 read_pwm(struct ttusb* ttusb) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; + + if ((i2c_transfer(&ttusb->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} static void frontend_init(struct ttusb* ttusb) @@ -1394,6 +1436,12 @@ static void frontend_init(struct ttusb* ttusb) break; + case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) + ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb)); + if (ttusb->fe != NULL) + break; + break; + case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??)) // try the ALPS TDMB7 first ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap); @@ -1570,7 +1618,7 @@ static void ttusb_disconnect(struct usb_interface *intf) static struct usb_device_id ttusb_table[] = { {USB_DEVICE(0xb48, 0x1003)}, -/* {USB_DEVICE(0xb48, 0x1004)},UNDEFINED HARDWARE - mail linuxtv.org list*/ /* to be confirmed ???? */ + {USB_DEVICE(0xb48, 0x1004)}, {USB_DEVICE(0xb48, 0x1005)}, {} }; -- cgit v1.2.3 From 68293ddbabb26a58ddb0a84aa5058a7acd7127e7 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 7 Jul 2005 17:58:06 -0700 Subject: [PATCH] dvb: dvb-usb: support Artect T1 with broken USB ids Add #define for device with broken USB ids. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dibusb-mb.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index a0ffbb59fa1..494e1227cb7 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -115,6 +115,12 @@ static struct usb_device_id dibusb_dib3000mb_table [] = { /* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, /* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) }, /* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, + +// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs + +#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs +/* 25 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, +#endif { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table); @@ -228,12 +234,22 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { } }, +#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs + .num_device_descs = 2, +#else .num_device_descs = 1, +#endif .devices = { { "Artec T1 USB1.1 TVBOX with AN2235", { &dibusb_dib3000mb_table[20], NULL }, { &dibusb_dib3000mb_table[21], NULL }, }, +#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs + { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", + { &dibusb_dib3000mb_table[25], NULL }, + { NULL }, + }, +#endif } }; -- cgit v1.2.3 From 8945c8c3d207c7a69024c02d164f5ae790c5b7ba Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:07 -0700 Subject: [PATCH] dvb: usb: fix ADSTech Instant TV DVB-T USB2.0 support Fixed support for the ADSTech Instant TV DVB-T USB (2.0 version). Thanks to Gerolf Wendland for his support. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dibusb-mb.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 494e1227cb7..aee6263f07c 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -31,10 +31,17 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d) return 0; } -/* some of the dibusb 1.1 device aren't equipped with the default tuner +static int dibusb_thomson_tuner_attach(struct dvb_usb_device *d) +{ + d->pll_addr = 0x61; + d->pll_desc = &dvb_pll_tua6010xs; + return 0; +} + +/* Some of the Artec 1.1 device aren't equipped with the default tuner * (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures * this out. */ -static int dibusb_dib3000mb_tuner_attach (struct dvb_usb_device *d) +static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d) { u8 b[2] = { 0,0 }, b2[1]; int ret = 0; @@ -59,8 +66,7 @@ static int dibusb_dib3000mb_tuner_attach (struct dvb_usb_device *d) if (b2[0] == 0xfe) { info("this device has the Thomson Cable onboard. Which is default."); - d->pll_addr = 0x61; - d->pll_desc = &dvb_pll_tua6010xs; + dibusb_thomson_tuner_attach(d); } else { u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab }; info("this device has the Panasonic ENV77H11D5 onboard."); @@ -114,6 +120,8 @@ static struct usb_device_id dibusb_dib3000mb_table [] = { /* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) }, /* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, /* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) }, + +/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */ /* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, // #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs @@ -140,7 +148,7 @@ static struct dvb_usb_properties dibusb1_1_properties = { .pid_filter_ctrl = dibusb_pid_filter_ctrl, .power_ctrl = dibusb_power_ctrl, .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_dib3000mb_tuner_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dibusb_rc_keys, @@ -212,7 +220,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { .pid_filter_ctrl = dibusb_pid_filter_ctrl, .power_ctrl = dibusb_power_ctrl, .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_dib3000mb_tuner_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dibusb_rc_keys, @@ -257,7 +265,7 @@ static struct dvb_usb_properties dibusb2_0b_properties = { .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, - .firmware = "dvb-usb-adstech-usb2-01.fw", + .firmware = "dvb-usb-adstech-usb2-02.fw", .size_of_priv = sizeof(struct dibusb_state), @@ -266,7 +274,7 @@ static struct dvb_usb_properties dibusb2_0b_properties = { .pid_filter_ctrl = dibusb_pid_filter_ctrl, .power_ctrl = dibusb2_0_power_ctrl, .frontend_attach = dibusb_dib3000mb_frontend_attach, - .tuner_attach = dibusb_dib3000mb_tuner_attach, + .tuner_attach = dibusb_thomson_tuner_attach, .rc_interval = DEFAULT_RC_INTERVAL, .rc_key_map = dibusb_rc_keys, @@ -288,11 +296,11 @@ static struct dvb_usb_properties dibusb2_0b_properties = { } }, - .num_device_descs = 2, + .num_device_descs = 1, .devices = { { "KWorld/ADSTech Instant DVB-T USB 2.0", { &dibusb_dib3000mb_table[23], NULL }, - { &dibusb_dib3000mb_table[24], NULL }, /* device ID with default DIBUSB2_0-firmware */ + { &dibusb_dib3000mb_table[24], NULL }, }, } }; -- cgit v1.2.3 From 7f5fee57812c99c95edf6794a50413c75e99fd4d Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:08 -0700 Subject: [PATCH] dvb: usb: add isochronous streaming method Added isochronous-streaming method. Changed memory (de)allocation behaviour accordingly. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dvb-usb-common.h | 3 +- drivers/media/dvb/dvb-usb/dvb-usb-urb.c | 178 +++++++++++++++++++++++------ drivers/media/dvb/dvb-usb/dvb-usb.h | 24 +++- 3 files changed, 167 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h index 67e0d73fbce..abf7d2f562b 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h @@ -15,11 +15,12 @@ extern int dvb_usb_debug; #define deb_info(args...) dprintk(dvb_usb_debug,0x01,args) #define deb_xfer(args...) dprintk(dvb_usb_debug,0x02,args) -#define deb_pll(args...) dprintk(dvb_usb_debug,0x04,args) +#define deb_pll(args...) dprintk(dvb_usb_debug,0x04,args) #define deb_ts(args...) dprintk(dvb_usb_debug,0x08,args) #define deb_err(args...) dprintk(dvb_usb_debug,0x10,args) #define deb_rc(args...) dprintk(dvb_usb_debug,0x20,args) #define deb_fw(args...) dprintk(dvb_usb_debug,0x40,args) +#define deb_mem(args...) dprintk(dvb_usb_debug,0x80,args) /* commonly used methods */ extern int usb_cypress_load_firmware(struct usb_device *, const char *, int); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c index 83d476fb410..dcd8c2f915f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c @@ -24,6 +24,7 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, if ((ret = down_interruptible(&d->usb_sem))) return ret; + deb_xfer(">>> "); debug_dump(wbuf,wlen,deb_xfer); ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, @@ -46,8 +47,10 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, if (ret) err("recv bulk message failed: %d",ret); - else + else { + deb_xfer("<<< "); debug_dump(rbuf,actlen,deb_xfer); + } } up(&d->usb_sem); @@ -61,12 +64,19 @@ int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) } EXPORT_SYMBOL(dvb_usb_generic_write); -static void dvb_usb_bulk_urb_complete(struct urb *urb, struct pt_regs *ptregs) + +/* URB stuff for streaming */ +static void dvb_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs) { struct dvb_usb_device *d = urb->context; + int ptype = usb_pipetype(urb->pipe); + int i; + u8 *b; - deb_ts("bulk urb completed. feedcount: %d, status: %d, length: %d\n",d->feedcount,urb->status, - urb->actual_length); + deb_ts("'%s' urb completed. feedcount: %d, status: %d, length: %d/%d, pack_num: %d, errors: %d\n", + ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", d->feedcount, + urb->status,urb->actual_length,urb->transfer_buffer_length, + urb->number_of_packets,urb->error_count); switch (urb->status) { case 0: /* success */ @@ -81,11 +91,33 @@ static void dvb_usb_bulk_urb_complete(struct urb *urb, struct pt_regs *ptregs) break; } - if (d->feedcount > 0 && urb->actual_length > 0) { - if (d->state & DVB_USB_STATE_DVB) - dvb_dmx_swfilter(&d->demux, (u8*) urb->transfer_buffer,urb->actual_length); - } else - deb_ts("URB dropped because of feedcount.\n"); + if (d->feedcount > 0) { + if (d->state & DVB_USB_STATE_DVB) { + switch (ptype) { + case PIPE_ISOCHRONOUS: + b = (u8 *) urb->transfer_buffer; + 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) { + dvb_dmx_swfilter(&d->demux,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_ts); + break; + case PIPE_BULK: + if (urb->actual_length > 0) + dvb_dmx_swfilter(&d->demux, (u8 *) urb->transfer_buffer,urb->actual_length); + break; + default: + err("unkown endpoint type in completition handler."); + return; + } + } + } usb_submit_urb(urb,GFP_ATOMIC); } @@ -94,7 +126,7 @@ int dvb_usb_urb_kill(struct dvb_usb_device *d) { int i; for (i = 0; i < d->urbs_submitted; i++) { - deb_info("killing URB no. %d.\n",i); + deb_ts("killing URB no. %d.\n",i); /* stop the URB */ usb_kill_urb(d->urb_list[i]); @@ -107,9 +139,9 @@ int dvb_usb_urb_submit(struct dvb_usb_device *d) { int i,ret; for (i = 0; i < d->urbs_initialized; i++) { - deb_info("submitting URB no. %d\n",i); + deb_ts("submitting URB no. %d\n",i); if ((ret = usb_submit_urb(d->urb_list[i],GFP_ATOMIC))) { - err("could not submit URB no. %d - get them all back\n",i); + err("could not submit URB no. %d - get them all back",i); dvb_usb_urb_kill(d); return ret; } @@ -118,32 +150,78 @@ int dvb_usb_urb_submit(struct dvb_usb_device *d) return 0; } -static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d) +static int dvb_usb_free_stream_buffers(struct dvb_usb_device *d) { - int i,bufsize = d->props.urb.count * d->props.urb.u.bulk.buffersize; + if (d->state & DVB_USB_STATE_URB_BUF) { + while (d->buf_num) { + d->buf_num--; + deb_mem("freeing buffer %d\n",d->buf_num); + usb_buffer_free(d->udev, d->buf_size, + d->buf_list[d->buf_num], d->dma_addr[d->buf_num]); + } + kfree(d->buf_list); + kfree(d->dma_addr); + } + + d->state &= ~DVB_USB_STATE_URB_BUF; - deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize); - /* allocate the actual buffer for the URBs */ - if ((d->buffer = usb_buffer_alloc(d->udev, bufsize, SLAB_ATOMIC, &d->dma_handle)) == NULL) { - deb_info("not enough memory for urb-buffer allocation.\n"); + return 0; +} + +static int dvb_usb_allocate_stream_buffers(struct dvb_usb_device *d, int num, unsigned long size) +{ + d->buf_num = 0; + d->buf_size = size; + + deb_mem("all in all I will use %lu bytes for streaming\n",num*size); + + if ((d->buf_list = kmalloc(num*sizeof(u8 *), GFP_ATOMIC)) == NULL) + return -ENOMEM; + + if ((d->dma_addr = kmalloc(num*sizeof(dma_addr_t), GFP_ATOMIC)) == NULL) { + kfree(d->buf_list); return -ENOMEM; } - deb_info("allocation successful\n"); - memset(d->buffer,0,bufsize); + memset(d->buf_list,0,num*sizeof(u8 *)); + memset(d->dma_addr,0,num*sizeof(dma_addr_t)); d->state |= DVB_USB_STATE_URB_BUF; + for (d->buf_num = 0; d->buf_num < num; d->buf_num++) { + deb_mem("allocating buffer %d\n",d->buf_num); + if (( d->buf_list[d->buf_num] = + usb_buffer_alloc(d->udev, size, SLAB_ATOMIC, + &d->dma_addr[d->buf_num]) ) == NULL) { + deb_mem("not enough memory for urb-buffer allocation.\n"); + dvb_usb_free_stream_buffers(d); + return -ENOMEM; + } + deb_mem("buffer %d: %p (dma: %d)\n",d->buf_num,d->buf_list[d->buf_num],d->dma_addr[d->buf_num]); + memset(d->buf_list[d->buf_num],0,size); + } + deb_mem("allocation successful\n"); + + return 0; +} + +static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d) +{ + int i; + + if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count, + d->props.urb.u.bulk.buffersize)) < 0) + return i; + /* allocate the URBs */ for (i = 0; i < d->props.urb.count; i++) { - if (!(d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) { + if ((d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL) return -ENOMEM; - } usb_fill_bulk_urb( d->urb_list[i], d->udev, usb_rcvbulkpipe(d->udev,d->props.urb.endpoint), - &d->buffer[i*d->props.urb.u.bulk.buffersize], + d->buf_list[i], d->props.urb.u.bulk.buffersize, - dvb_usb_bulk_urb_complete, d); + dvb_usb_urb_complete, d); d->urb_list[i]->transfer_flags = 0; d->urbs_initialized++; @@ -151,6 +229,47 @@ static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d) return 0; } +static int dvb_usb_isoc_urb_init(struct dvb_usb_device *d) +{ + int i,j; + + if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count, + d->props.urb.u.isoc.framesize*d->props.urb.u.isoc.framesperurb)) < 0) + return i; + + /* allocate the URBs */ + for (i = 0; i < d->props.urb.count; i++) { + struct urb *urb; + int frame_offset = 0; + if ((d->urb_list[i] = + usb_alloc_urb(d->props.urb.u.isoc.framesperurb,GFP_ATOMIC)) == NULL) + return -ENOMEM; + + urb = d->urb_list[i]; + + urb->dev = d->udev; + urb->context = d; + urb->complete = dvb_usb_urb_complete; + urb->pipe = usb_rcvisocpipe(d->udev,d->props.urb.endpoint); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->interval = d->props.urb.u.isoc.interval; + urb->number_of_packets = d->props.urb.u.isoc.framesperurb; + urb->transfer_buffer_length = d->buf_size; + urb->transfer_buffer = d->buf_list[i]; + urb->transfer_dma = d->dma_addr[i]; + + for (j = 0; j < d->props.urb.u.isoc.framesperurb; j++) { + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = d->props.urb.u.isoc.framesize; + frame_offset += d->props.urb.u.isoc.framesize; + } + + d->urbs_initialized++; + } + return 0; + +} + int dvb_usb_urb_init(struct dvb_usb_device *d) { /* @@ -174,8 +293,7 @@ int dvb_usb_urb_init(struct dvb_usb_device *d) case DVB_USB_BULK: return dvb_usb_bulk_urb_init(d); case DVB_USB_ISOC: - err("isochronous transfer not yet implemented in dvb-usb."); - return -EINVAL; + return dvb_usb_isoc_urb_init(d); default: err("unkown URB-type for data transfer."); return -EINVAL; @@ -191,7 +309,7 @@ int dvb_usb_urb_exit(struct dvb_usb_device *d) if (d->state & DVB_USB_STATE_URB_LIST) { for (i = 0; i < d->urbs_initialized; i++) { if (d->urb_list[i] != NULL) { - deb_info("freeing URB no. %d.\n",i); + deb_mem("freeing URB no. %d.\n",i); /* free the URBs */ usb_free_urb(d->urb_list[i]); } @@ -202,10 +320,6 @@ int dvb_usb_urb_exit(struct dvb_usb_device *d) d->state &= ~DVB_USB_STATE_URB_LIST; } - if (d->state & DVB_USB_STATE_URB_BUF) - usb_buffer_free(d->udev, d->props.urb.u.bulk.buffersize * d->props.urb.count, - d->buffer, d->dma_handle); - - d->state &= ~DVB_USB_STATE_URB_BUF; + dvb_usb_free_stream_buffers(d); return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index abcee1943f6..6c627e9ea64 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -189,6 +189,7 @@ struct dvb_usb_properties { struct { int framesperurb; int framesize; + int interval; } isoc; } u; } urb; @@ -207,19 +208,28 @@ struct dvb_usb_properties { * @udev: pointer to the device's struct usb_device. * @urb_list: array of dynamically allocated struct urb for the MPEG2-TS- * streaming. - * @buffer: buffer used to streaming. - * @dma_handle: dma_addr_t for buffer. + * + * @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. + * * @feedcount: number of reqested feeds (used for streaming-activation) * @pid_filtering: is hardware pid_filtering used or not. + * * @usb_sem: semaphore of USB control messages (reading needs two messages) * @i2c_sem: semaphore for i2c-transfers + * * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB * @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 + * + * @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. @@ -253,8 +263,12 @@ struct dvb_usb_device { /* usb */ struct usb_device *udev; struct urb **urb_list; - u8 *buffer; - dma_addr_t dma_handle; + + int buf_num; + unsigned long buf_size; + u8 **buf_list; + dma_addr_t *dma_addr; + int urbs_initialized; int urbs_submitted; -- cgit v1.2.3 From 49dc82fdac3866e6ce9c978df80cedfb735d740c Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:09 -0700 Subject: [PATCH] dvb: frontend: add FMD1216ME PLL o change dvb-pll desc to take the frequency as parameter for setbw-callback into consideration o added dvb-pll desc for Philips FMD1216ME (needed for cxusb) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/dvb-pll.c | 35 +++++++++++++++++++++++++++++++---- drivers/media/dvb/frontends/dvb-pll.h | 3 ++- 2 files changed, 33 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index f73b5f48e23..81852686980 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -55,7 +55,7 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { }; EXPORT_SYMBOL(dvb_pll_thomson_dtt7610); -static void thomson_dtt759x_bw(u8 *buf, int bandwidth) +static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth) { if (BANDWIDTH_7_MHZ == bandwidth) buf[3] |= 0x10; @@ -146,7 +146,7 @@ EXPORT_SYMBOL(dvb_pll_env57h1xd5); /* Philips TDA6650/TDA6651 * used in Panasonic ENV77H11D5 */ -static void tda665x_bw(u8 *buf, int bandwidth) +static void tda665x_bw(u8 *buf, u32 freq, int bandwidth) { if (bandwidth == BANDWIDTH_8_MHZ) buf[3] |= 0x08; @@ -178,7 +178,7 @@ EXPORT_SYMBOL(dvb_pll_tda665x); /* Infineon TUA6034 * used in LG TDTP E102P */ -static void tua6034_bw(u8 *buf, int bandwidth) +static void tua6034_bw(u8 *buf, u32 freq, int bandwidth) { if (BANDWIDTH_7_MHZ != bandwidth) buf[3] |= 0x08; @@ -198,6 +198,33 @@ struct dvb_pll_desc dvb_pll_tua6034 = { }; EXPORT_SYMBOL(dvb_pll_tua6034); +/* Philips FMD1216ME + * used in Medion Hybrid PCMCIA card and USB Box + */ +static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth) +{ + if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000) + buf[3] |= 0x08; +} + +struct dvb_pll_desc dvb_pll_fmd1216me = { + .name = "placeholder", + .min = 50870000, + .max = 858000000, + .setbw = fmd1216me_bw, + .count = 7, + .entries = { + { 143870000, 36213333, 166667, 0xbc, 0x41 }, + { 158870000, 36213333, 166667, 0xf4, 0x41 }, + { 329870000, 36213333, 166667, 0xbc, 0x42 }, + { 441870000, 36213333, 166667, 0xf4, 0x42 }, + { 625870000, 36213333, 166667, 0xbc, 0x44 }, + { 803870000, 36213333, 166667, 0xf4, 0x44 }, + { 999999999, 36213333, 166667, 0xfc, 0x44 }, + } +}; +EXPORT_SYMBOL(dvb_pll_fmd1216me); + /* ----------------------------------------------------------- */ /* code */ @@ -231,7 +258,7 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, buf[3] = desc->entries[i].cb2; if (desc->setbw) - desc->setbw(buf, bandwidth); + desc->setbw(buf, freq, bandwidth); if (debug) printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index b796778624b..dc4e1d49ef8 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -9,7 +9,7 @@ struct dvb_pll_desc { char *name; u32 min; u32 max; - void (*setbw)(u8 *buf, int bandwidth); + void (*setbw)(u8 *buf, u32 freq, int bandwidth); int count; struct { u32 limit; @@ -30,6 +30,7 @@ extern struct dvb_pll_desc dvb_pll_tua6010xs; extern struct dvb_pll_desc dvb_pll_env57h1xd5; extern struct dvb_pll_desc dvb_pll_tua6034; extern struct dvb_pll_desc dvb_pll_tda665x; +extern struct dvb_pll_desc dvb_pll_fmd1216me; int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, u32 freq, int bandwidth); -- cgit v1.2.3 From 22c6d93a73105fddd58796d7cb10f5f90ee2a338 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:10 -0700 Subject: [PATCH] dvb: usb: support Medion hybrid USB2.0 DVB-T/analogue box Add preliminary support for the Medion Hybrid USB2.0 DVB-T/Analogue box. Analogue part is not working yet (cx25842 --> ivtv?). Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/Kconfig | 16 ++ drivers/media/dvb/dvb-usb/Makefile | 3 + drivers/media/dvb/dvb-usb/cxusb.c | 287 ++++++++++++++++++++++++++++++++ drivers/media/dvb/dvb-usb/cxusb.h | 30 ++++ drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 + 5 files changed, 338 insertions(+) create mode 100644 drivers/media/dvb/dvb-usb/cxusb.c create mode 100644 drivers/media/dvb/dvb-usb/cxusb.h (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 8aa32f6e447..1a69130a846 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -21,12 +21,14 @@ config DVB_USB_DEBUG config DVB_USB_A800 tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" depends on DVB_USB + select DVB_DIB3000MC help Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. config DVB_USB_DIBUSB_MB tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" depends on DVB_USB + select DVB_DIB3000MB help Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by DiBcom () equipped with a DiB3000M-B demodulator. @@ -52,6 +54,7 @@ config DVB_USB_DIBUSB_MB config DVB_USB_DIBUSB_MC tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" depends on DVB_USB + select DVB_DIB3000MC help Support for 2.0 DVB-T receivers based on reference designs made by DiBcom () equipped with a DiB3000M-C/P demodulator. @@ -66,12 +69,24 @@ config DVB_USB_DIBUSB_MC config DVB_USB_UMT_010 tristate "HanfTek UMT-010 DVB-T USB2.0 support" depends on DVB_USB + select DVB_DIB3000MC help Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. +config DVB_USB_CXUSB + tristate "Medion MD95700 hybrid USB2.0 (Conexant) support" + depends on DVB_USB + select DVB_CX22702 + help + Say Y here to support the Medion MD95700 hybrid USB2.0 device. Currently + only the DVB-T part is supported and MPEG2 data transfer are not working + :(. + config DVB_USB_DIGITV tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" depends on DVB_USB + select DVB_NXT6000 + select DVB_MT352 help Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver. @@ -87,6 +102,7 @@ config DVB_USB_VP7045 config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" depends on DVB_USB + select DVB_DIB3000MC help Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index d65b50f9abb..746d87ed6f3 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -27,4 +27,7 @@ obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o dvb-usb-digitv-objs = digitv.o obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o +dvb-usb-cxusb-objs = cxusb.o +obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o + EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c new file mode 100644 index 00000000000..0324807376c --- /dev/null +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -0,0 +1,287 @@ +/* DVB USB compliant linux driver for Conexant USB reference design. + * + * The Conexant reference design I saw on their website was only for analogue + * capturing (using the cx25842). The box I took to write this driver (reverse + * engineered) is the one labeled Medion MD95700. In addition to the cx25842 + * for analogue capturing it also has a cx22702 DVB-T demodulator on the main + * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard. + * + * Maybe it is a little bit premature to call this driver cxusb, but I assume + * the USB protocol is identical or at least inherited from the reference + * design, so it can be reused for the "analogue-only" device (if it will + * appear at all). + * + * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue + * part + * + * FIXME: We're getting a lock and signal, but the isochronous transfer is empty + * for DVB-T. + * + * Copyright (C) 2005 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 "cxusb.h" + +#include "cx22702.h" + +/* debug */ +int dvb_usb_cxusb_debug; +module_param_named(debug,dvb_usb_cxusb_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); + +static int cxusb_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) +{ + int wo = (rbuf == NULL || rlen == 0); /* write-only */ + u8 sndbuf[1+wlen]; + memset(sndbuf,0,1+wlen); + + sndbuf[0] = cmd; + memcpy(&sndbuf[1],wbuf,wlen); + if (wo) + dvb_usb_generic_write(d,sndbuf,1+wlen); + else + dvb_usb_generic_rw(d,sndbuf,1+wlen,rbuf,rlen,0); + + return 0; +} + +/* I2C */ +static void cxusb_set_i2c_path(struct dvb_usb_device *d, enum cxusb_i2c_pathes path) +{ + struct cxusb_state *st = d->priv; + u8 o[2],i; + + if (path == st->cur_i2c_path) + return; + + o[0] = IOCTL_SET_I2C_PATH; + switch (path) { + case PATH_CX22702: + o[1] = 0; + break; + case PATH_TUNER_OTHER: + o[1] = 1; + break; + default: + err("unkown i2c path"); + return; + } + cxusb_ctrl_msg(d,CMD_IOCTL,o,2,&i,1); + + if (i != 0x01) + deb_info("i2c_path setting failed.\n"); + + st->cur_i2c_path = path; +} + +static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + int i; + + if (down_interruptible(&d->i2c_sem) < 0) + return -EAGAIN; + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + for (i = 0; i < num; i++) { + + switch (msg[i].addr) { + case 0x63: + cxusb_set_i2c_path(d,PATH_CX22702); + break; + default: + cxusb_set_i2c_path(d,PATH_TUNER_OTHER); + break; + } + + /* read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len]; + obuf[0] = msg[i].len; + obuf[1] = msg[i+1].len; + obuf[2] = msg[i].addr; + memcpy(&obuf[3],msg[i].buf,msg[i].len); + + if (cxusb_ctrl_msg(d, CMD_I2C_READ, + obuf, 3+msg[i].len, + ibuf, 1+msg[i+1].len) < 0) + break; + + if (ibuf[0] != 0x08) + deb_info("i2c read could have been failed\n"); + + memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len); + + i++; + } else { /* write */ + u8 obuf[2+msg[i].len], ibuf; + obuf[0] = msg[i].addr; + obuf[1] = msg[i].len; + memcpy(&obuf[2],msg[i].buf,msg[i].len); + + if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0) + break; + if (ibuf != 0x08) + deb_info("i2c write could have been failed\n"); + } + } + + up(&d->i2c_sem); + return i; +} + +static u32 cxusb_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm cxusb_i2c_algo = { + .name = "Conexant USB I2C algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = cxusb_i2c_xfer, + .functionality = cxusb_i2c_func, +}; + +static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + return 0; +} + +static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) +{ + return 0; +} + +struct cx22702_config cxusb_cx22702_config = { + .demod_address = 0x63, + + .pll_init = dvb_usb_pll_init_i2c, + .pll_set = dvb_usb_pll_set_i2c, +}; + +/* Callbacks for DVB USB */ +static int cxusb_tuner_attach(struct dvb_usb_device *d) +{ + u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 }; + d->pll_addr = 0x61; + memcpy(d->pll_init,bpll,4); + d->pll_desc = &dvb_pll_fmd1216me; + return 0; +} + +static int cxusb_frontend_attach(struct dvb_usb_device *d) +{ + u8 buf[2] = { 0x03, 0x00 }; + u8 b = 0; + + cxusb_ctrl_msg(d,0xde,&b,0,NULL,0); + cxusb_set_i2c_path(d,PATH_TUNER_OTHER); + cxusb_ctrl_msg(d,CMD_POWER_OFF, NULL, 0, &b, 1); + + if (usb_set_interface(d->udev,0,6) < 0) + err("set interface failed\n"); + + cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0); + cxusb_set_i2c_path(d,PATH_CX22702); + cxusb_ctrl_msg(d,CMD_POWER_ON, NULL, 0, &b, 1); + + if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + +/* DVB USB Driver stuff */ +static struct dvb_usb_properties cxusb_properties; + +static int cxusb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE); +} + +static struct usb_device_id cxusb_table [] = { + { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE (usb, cxusb_table); + +static struct dvb_usb_properties cxusb_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .streaming_ctrl = cxusb_streaming_ctrl, + .power_ctrl = cxusb_power_ctrl, + .frontend_attach = cxusb_frontend_attach, + .tuner_attach = cxusb_tuner_attach, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_ISOC, + .count = 5, + .endpoint = 0x02, + .u = { + .isoc = { + .framesperurb = 64, + .framesize = 940*3, + .interval = 1, + } + } + }, + + .num_device_descs = 1, + .devices = { + { "Medion MD95700 (MDUSBTV-HYBRID)", + { NULL }, + { &cxusb_table[0], NULL }, + }, + } +}; + +static struct usb_driver cxusb_driver = { + .owner = THIS_MODULE, + .name = "cxusb", + .probe = cxusb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = cxusb_table, +}; + +/* module stuff */ +static int __init cxusb_module_init(void) +{ + int result; + if ((result = usb_register(&cxusb_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit cxusb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&cxusb_driver); +} + +module_init (cxusb_module_init); +module_exit (cxusb_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); +MODULE_VERSION("1.0-alpha"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h new file mode 100644 index 00000000000..1d79016e319 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/cxusb.h @@ -0,0 +1,30 @@ +#ifndef _DVB_USB_CXUSB_H_ +#define _DVB_USB_CXUSB_H_ + +#define DVB_USB_LOG_PREFIX "digitv" +#include "dvb-usb.h" + +extern int dvb_usb_cxusb_debug; +#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args) + +/* usb commands - some of it are guesses, don't have a reference yet */ +#define CMD_I2C_WRITE 0x08 +#define CMD_I2C_READ 0x09 + +#define CMD_IOCTL 0x0e +#define IOCTL_SET_I2C_PATH 0x02 + +#define CMD_POWER_OFF 0x50 +#define CMD_POWER_ON 0x51 + +enum cxusb_i2c_pathes { + PATH_UNDEF = 0x00, + PATH_CX22702 = 0x01, + PATH_TUNER_OTHER = 0x02, +}; + +struct cxusb_state { + enum cxusb_i2c_pathes cur_i2c_path; +}; + +#endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index bcb34191868..de2463bae22 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -24,6 +24,7 @@ #define USB_VID_HANFTEK 0x15f4 #define USB_VID_HAUPPAUGE 0x2040 #define USB_VID_HYPER_PALTEK 0x1025 +#define USB_VID_MEDION 0x1660 #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_TWINHAN 0x1822 #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 @@ -78,6 +79,7 @@ #define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820 #define USB_PID_DVICO_BLUEBIRD_LGZ201_1 0xdb01 #define USB_PID_DVICO_BLUEBIRD_TH7579_2 0xdb11 +#define USB_PID_MEDION_MD95700 0x0932 #endif -- cgit v1.2.3 From c9b06fa47e1c1ff8704461c7fd6a99e3621ba0e6 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:11 -0700 Subject: [PATCH] dvb: usb: add module parm to disable remote control polling Add module parameter to deactive remote control polling. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dvb-usb-common.h | 1 + drivers/media/dvb/dvb-usb/dvb-usb-init.c | 4 ++++ drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 8 +++++++- 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h index abf7d2f562b..7300489d3e2 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h @@ -12,6 +12,7 @@ #include "dvb-usb.h" extern int dvb_usb_debug; +extern int dvb_usb_disable_rc_polling; #define deb_info(args...) dprintk(dvb_usb_debug,0x01,args) #define deb_xfer(args...) dprintk(dvb_usb_debug,0x02,args) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index 3aadec974cf..c3b3ae4f3ec 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -18,6 +18,10 @@ 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 (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)."); + /* general initialization functions */ int dvb_usb_exit(struct dvb_usb_device *d) { diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index 9f1e23f82ba..f4038bf21c9 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -21,6 +21,10 @@ static void dvb_usb_read_remote_control(void *data) /* 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_query(d,&event,&state)) { err("error while querying for an remote control event."); goto schedule; @@ -85,7 +89,9 @@ schedule: int dvb_usb_remote_init(struct dvb_usb_device *d) { int i; - if (d->props.rc_key_map == NULL) + if (d->props.rc_key_map == NULL || + d->props.rc_query == NULL || + dvb_usb_disable_rc_polling) return 0; /* Initialise the remote-control structures.*/ -- cgit v1.2.3 From 0589b8e4fd24885a00d8954aef57c3319d161fee Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:12 -0700 Subject: [PATCH] dvb: frontend: add ALPS TDED4 PLL Add dvb_pll_desc for ALPS TDED4 used in Nebula USB boxes. Changed the name-field of the FMD1216. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/dvb-pll.c | 26 +++++++++++++++++++++++++- drivers/media/dvb/frontends/dvb-pll.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 81852686980..8be143b7ce4 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -208,7 +208,7 @@ static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth) } struct dvb_pll_desc dvb_pll_fmd1216me = { - .name = "placeholder", + .name = "Philips FMD1216ME", .min = 50870000, .max = 858000000, .setbw = fmd1216me_bw, @@ -225,6 +225,30 @@ struct dvb_pll_desc dvb_pll_fmd1216me = { }; EXPORT_SYMBOL(dvb_pll_fmd1216me); +/* ALPS TDED4 + * used in Nebula-Cards and USB boxes + */ +static void tded4_bw(u8 *buf, u32 freq, int bandwidth) +{ + if (bandwidth == BANDWIDTH_8_MHZ) + buf[3] |= 0x04; +} + +struct dvb_pll_desc dvb_pll_tded4 = { + .name = "ALPS TDED4", + .min = 47000000, + .max = 863000000, + .setbw = tded4_bw, + .count = 4, + .entries = { + { 153000000, 36166667, 166667, 0x85, 0x01 }, + { 470000000, 36166667, 166667, 0x85, 0x02 }, + { 823000000, 36166667, 166667, 0x85, 0x08 }, + { 999999999, 36166667, 166667, 0x85, 0x88 }, + } +}; +EXPORT_SYMBOL(dvb_pll_tded4); + /* ----------------------------------------------------------- */ /* code */ diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index dc4e1d49ef8..57b64ffee40 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -31,6 +31,7 @@ extern struct dvb_pll_desc dvb_pll_env57h1xd5; extern struct dvb_pll_desc dvb_pll_tua6034; extern struct dvb_pll_desc dvb_pll_tda665x; extern struct dvb_pll_desc dvb_pll_fmd1216me; +extern struct dvb_pll_desc dvb_pll_tded4; int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, u32 freq, int bandwidth); -- cgit v1.2.3 From 78c6e73f5a27f01e45e86a4e3d13863c9cce6374 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:13 -0700 Subject: [PATCH] dvb: usb: digitv-usb fixes Some more work on the digitv-usb driver: o MT352 initialization and PLL-programming o I2c-transfer fixed. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/digitv.c | 69 +++++++++++++------------------------- 1 file changed, 24 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 5acf3fde952..f272d34f772 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -1,10 +1,9 @@ /* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0 * receiver * - * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) and - * Allan Third (allan.third@cs.man.ac.uk) + * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) * - * partly based on the SDK published by Nebula Electronics (TODO do we want this line ?) + * partly based on the SDK published by Nebula Electronics * * 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 @@ -95,41 +94,20 @@ static int digitv_identify_state (struct usb_device *udev, struct static int digitv_mt352_demod_init(struct dvb_frontend *fe) { - static u8 mt352_clock_config[] = { 0x89, 0x38, 0x2d }; - static u8 mt352_reset[] = { 0x50, 0x80 }; - static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 }; - - static u8 mt352_agc_cfg[] = { 0x68, 0xa0 }; - static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0xa0 }; - static u8 mt352_acq_ctl[] = { 0x53, 0x50 }; - static u8 mt352_agc_target[] = { 0x67, 0x20 }; - - static u8 mt352_rs_err_per[] = { 0x7c, 0x00, 0x01 }; - static u8 mt352_snr_select[] = { 0x79, 0x00, 0x20 }; - - static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x05 }; + static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 }; + static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50, + 0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00, + 0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f, + 0x75, 0x32 }; + int i; - static u8 mt352_scan_ctl[] = { 0x88, 0x0f }; - static u8 mt352_capt_range[] = { 0x75, 0x32 }; + for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2) + mt352_write(fe, &reset_buf[i], 2); - mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); - mt352_write(fe, mt352_reset, sizeof(mt352_reset)); msleep(1); - mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio)); - - mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl)); - mt352_write(fe, mt352_agc_target, sizeof(mt352_agc_target)); - - - mt352_write(fe, mt352_rs_err_per, sizeof(mt352_rs_err_per)); - mt352_write(fe, mt352_snr_select, sizeof(mt352_snr_select)); - mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1)); - - mt352_write(fe, mt352_scan_ctl, sizeof(mt352_scan_ctl)); - mt352_write(fe, mt352_capt_range, sizeof(mt352_capt_range)); + for (i = 0; i < ARRAY_SIZE(init_buf); i += 2) + mt352_write(fe, &init_buf[i], 2); return 0; } @@ -137,7 +115,7 @@ static int digitv_mt352_demod_init(struct dvb_frontend *fe) static struct mt352_config digitv_mt352_config = { .demod_address = 0x0, /* ignored by the digitv anyway */ .demod_init = digitv_mt352_demod_init, - .pll_set = NULL, /* TODO */ + .pll_set = dvb_usb_pll_set, }; static struct nxt6000_config digitv_nxt6000_config = { @@ -150,9 +128,9 @@ static struct nxt6000_config digitv_nxt6000_config = { static int digitv_frontend_attach(struct dvb_usb_device *d) { - if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) == NULL) + if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) return 0; - if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) == NULL) { + if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) { warn("nxt6000 support is not done yet, in fact you are one of the first " "person who wants to use this device in Linux. Please report to " @@ -163,6 +141,13 @@ static int digitv_frontend_attach(struct dvb_usb_device *d) return -EIO; } +static int digitv_tuner_attach(struct dvb_usb_device *d) +{ + d->pll_addr = 0x60; + d->pll_desc = &dvb_pll_tded4; + return 0; +} + static struct dvb_usb_rc_key digitv_rc_keys[] = { { 0x00, 0x16, KEY_POWER }, /* dummy key */ }; @@ -184,7 +169,6 @@ int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } - /* DVB USB Driver stuff */ static struct dvb_usb_properties digitv_properties; @@ -208,13 +192,8 @@ static struct dvb_usb_properties digitv_properties = { .size_of_priv = 0, - .streaming_ctrl = NULL, - .pid_filter = NULL, - .pid_filter_ctrl = NULL, - .power_ctrl = NULL, .frontend_attach = digitv_frontend_attach, - .tuner_attach = NULL, // digitv_tuner_attach, - .read_mac_address = NULL, + .tuner_attach = digitv_tuner_attach, .rc_interval = 1000, .rc_key_map = digitv_rc_keys, @@ -238,7 +217,7 @@ static struct dvb_usb_properties digitv_properties = { } }, - .num_device_descs = 2, + .num_device_descs = 1, .devices = { { "Nebula Electronics uDigiTV DVB-T USB2.0)", { &digitv_table[0], NULL }, -- cgit v1.2.3 From c251ef6167c46152e247fc41628a4ac2d0aca33e Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:14 -0700 Subject: [PATCH] dvb: usb: dvb_usb_properties init fix There was no pid-filter-count set for some devices - led to an error. Thanks to Gerolf Wendland. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dibusb-mb.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index aee6263f07c..691900578ee 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -209,6 +209,8 @@ static struct dvb_usb_properties dibusb1_1_properties = { static struct dvb_usb_properties dibusb1_1_an2235_properties = { .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, + .pid_filter_count = 16, + .usb_ctrl = CYPRESS_AN2235, .firmware = "dvb-usb-dibusb-an2235-01.fw", @@ -263,6 +265,8 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { static struct dvb_usb_properties dibusb2_0b_properties = { .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, + .pid_filter_count = 32, + .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-adstech-usb2-02.fw", -- cgit v1.2.3 From 8257e8a444a2b81952de9f8bfeb3a4726c0f7d5b Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:15 -0700 Subject: [PATCH] dvb: usb: cxusb DVB-T fixes cxusb DVB-T fixes. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/cxusb.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 0324807376c..b4bb206a510 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -14,9 +14,6 @@ * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue * part * - * FIXME: We're getting a lock and signal, but the isochronous transfer is empty - * for DVB-T. - * * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) * * This program is free software; you can redistribute it and/or modify it @@ -157,12 +154,20 @@ static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) { + u8 buf[2] = { 0x03, 0x00 }; + if (onoff) + cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0); + else + cxusb_ctrl_msg(d,0x37, NULL, 0, NULL, 0); + return 0; } struct cx22702_config cxusb_cx22702_config = { .demod_address = 0x63, + .output_mode = CX22702_PARALLEL_OUTPUT, + .pll_init = dvb_usb_pll_init_i2c, .pll_set = dvb_usb_pll_set_i2c, }; @@ -182,12 +187,15 @@ static int cxusb_frontend_attach(struct dvb_usb_device *d) u8 buf[2] = { 0x03, 0x00 }; u8 b = 0; + if (usb_set_interface(d->udev,0,0) < 0) + err("set interface to alts=0 failed"); + cxusb_ctrl_msg(d,0xde,&b,0,NULL,0); cxusb_set_i2c_path(d,PATH_TUNER_OTHER); cxusb_ctrl_msg(d,CMD_POWER_OFF, NULL, 0, &b, 1); if (usb_set_interface(d->udev,0,6) < 0) - err("set interface failed\n"); + err("set interface failed"); cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0); cxusb_set_i2c_path(d,PATH_CX22702); @@ -236,9 +244,9 @@ static struct dvb_usb_properties cxusb_properties = { .endpoint = 0x02, .u = { .isoc = { - .framesperurb = 64, - .framesize = 940*3, - .interval = 1, + .framesperurb = 32, + .framesize = 940, + .interval = 5, } } }, -- cgit v1.2.3 From 2f7f96b95991bcbe52dee5aa50a19130873738bf Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:16 -0700 Subject: [PATCH] dvb: usb: add VideoWalker DVB-T USB ids Add another USB ID pair for the VideoWalker USB DVB-T. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dibusb-mb.c | 12 +++++++++--- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 3 +++ drivers/media/dvb/dvb-usb/dvb-usb.h | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 691900578ee..1cd49025289 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -123,11 +123,13 @@ static struct usb_device_id dibusb_dib3000mb_table [] = { /* device ID with default DIBUSB2_0-firmware and with the hacked firmware */ /* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, +/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) }, +/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) }, // #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs -/* 25 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, +/* 27 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, #endif { } /* Terminating entry */ }; @@ -170,7 +172,7 @@ static struct dvb_usb_properties dibusb1_1_properties = { } }, - .num_device_descs = 8, + .num_device_descs = 9, .devices = { { "AVerMedia AverTV DVBT USB1.1", { &dibusb_dib3000mb_table[0], NULL }, @@ -204,6 +206,10 @@ static struct dvb_usb_properties dibusb1_1_properties = { { &dibusb_dib3000mb_table[19], NULL }, { &dibusb_dib3000mb_table[20], NULL }, }, + { "VideoWalker DVB-T USB", + { &dibusb_dib3000mb_table[25], NULL }, + { &dibusb_dib3000mb_table[26], NULL }, + }, } }; @@ -256,7 +262,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { }, #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", - { &dibusb_dib3000mb_table[25], NULL }, + { &dibusb_dib3000mb_table[27], NULL }, { NULL }, }, #endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index de2463bae22..9fea93df6ab 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -24,6 +24,7 @@ #define USB_VID_HANFTEK 0x15f4 #define USB_VID_HAUPPAUGE 0x2040 #define USB_VID_HYPER_PALTEK 0x1025 +#define USB_VID_KYE 0x0458 #define USB_VID_MEDION 0x1660 #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_TWINHAN 0x1822 @@ -80,6 +81,8 @@ #define USB_PID_DVICO_BLUEBIRD_LGZ201_1 0xdb01 #define USB_PID_DVICO_BLUEBIRD_TH7579_2 0xdb11 #define USB_PID_MEDION_MD95700 0x0932 +#define USB_PID_KYE_DVB_T_COLD 0x701e +#define USB_PID_KYE_DVB_T_WARM 0x701f #endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 6c627e9ea64..a80567caf50 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -195,7 +195,7 @@ struct dvb_usb_properties { } urb; int num_device_descs; - struct dvb_usb_device_description devices[8]; + struct dvb_usb_device_description devices[9]; }; -- cgit v1.2.3 From 97432808ee367e15485e55c734ba04ca290a306d Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:17 -0700 Subject: [PATCH] dvb: usb: digitv memcpy fix Fix memcpy copying into the wrong destination. Thanks to Allan Third for reporting. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/digitv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index f272d34f772..8155a26f0dd 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -37,7 +37,7 @@ static int digitv_ctrl_msg(struct dvb_usb_device *d, dvb_usb_generic_write(d,sndbuf,7); } else { dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10); - memcpy(&rbuf,&rcvbuf[3],rlen); + memcpy(rbuf,&rcvbuf[3],rlen); } return 0; } -- cgit v1.2.3 From d72fa1c91d721bf4c68a18f2d8fed820a8f1611e Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:20 -0700 Subject: [PATCH] dvb: usb Kconfig help text update o corrected some typos o added the Wikilink pointing to the USB device list Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/Kconfig | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 1a69130a846..d4deb75352c 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -3,19 +3,22 @@ config DVB_USB depends on DVB_CORE && USB select FW_LOADER help - By enabling this you will be able to choose the various USB 1.1 and - USB2.0 DVB devices. + 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 - + . - Say Y if you own an USB DVB device. + 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 help - Say Y if you want to enable debuging. See modinfo dvb-usb (and the + Say Y if you want to enable debugging. See modinfo dvb-usb (and the appropriate drivers) for debug levels. config DVB_USB_A800 @@ -79,8 +82,7 @@ config DVB_USB_CXUSB select DVB_CX22702 help Say Y here to support the Medion MD95700 hybrid USB2.0 device. Currently - only the DVB-T part is supported and MPEG2 data transfer are not working - :(. + only the DVB-T part is supported. config DVB_USB_DIGITV tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" -- cgit v1.2.3 From 2d188c68a04d89d9351c3130226d0e8af9439dda Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:21 -0700 Subject: [PATCH] dvb: usb: add vp7045 IR keymap Add keymap for Twinhan vp7045 remote control. Signed-off-by: Michael Paxton Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/vp7045.c | 39 +++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 02ecc9a8e3b..bb99cbc098f 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -94,13 +94,38 @@ static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff) /* The keymapping struct. Somehow this should be loaded to the driver, but * currently it is hardcoded. */ static struct dvb_usb_rc_key vp7045_rc_keys[] = { - /* insert the keys like this. to make the raw keys visible, enable - * debug=0x04 when loading dvb-usb-vp7045. */ - - /* these keys are probably wrong. I don't have a working IR-receiver on my - * vp7045, so I can't test it. Patches are welcome. */ - { 0x00, 0x01, KEY_1 }, - { 0x00, 0x02, KEY_2 }, + { 0x00, 0x16, KEY_POWER }, + { 0x00, 0x10, KEY_MUTE }, + { 0x00, 0x03, KEY_1 }, + { 0x00, 0x01, KEY_2 }, + { 0x00, 0x06, KEY_3 }, + { 0x00, 0x09, KEY_4 }, + { 0x00, 0x1d, KEY_5 }, + { 0x00, 0x1f, KEY_6 }, + { 0x00, 0x0d, KEY_7 }, + { 0x00, 0x19, KEY_8 }, + { 0x00, 0x1b, KEY_9 }, + { 0x00, 0x15, KEY_0 }, + { 0x00, 0x05, KEY_CHANNELUP }, + { 0x00, 0x02, KEY_CHANNELDOWN }, + { 0x00, 0x1e, KEY_VOLUMEUP }, + { 0x00, 0x0a, KEY_VOLUMEDOWN }, + { 0x00, 0x11, KEY_RECORD }, + { 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */ + { 0x00, 0x14, KEY_PLAY }, + { 0x00, 0x1a, KEY_STOP }, + { 0x00, 0x40, KEY_REWIND }, + { 0x00, 0x12, KEY_FASTFORWARD }, + { 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */ + { 0x00, 0x4c, KEY_PAUSE }, + { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */ + { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ + { 0x00, 0xa1, KEY_CANCEL }, /* Cancel */ + { 0x00, 0x1c, KEY_EPG }, /* EPG */ + { 0x00, 0x40, KEY_TAB }, /* Tab */ + { 0x00, 0x48, KEY_INFO }, /* Preview */ + { 0x00, 0x04, KEY_LIST }, /* RecordList */ + { 0x00, 0x0f, KEY_TEXT } /* Teletext */ }; static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state) -- cgit v1.2.3 From fb41f5a725d052d7542e0e966e5799b95c2648c8 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:23 -0700 Subject: [PATCH] dvb: usb: fix WideView USB ids o Steve Chang reported the real name behind 0x14aa: WideView, changed USB IDs accordingly. o fixed an assignment Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/Kconfig | 4 ++-- drivers/media/dvb/dvb-usb/dibusb-mb.c | 4 ++-- drivers/media/dvb/dvb-usb/dtt200u-fe.c | 4 ++-- drivers/media/dvb/dvb-usb/dtt200u.c | 16 ++++++++-------- drivers/media/dvb/dvb-usb/dtt200u.h | 4 ++-- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index d4deb75352c..91e88b2ed5d 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -109,9 +109,9 @@ config DVB_USB_NOVA_T_USB2 Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. config DVB_USB_DTT200U - tristate "Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 support" + tristate "WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 support" depends on DVB_USB help - Say Y here to support the Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver. + Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver. The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 1cd49025289..cda2179d61a 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -96,8 +96,8 @@ static int dibusb_probe(struct usb_interface *intf, /* do not change the order of the ID table */ static struct usb_device_id dibusb_dib3000mb_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_AVERMEDIA_DVBT_USB_COLD)}, -/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_AVERMEDIA_DVBT_USB_WARM)}, +/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD)}, +/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM)}, /* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) }, /* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) }, /* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) }, diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c index d17d768038c..7807f33573b 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c @@ -1,5 +1,5 @@ -/* Frontend part of the Linux driver for the Yakumo/Hama/Typhoon DVB-T - * USB2.0 receiver. +/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan DVB-T USB2.0 receiver. * * Copyright (C) 2005 Patrick Boettcher * diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index fb2b5a2da13..1ebd3eff96d 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -1,5 +1,5 @@ -/* DVB USB library compliant Linux driver for the Yakumo/Hama/Typhoon DVB-T - * USB2.0 receiver. +/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan DVB-T USB2.0 receiver. * * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * @@ -89,8 +89,8 @@ static int dtt200u_usb_probe(struct usb_interface *intf, } static struct usb_device_id dtt200u_usb_table [] = { - { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_DTT200U_COLD) }, - { USB_DEVICE(USB_VID_AVERMEDIA_UNK, USB_PID_DTT200U_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); @@ -127,8 +127,8 @@ static struct dvb_usb_properties dtt200u_properties = { .num_device_descs = 1, .devices = { - { .name = "Yakumo/Hama/Typhoon DVB-T USB2.0)", - .cold_ids = { &dtt200u_usb_table[0], &dtt200u_usb_table[2] }, + { .name = "WideView/Yakumo/Hama/Typhoon DVB-T USB2.0)", + .cold_ids = { &dtt200u_usb_table[0], NULL }, .warm_ids = { &dtt200u_usb_table[1], NULL }, }, { 0 }, @@ -138,7 +138,7 @@ static struct dvb_usb_properties dtt200u_properties = { /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver dtt200u_usb_driver = { .owner = THIS_MODULE, - .name = "Yakumo/Hama/Typhoon DVB-T USB2.0", + .name = "dtt200u", .probe = dtt200u_usb_probe, .disconnect = dvb_usb_device_exit, .id_table = dtt200u_usb_table, @@ -166,6 +166,6 @@ module_init(dtt200u_usb_module_init); module_exit(dtt200u_usb_module_exit); MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the Yakumo/Hama/Typhoon DVB-T USB2.0 device"); +MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 device"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h index ed414207151..9ab081a55b8 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.h +++ b/drivers/media/dvb/dvb-usb/dtt200u.h @@ -1,5 +1,5 @@ -/* Common header file of Linux driver for the Yakumo/Hama/Typhoon DVB-T - * USB2.0 receiver. +/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/ + * Typhoon/ Yuan DVB-T USB2.0 receiver. * * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 9fea93df6ab..75f4cb18a63 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -12,7 +12,7 @@ /* Vendor IDs */ #define USB_VID_ADSTECH 0x06e1 #define USB_VID_ANCHOR 0x0547 -#define USB_VID_AVERMEDIA_UNK 0x14aa +#define USB_VID_WIDEVIEW 0x14aa #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b #define USB_VID_COMPRO_UNK 0x145f -- cgit v1.2.3 From 04f3e5ea51248ff974a13ef2dd0145125c76204c Mon Sep 17 00:00:00 2001 From: Michael Paxton Date: Thu, 7 Jul 2005 17:58:24 -0700 Subject: [PATCH] dvb: usb: vp7045 IR map fix Correct two keys of the vp7045 remote control key mapping. Signed-off-by: Michael Paxton Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/vp7045.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index bb99cbc098f..72d5d3f7446 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -120,9 +120,9 @@ static struct dvb_usb_rc_key vp7045_rc_keys[] = { { 0x00, 0x4c, KEY_PAUSE }, { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */ { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ - { 0x00, 0xa1, KEY_CANCEL }, /* Cancel */ + { 0x00, 0x0c, KEY_CANCEL }, /* Cancel */ { 0x00, 0x1c, KEY_EPG }, /* EPG */ - { 0x00, 0x40, KEY_TAB }, /* Tab */ + { 0x00, 0x00, KEY_TAB }, /* Tab */ { 0x00, 0x48, KEY_INFO }, /* Preview */ { 0x00, 0x04, KEY_LIST }, /* RecordList */ { 0x00, 0x0f, KEY_TEXT } /* Teletext */ -- cgit v1.2.3 From 1df896aa239caf72483655290c40b21da536d85e Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:24 -0700 Subject: [PATCH] dvb: usb: IR input fixes o fixed usage of the correct number of events in keymapping-array o better place for return Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index f4038bf21c9..fc7800f1743 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -39,7 +39,7 @@ static void dvb_usb_read_remote_control(void *data) d->last_event = event; case REMOTE_KEY_REPEAT: deb_rc("key repeated\n"); - input_event(&d->rc_input_dev, EV_KEY, event, 1); + input_event(&d->rc_input_dev, EV_KEY, d->last_event, 1); input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0); input_sync(&d->rc_input_dev); break; @@ -160,12 +160,12 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d, break; } /* See if we can match the raw key code. */ - for (i = 0; i < sizeof(keymap)/sizeof(struct dvb_usb_rc_key); i++) + for (i = 0; i < d->props.rc_key_map_size; i++) if (keymap[i].custom == keybuf[1] && keymap[i].data == keybuf[3]) { *event = keymap[i].event; *state = REMOTE_KEY_PRESSED; - break; + return 0; } deb_err("key mapping failed - no appropriate key found in keymapping\n"); break; -- cgit v1.2.3 From 58769a5486bec8ed44b3b51029f8df8f13cddd5a Mon Sep 17 00:00:00 2001 From: Andrew Hodgson Date: Thu, 7 Jul 2005 17:58:26 -0700 Subject: [PATCH] dvb: usb: A800 rc and timeout fixes o add some remote control codes o not using HZ for control_msg-timeout Signed-off-by: Andrew Hodgson Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/a800.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index a3542935604..672037c2281 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -61,6 +61,12 @@ static struct dvb_usb_rc_key a800_rc_keys[] = { { 0x02, 0x00, KEY_LAST }, /* >>| / BLUE */ { 0x02, 0x04, KEY_EPG }, /* EPG */ { 0x02, 0x15, KEY_MENU }, /* MENU */ + + { 0x03, 0x03, KEY_CHANNELUP }, /* CH UP */ + { 0x03, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */ + { 0x03, 0x01, KEY_FIRST }, /* |<< / GREEN */ + { 0x03, 0x00, KEY_LAST }, /* >>| / BLUE */ + }; int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) @@ -68,7 +74,7 @@ int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) u8 key[5]; if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0), 0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5, - 2*HZ) != 5) + 2000) != 5) return -ENODEV; /* call the universal NEC remote processor, to find out the key's state and event */ -- cgit v1.2.3 From e161f817bebecc1c1cc461dc83cce2eafbed9ee9 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:27 -0700 Subject: [PATCH] dvb: usb: dont use HZ for timeouts Don't use HZ for usb-transfer-timeouts. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dvb-usb-urb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c index dcd8c2f915f..f5799a4c228 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_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen, - 2*HZ); + 2000); if (ret) err("bulk message failed: %d (%d/%d)",ret,wlen,actlen); @@ -43,7 +43,7 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen, - 2*HZ); + 2000); if (ret) err("recv bulk message failed: %d",ret); -- cgit v1.2.3 From 25de192660627e1e8dc8ee6a120ff8b54d108593 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Thu, 7 Jul 2005 17:58:28 -0700 Subject: [PATCH] dvb: ttpci: fix timeout handling to be save with PREEMPT Timeout handling fixed, especially for preemtible kernels and/or high system load. Signed-off-by: Oliver Endriss Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/common/saa7146_core.c | 11 +++--- drivers/media/dvb/ttpci/av7110_hw.c | 72 +++++++++++++++++++++++++------------ 2 files changed, 56 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 77ff2291156..cd5828b5e9e 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -62,13 +62,15 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data) int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) { unsigned long start; + int err; /* wait for registers to be programmed */ start = jiffies; while (1) { - if (saa7146_read(dev, MC2) & 2) - break; - if (time_after(jiffies, start + HZ/20)) { + err = time_after(jiffies, start + HZ/20); + if (saa7146_read(dev, MC2) & 2) + break; + if (err) { DEB_S(("timed out while waiting for registers getting programmed\n")); return -ETIMEDOUT; } @@ -79,10 +81,11 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) /* wait for transfer to complete */ start = jiffies; while (1) { + err = time_after(jiffies, start + HZ/4); if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) break; saa7146_read(dev, MC2); - if (time_after(jiffies, start + HZ/4)) { + if (err) { DEB_S(("timed out while waiting for transfer completion\n")); return -ETIMEDOUT; } diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c index aa1efce6cb3..1220826696c 100644 --- a/drivers/media/dvb/ttpci/av7110_hw.c +++ b/drivers/media/dvb/ttpci/av7110_hw.c @@ -308,6 +308,7 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) { unsigned long start; u32 stat; + int err; if (FW_VERSION(av7110->arm_app) <= 0x261c) { /* not supported by old firmware */ @@ -318,14 +319,14 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) /* new firmware */ start = jiffies; for (;;) { + err = time_after(jiffies, start + ARM_WAIT_FREE); if (down_interruptible(&av7110->dcomlock)) return -ERESTARTSYS; stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); up(&av7110->dcomlock); - if ((stat & flags) == 0) { + if ((stat & flags) == 0) break; - } - if (time_after(jiffies, start + ARM_WAIT_FREE)) { + if (err) { printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n", __FUNCTION__, stat & flags); return -ETIMEDOUT; @@ -342,6 +343,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) char *type = NULL; u16 flags[2] = {0, 0}; u32 stat; + int err; // dprintk(4, "%p\n", av7110); @@ -351,8 +353,11 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) } start = jiffies; - while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) { - if (time_after(jiffies, start + ARM_WAIT_FREE)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__); return -ETIMEDOUT; } @@ -363,8 +368,11 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) #ifndef _NOHANDSHAKE start = jiffies; - while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) { - if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); return -ETIMEDOUT; } @@ -401,6 +409,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) /* non-immediate COMMAND type */ start = jiffies; for (;;) { + err = time_after(jiffies, start + ARM_WAIT_FREE); stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); if (stat & flags[0]) { printk(KERN_ERR "%s: %s QUEUE overflow\n", @@ -409,7 +418,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) } if ((stat & flags[1]) == 0) break; - if (time_after(jiffies, start + ARM_WAIT_FREE)) { + if (err) { printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n", __FUNCTION__, type); return -ETIMEDOUT; @@ -432,12 +441,13 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) #ifdef COM_DEBUG start = jiffies; - while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) { - if (time_after(jiffies, start + ARM_WAIT_FREE)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", - __FUNCTION__, - (buf[0] >> 8) & 0xff - ); + __FUNCTION__, (buf[0] >> 8) & 0xff); return -ETIMEDOUT; } msleep(1); @@ -553,8 +563,11 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, } start = jiffies; - while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) { - if (time_after(jiffies, start + ARM_WAIT_FREE)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; @@ -566,8 +579,11 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, #ifndef _NOHANDSHAKE start = jiffies; - while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) { - if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); return -ETIMEDOUT; @@ -707,12 +723,16 @@ static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize, static int FlushText(struct av7110 *av7110) { unsigned long start; + int err; if (down_interruptible(&av7110->dcomlock)) return -ERESTARTSYS; start = jiffies; - while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) { - if (time_after(jiffies, start + ARM_WAIT_OSD)) { + while (1) { + err = time_after(jiffies, start + ARM_WAIT_OSD); + if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) + break; + if (err) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); @@ -735,8 +755,11 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) return -ERESTARTSYS; start = jiffies; - while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) { - if (time_after(jiffies, start + ARM_WAIT_OSD)) { + while (1) { + ret = time_after(jiffies, start + ARM_WAIT_OSD); + if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) + break; + if (ret) { printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", __FUNCTION__); up(&av7110->dcomlock); @@ -746,8 +769,11 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf) } #ifndef _NOHANDSHAKE start = jiffies; - while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) { - if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { + while (1) { + ret = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (ret) { printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); up(&av7110->dcomlock); -- cgit v1.2.3 From d8667cbbe440aacb246832afc217a6a44664115c Mon Sep 17 00:00:00 2001 From: Mac Michaels Date: Thu, 7 Jul 2005 17:58:29 -0700 Subject: [PATCH] dvb: frontend: add driver for LGDT3302 Add support for LGDT3302 (ATSC VSB/QAM) used in DViCO FusionHDTV3 Gold. Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/dvb-pll.c | 13 + drivers/media/dvb/frontends/dvb-pll.h | 1 + drivers/media/dvb/frontends/lgdt3302.c | 618 ++++++++++++++++++++++++++++ drivers/media/dvb/frontends/lgdt3302.h | 49 +++ drivers/media/dvb/frontends/lgdt3302_priv.h | 72 ++++ 7 files changed, 761 insertions(+) create mode 100644 drivers/media/dvb/frontends/lgdt3302.c create mode 100644 drivers/media/dvb/frontends/lgdt3302.h create mode 100644 drivers/media/dvb/frontends/lgdt3302_priv.h (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 5c695937e2a..d847c62bd83 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -187,4 +187,11 @@ config DVB_BCM3510 An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_LGDT3302 + tristate "LGDT3302 based (DViCO FusionHDTV3 Gold)" + depends on DVB_CORE + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + endmenu diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 8d46dd721f4..de5e240cba7 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_DVB_OR51211) += or51211.o obj-$(CONFIG_DVB_OR51132) += or51132.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o +obj-$(CONFIG_DVB_LGDT3302) += lgdt3302.o diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 8be143b7ce4..71e06ec7925 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -93,6 +93,19 @@ struct dvb_pll_desc dvb_pll_lg_z201 = { }; EXPORT_SYMBOL(dvb_pll_lg_z201); +struct dvb_pll_desc dvb_pll_microtune_4042 = { + .name = "Microtune 4042 FI5", + .min = 57000000, + .max = 858000000, + .count = 3, + .entries = { + { 162000000, 44000000, 62500, 0x8e, 0xa1 }, + { 457000000, 44000000, 62500, 0x8e, 0x91 }, + { 999999999, 44000000, 62500, 0x8e, 0x31 }, + }, +}; +EXPORT_SYMBOL(dvb_pll_microtune_4042); + struct dvb_pll_desc dvb_pll_unknown_1 = { .name = "unknown 1", /* used by dntv live dvb-t */ .min = 174000000, diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 57b64ffee40..98312bfe59d 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -24,6 +24,7 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt7579; extern struct dvb_pll_desc dvb_pll_thomson_dtt759x; extern struct dvb_pll_desc dvb_pll_thomson_dtt7610; extern struct dvb_pll_desc dvb_pll_lg_z201; +extern struct dvb_pll_desc dvb_pll_microtune_4042; extern struct dvb_pll_desc dvb_pll_unknown_1; extern struct dvb_pll_desc dvb_pll_tua6010xs; diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c new file mode 100644 index 00000000000..d0b91219cf6 --- /dev/null +++ b/drivers/media/dvb/frontends/lgdt3302.c @@ -0,0 +1,618 @@ +/* + * $Id: lgdt3302.c,v 1.2 2005/06/28 23:50:48 mkrufky Exp $ + * + * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * Based on code from Kirk Lapray + * Copyright (C) 2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * NOTES ABOUT THIS DRIVER + * + * This driver supports DViCO FusionHDTV 3 Gold under Linux. + * + * TODO: + * BER and signal strength always return 0. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb-pll.h" +#include "lgdt3302_priv.h" +#include "lgdt3302.h" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"Turn on/off lgdt3302 frontend debugging (default:off)."); +#define dprintk(args...) \ +do { \ +if (debug) printk(KERN_DEBUG "lgdt3302: " args); \ +} while (0) + +struct lgdt3302_state +{ + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; + + /* Configuration settings */ + const struct lgdt3302_config* config; + + struct dvb_frontend frontend; + + /* Demodulator private data */ + fe_modulation_t current_modulation; + + /* Tuner private data */ + u32 current_frequency; +}; + +static int i2c_writebytes (struct lgdt3302_state* state, + u8 addr, /* demod_address or pll_address */ + u8 *buf, /* data bytes to send */ + int len /* number of bytes to send */ ) +{ + if (addr == state->config->pll_address) { + struct i2c_msg msg = + { .addr = addr, .flags = 0, .buf = buf, .len = len }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); + return -EREMOTEIO; + } + } else { + u8 tmp[] = { buf[0], buf[1] }; + struct i2c_msg msg = + { .addr = addr, .flags = 0, .buf = tmp, .len = 2 }; + int err; + int i; + + for (i=1; ii2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); + return -EREMOTEIO; + } + tmp[0]++; + } + } + return 0; +} +static int i2c_readbytes (struct lgdt3302_state* state, + u8 addr, /* demod_address or pll_address */ + u8 *buf, /* holds data bytes read */ + int len /* number of bytes to read */ ) +{ + struct i2c_msg msg = + { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; + int err; + + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt3302: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err); + return -EREMOTEIO; + } + return 0; +} + +/* + * This routine writes the register (reg) to the demod bus + * then reads the data returned for (len) bytes. + */ + +static u8 i2c_selectreadbytes (struct lgdt3302_state* state, + enum I2C_REG reg, u8* buf, int len) +{ + u8 wr [] = { reg }; + struct i2c_msg msg [] = { + { .addr = state->config->demod_address, + .flags = 0, .buf = wr, .len = 1 }, + { .addr = state->config->demod_address, + .flags = I2C_M_RD, .buf = buf, .len = len }, + }; + int ret; + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) { + printk(KERN_WARNING "lgdt3302: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __FUNCTION__, state->config->demod_address, reg, ret); + } else { + ret = 0; + } + return ret; +} + +/* Software reset */ +int lgdt3302_SwReset(struct lgdt3302_state* state) +{ + u8 ret; + u8 reset[] = { + IRQ_MASK, + 0x00 /* bit 6 is active low software reset + * bits 5-0 are 1 to mask interrupts */ + }; + + ret = i2c_writebytes(state, + state->config->demod_address, + reset, sizeof(reset)); + if (ret == 0) { + /* spec says reset takes 100 ns why wait */ + /* mdelay(100); */ /* keep low for 100mS */ + reset[1] = 0x7f; /* force reset high (inactive) + * and unmask interrupts */ + ret = i2c_writebytes(state, + state->config->demod_address, + reset, sizeof(reset)); + } + /* Spec does not indicate a need for this either */ + /*mdelay(5); */ /* wait 5 msec before doing more */ + return ret; +} + +static int lgdt3302_init(struct dvb_frontend* fe) +{ + /* Hardware reset is done using gpio[0] of cx23880x chip. + * I'd like to do it here, but don't know how to find chip address. + * cx88-cards.c arranges for the reset bit to be inactive (high). + * Maybe there needs to be a callable function in cx88-core or + * the caller of this function needs to do it. */ + + dprintk("%s entered\n", __FUNCTION__); + return lgdt3302_SwReset((struct lgdt3302_state*) fe->demodulator_priv); +} + +static int lgdt3302_read_ber(struct dvb_frontend* fe, u32* ber) +{ + *ber = 0; /* Dummy out for now */ + return 0; +} + +static int lgdt3302_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; + u8 buf[2]; + + i2c_selectreadbytes(state, PACKET_ERR_COUNTER1, buf, sizeof(buf)); + + *ucblocks = (buf[0] << 8) | buf[1]; + return 0; +} + +static int lgdt3302_set_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) +{ + u8 buf[4]; + struct lgdt3302_state* state = + (struct lgdt3302_state*) fe->demodulator_priv; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) + + /* Use 50MHz parameter values from spec sheet since xtal is 50 */ + static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; + static u8 vsb_freq_cfg[] = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 }; + static u8 demux_ctrl_cfg[] = { DEMUX_CONTROL, 0xfb }; + static u8 agc_rf_cfg[] = { AGC_RF_BANDWIDTH0, 0x40, 0x93, 0x00 }; + static u8 agc_ctrl_cfg[] = { AGC_FUNC_CTRL2, 0xc6, 0x40 }; + static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x00, 0x00, 0x00 }; + static u8 agc_loop_cfg[] = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a }; + + /* Change only if we are actually changing the modulation */ + if (state->current_modulation != param->u.vsb.modulation) { + switch(param->u.vsb.modulation) { + case VSB_8: + dprintk("%s: VSB_8 MODE\n", __FUNCTION__); + + /* Select VSB mode and serial MPEG interface */ + top_ctrl_cfg[1] = 0x07; + break; + + case QAM_64: + dprintk("%s: QAM_64 MODE\n", __FUNCTION__); + + /* Select QAM_64 mode and serial MPEG interface */ + top_ctrl_cfg[1] = 0x04; + break; + + case QAM_256: + dprintk("%s: QAM_256 MODE\n", __FUNCTION__); + + /* Select QAM_256 mode and serial MPEG interface */ + top_ctrl_cfg[1] = 0x05; + break; + default: + printk(KERN_WARNING "lgdt3302: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation); + return -1; + } + /* Initializations common to all modes */ + + /* Select the requested mode */ + i2c_writebytes(state, state->config->demod_address, + top_ctrl_cfg, sizeof(top_ctrl_cfg)); + + /* Change the value of IFBW[11:0] + of AGC IF/RF loop filter bandwidth register */ + i2c_writebytes(state, state->config->demod_address, + agc_rf_cfg, sizeof(agc_rf_cfg)); + + /* Change the value of bit 6, 'nINAGCBY' and + 'NSSEL[1:0] of ACG function control register 2 */ + /* Change the value of bit 6 'RFFIX' + of AGC function control register 3 */ + i2c_writebytes(state, state->config->demod_address, + agc_ctrl_cfg, sizeof(agc_ctrl_cfg)); + + /* Change the TPCLK pin polarity + data is valid on falling clock */ + i2c_writebytes(state, state->config->demod_address, + demux_ctrl_cfg, sizeof(demux_ctrl_cfg)); + + if (param->u.vsb.modulation == VSB_8) { + /* Initialization for VSB modes only */ + /* Change the value of NCOCTFV[25:0]of carrier + recovery center frequency register for VSB */ + i2c_writebytes(state, state->config->demod_address, + vsb_freq_cfg, sizeof(vsb_freq_cfg)); + } else { + /* Initialization for QAM modes only */ + /* Set the value of 'INLVTHD' register 0x2a/0x2c + to value from 'IFACC' register 0x39/0x3b -1 */ + int value; + i2c_selectreadbytes(state, AGC_RFIF_ACC0, + &agc_delay_cfg[1], 3); + value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3]; + value = value -1; + dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value); + agc_delay_cfg[1] = (value >> 8) & 0x0f; + agc_delay_cfg[2] = 0x00; + agc_delay_cfg[3] = value & 0xff; + i2c_writebytes(state, state->config->demod_address, + agc_delay_cfg, sizeof(agc_delay_cfg)); + + /* Change the value of IAGCBW[15:8] + of inner AGC loop filter bandwith */ + i2c_writebytes(state, state->config->demod_address, + agc_loop_cfg, sizeof(agc_loop_cfg)); + } + + state->config->set_ts_params(fe, 0); + lgdt3302_SwReset(state); + state->current_modulation = param->u.vsb.modulation; + } +#else + printk("lgdt3302: %s: you need a newer kernel for this, sorry\n",__FUNCTION__); +#endif + + /* Change only if we are actually changing the channel */ + if (state->current_frequency != param->frequency) { + dvb_pll_configure(state->config->pll_desc, buf, + param->frequency, 0); + dprintk("%s: tuner bytes: 0x%02x 0x%02x " + "0x%02x 0x%02x\n", __FUNCTION__, buf[0],buf[1],buf[2],buf[3]); + i2c_writebytes(state, state->config->pll_address ,buf, 4); + + /* Check the status of the tuner pll */ + i2c_readbytes(state, state->config->pll_address, buf, 1); + dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]); + + lgdt3302_SwReset(state); + + /* Update current frequency */ + state->current_frequency = param->frequency; + } + return 0; +} + +static int lgdt3302_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters* param) +{ + struct lgdt3302_state *state = fe->demodulator_priv; + param->frequency = state->current_frequency; + return 0; +} + +static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; + u8 buf[3]; + + *status = 0; /* Reset status result */ + + /* Check the status of the tuner pll */ + i2c_readbytes(state, state->config->pll_address, buf, 1); + dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]); + if ((buf[0] & 0xc0) != 0x40) + return 0; /* Tuner PLL not locked or not powered on */ + + /* + * You must set the Mask bits to 1 in the IRQ_MASK in order + * to see that status bit in the IRQ_STATUS register. + * This is done in SwReset(); + */ + + /* signal status */ + i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf)); + dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]); + if ((buf[2] & 0x30) == 0x10) + *status |= FE_HAS_SIGNAL; + + /* sync status */ + if ((buf[2] & 0x03) == 0x01) { + *status |= FE_HAS_SYNC; + } + + /* FEC error status */ + if ((buf[2] & 0x0c) == 0x08) { + *status |= FE_HAS_LOCK; + *status |= FE_HAS_VITERBI; + } + +#if 0 + /* Alternative method to check for a signal */ + /* AGC status register */ + i2c_selectreadbytes(state, AGC_STATUS, buf, 1); + dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); + if ((buf[0] & 0x0c) == 0x80) /* Test signal does not exist flag */ + /* Test AGC lock flag */ + *status |= FE_HAS_SIGNAL; + else + return 0; + + /* Carrier Recovery Lock Status Register */ + i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1); + dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]); + switch (state->current_modulation) { + case QAM_256: + case QAM_64: + /* Need to undestand why there are 3 lock levels here */ + if ((buf[0] & 0x07) == 0x07) + *status |= FE_HAS_CARRIER; + else + return 0; + break; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) + case VSB_8: + if ((buf[0] & 0x80) == 0x80) + *status |= FE_HAS_CARRIER; + else + return 0; + break; +#endif + default: + printk("KERN_WARNING lgdt3302: %s: Modulation set to unsupported value\n", __FUNCTION__); + } +#endif + + return 0; +} + +static int lgdt3302_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + /* not directly available. */ + return 0; +} + +static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr) +{ +#ifdef SNR_IN_DB + /* + * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise) + * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker + * respectively. The following tables are built on these formulas. + * The usual definition is SNR = 20 log10(signal/noise) + * If the specification is wrong the value retuned is 1/2 the actual SNR in db. + * + * This table is a an ordered list of noise values computed by the + * formula from the spec sheet such that the index into the table + * starting at 43 or 45 is the SNR value in db. There are duplicate noise + * value entries at the beginning because the SNR varies more than + * 1 db for a change of 1 digit in noise at very small values of noise. + * + * Examples from SNR_EQ table: + * noise SNR + * 0 43 + * 1 42 + * 2 39 + * 3 37 + * 4 36 + * 5 35 + * 6 34 + * 7 33 + * 8 33 + * 9 32 + * 10 32 + * 11 31 + * 12 31 + * 13 30 + */ + + static const u32 SNR_EQ[] = + { 1, 2, 2, 2, 3, 3, 4, 4, 5, 7, + 9, 11, 13, 17, 21, 26, 33, 41, 52, 65, + 81, 102, 129, 162, 204, 257, 323, 406, 511, 644, + 810, 1020, 1284, 1616, 2035, 2561, 3224, 4059, 5110, 6433, + 8098, 10195, 12835, 16158, 20341, 25608, 32238, 40585, 51094, 64323, + 80978, 101945, 128341, 161571, 203406, 256073, 0x40000 + }; + + static const u32 SNR_PH[] = + { 1, 2, 2, 2, 3, 3, 4, 5, 6, 8, + 10, 12, 15, 19, 23, 29, 37, 46, 58, 73, + 91, 115, 144, 182, 229, 288, 362, 456, 574, 722, + 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216, + 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151, + 90833, 114351, 143960, 181235, 228161, 0x040000 + }; + + static u8 buf[5];/* read data buffer */ + static u32 noise; /* noise value */ + static u32 snr_db; /* index into SNR_EQ[] */ + struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; + + /* read both equalizer and pase tracker noise data */ + i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); + + if (state->current_modulation == VSB_8) { + /* Equalizer Mean-Square Error Register for VSB */ + noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; + + /* + * Look up noise value in table. + * A better search algorithm could be used... + * watch out there are duplicate entries. + */ + for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) { + if (noise < SNR_EQ[snr_db]) { + *snr = 43 - snr_db; + break; + } + } + } else { + /* Phase Tracker Mean-Square Error Register for QAM */ + noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; + + /* Look up noise value in table. */ + for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) { + if (noise < SNR_PH[snr_db]) { + *snr = 45 - snr_db; + break; + } + } + } +#else + /* Return the raw noise value */ + static u8 buf[5];/* read data buffer */ + static u32 noise; /* noise value */ + struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; + + /* read both equalizer and pase tracker noise data */ + i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); + + if (state->current_modulation == VSB_8) { + /* Equalizer Mean-Square Error Register for VSB */ + noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; + } else { + /* Phase Tracker Mean-Square Error Register for QAM */ + noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; + } + + /* Small values for noise mean signal is better so invert noise */ + /* Noise is 19 bit value so discard 3 LSB*/ + *snr = ~noise>>3; +#endif + + dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); + + return 0; +} + +static int lgdt3302_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) +{ + /* I have no idea about this - it may not be needed */ + fe_tune_settings->min_delay_ms = 500; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + return 0; +} + +static void lgdt3302_release(struct dvb_frontend* fe) +{ + struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops lgdt3302_ops; + +struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config, + struct i2c_adapter* i2c) +{ + struct lgdt3302_state* state = NULL; + u8 buf[1]; + + /* Allocate memory for the internal state */ + state = (struct lgdt3302_state*) kmalloc(sizeof(struct lgdt3302_state), GFP_KERNEL); + if (state == NULL) + goto error; + memset(state,0,sizeof(*state)); + + /* Setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops)); + /* Verify communication with demod chip */ + if (i2c_selectreadbytes(state, 2, buf, 1)) + goto error; + + state->current_frequency = -1; + state->current_modulation = -1; + + /* Create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) + kfree(state); + dprintk("%s: ERROR\n",__FUNCTION__); + return NULL; +} + +static struct dvb_frontend_ops lgdt3302_ops = { + .info = { + .name= "LG Electronics LGDT3302 VSB/QAM Frontend", + .type = FE_ATSC, + .frequency_min= 54000000, + .frequency_max= 858000000, + .frequency_stepsize= 62500, + /* Symbol rate is for all VSB modes need to check QAM */ + .symbol_rate_min = 10762000, + .symbol_rate_max = 10762000, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .init = lgdt3302_init, + .set_frontend = lgdt3302_set_parameters, + .get_frontend = lgdt3302_get_frontend, + .get_tune_settings = lgdt3302_get_tune_settings, + .read_status = lgdt3302_read_status, + .read_ber = lgdt3302_read_ber, + .read_signal_strength = lgdt3302_read_signal_strength, + .read_snr = lgdt3302_read_snr, + .read_ucblocks = lgdt3302_read_ucblocks, + .release = lgdt3302_release, +}; + +MODULE_DESCRIPTION("LGDT3302 [DViCO FusionHDTV 3 Gold] (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); +MODULE_AUTHOR("Wilson Michaels"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(lgdt3302_attach); + +/* + * Local variables: + * c-basic-offset: 8 + * compile-command: "make DVB=1" + * End: + */ diff --git a/drivers/media/dvb/frontends/lgdt3302.h b/drivers/media/dvb/frontends/lgdt3302.h new file mode 100644 index 00000000000..81587a40032 --- /dev/null +++ b/drivers/media/dvb/frontends/lgdt3302.h @@ -0,0 +1,49 @@ +/* + * $Id: lgdt3302.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $ + * + * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef LGDT3302_H +#define LGDT3302_H + +#include + +struct lgdt3302_config +{ + /* The demodulator's i2c address */ + u8 demod_address; + u8 pll_address; + struct dvb_pll_desc *pll_desc; + + /* Need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); +}; + +extern struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config, + struct i2c_adapter* i2c); + +#endif /* LGDT3302_H */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/lgdt3302_priv.h b/drivers/media/dvb/frontends/lgdt3302_priv.h new file mode 100644 index 00000000000..6193fa7a569 --- /dev/null +++ b/drivers/media/dvb/frontends/lgdt3302_priv.h @@ -0,0 +1,72 @@ +/* + * $Id: lgdt3302_priv.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $ + * + * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM + * + * Copyright (C) 2005 Wilson Michaels + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _LGDT3302_PRIV_ +#define _LGDT3302_PRIV_ + +/* i2c control register addresses */ +enum I2C_REG { + TOP_CONTROL= 0x00, + IRQ_MASK= 0x01, + IRQ_STATUS= 0x02, + VSB_CARRIER_FREQ0= 0x16, + VSB_CARRIER_FREQ1= 0x17, + VSB_CARRIER_FREQ2= 0x18, + VSB_CARRIER_FREQ3= 0x19, + CARRIER_MSEQAM1= 0x1a, + CARRIER_MSEQAM2= 0x1b, + CARRIER_LOCK= 0x1c, + TIMING_RECOVERY= 0x1d, + AGC_DELAY0= 0x2a, + AGC_DELAY1= 0x2b, + AGC_DELAY2= 0x2c, + AGC_RF_BANDWIDTH0= 0x2d, + AGC_RF_BANDWIDTH1= 0x2e, + AGC_RF_BANDWIDTH2= 0x2f, + AGC_LOOP_BANDWIDTH0= 0x30, + AGC_LOOP_BANDWIDTH1= 0x31, + AGC_FUNC_CTRL1= 0x32, + AGC_FUNC_CTRL2= 0x33, + AGC_FUNC_CTRL3= 0x34, + AGC_RFIF_ACC0= 0x39, + AGC_RFIF_ACC1= 0x3a, + AGC_RFIF_ACC2= 0x3b, + AGC_STATUS= 0x3f, + SYNC_STATUS_VSB= 0x43, + EQPH_ERR0= 0x47, + EQ_ERR1= 0x48, + EQ_ERR2= 0x49, + PH_ERR1= 0x4a, + PH_ERR2= 0x4b, + DEMUX_CONTROL= 0x66, + PACKET_ERR_COUNTER1= 0x6a, + PACKET_ERR_COUNTER2= 0x6b, +}; + +#endif /* _LGDT3302_PRIV_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ -- cgit v1.2.3 From 63b5c1c47fd6c5ae26d279756e8a050c721ea379 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:30 -0700 Subject: [PATCH] dvb: usb/pci: correct syntax of driver name fields Change the name-field of the pci_driver and usb_driver structs to the name of the module after compilation. It seems that this field is used in some places where special characters are not allowed. Thanks to Alan Halverson for finding this problem. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/b2c2/flexcop-pci.c | 2 +- drivers/media/dvb/b2c2/flexcop-usb.c | 2 +- drivers/media/dvb/dvb-usb/a800.c | 2 +- drivers/media/dvb/dvb-usb/cxusb.c | 2 +- drivers/media/dvb/dvb-usb/dibusb-mb.c | 2 +- drivers/media/dvb/dvb-usb/dibusb-mc.c | 2 +- drivers/media/dvb/dvb-usb/digitv.c | 2 +- drivers/media/dvb/dvb-usb/nova-t-usb2.c | 2 +- drivers/media/dvb/dvb-usb/umt-010.c | 2 +- drivers/media/dvb/dvb-usb/vp7045.c | 6 +++--- 10 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index a436d5584ea..2f76eb3fea4 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -409,7 +409,7 @@ static struct pci_device_id flexcop_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl); static struct pci_driver flexcop_pci_driver = { - .name = "Technisat/B2C2 FlexCop II/IIb PCI", + .name = "b2c2_flexcop_pci", .id_table = flexcop_pci_tbl, .probe = flexcop_pci_probe, .remove = flexcop_pci_remove, diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c index 0113449abd1..0a78ba3737a 100644 --- a/drivers/media/dvb/b2c2/flexcop-usb.c +++ b/drivers/media/dvb/b2c2/flexcop-usb.c @@ -545,7 +545,7 @@ static struct usb_device_id flexcop_usb_table [] = { /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver flexcop_usb_driver = { .owner = THIS_MODULE, - .name = "Technisat/B2C2 FlexCop II/IIb/III USB", + .name = "b2c2_flexcop_usb", .probe = flexcop_usb_probe, .disconnect = flexcop_usb_disconnect, .id_table = flexcop_usb_table, diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index 672037c2281..f2fcc2f1f84 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -149,7 +149,7 @@ static struct dvb_usb_properties a800_properties = { static struct usb_driver a800_driver = { .owner = THIS_MODULE, - .name = "AVerMedia AverTV DVB-T USB 2.0 (A800)", + .name = "dvb_usb_a800", .probe = a800_probe, .disconnect = dvb_usb_device_exit, .id_table = a800_table, diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index b4bb206a510..c3e1b661aae 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -262,7 +262,7 @@ static struct dvb_usb_properties cxusb_properties = { static struct usb_driver cxusb_driver = { .owner = THIS_MODULE, - .name = "cxusb", + .name = "dvb_usb_cxusb", .probe = cxusb_probe, .disconnect = dvb_usb_device_exit, .id_table = cxusb_table, diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index cda2179d61a..828b5182e16 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -317,7 +317,7 @@ static struct dvb_usb_properties dibusb2_0b_properties = { static struct usb_driver dibusb_driver = { .owner = THIS_MODULE, - .name = "DiBcom based USB DVB-T devices (DiB3000M-B based)", + .name = "dvb_usb_dibusb_mb", .probe = dibusb_probe, .disconnect = dvb_usb_device_exit, .id_table = dibusb_dib3000mb_table, diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c index aad8ed3fe00..e9dac430f37 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mc.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c @@ -83,7 +83,7 @@ static struct dvb_usb_properties dibusb_mc_properties = { static struct usb_driver dibusb_mc_driver = { .owner = THIS_MODULE, - .name = "DiBcom based USB2.0 DVB-T (DiB3000M-C/P based) devices", + .name = "dvb_usb_dibusb_mc", .probe = dibusb_mc_probe, .disconnect = dvb_usb_device_exit, .id_table = dibusb_dib3000mc_table, diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 8155a26f0dd..9a676afc1d6 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -228,7 +228,7 @@ static struct dvb_usb_properties digitv_properties = { static struct usb_driver digitv_driver = { .owner = THIS_MODULE, - .name = "Nebula Electronics uDigiTV DVB-T USB2.0 device", + .name = "dvb_usb_digitv", .probe = digitv_probe, .disconnect = dvb_usb_device_exit, .id_table = digitv_table, diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c index 9d83781aef9..258a92bfbcc 100644 --- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c @@ -203,7 +203,7 @@ static struct dvb_usb_properties nova_t_properties = { static struct usb_driver nova_t_driver = { .owner = THIS_MODULE, - .name = "Hauppauge WinTV-NOVA-T usb2", + .name = "dvb_usb_nova_t_usb2", .probe = nova_t_probe, .disconnect = dvb_usb_device_exit, .id_table = nova_t_table, diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c index aa560422ce7..2112ac3cf5e 100644 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -129,7 +129,7 @@ static struct dvb_usb_properties umt_properties = { static struct usb_driver umt_driver = { .owner = THIS_MODULE, - .name = "HanfTek UMT-010 USB2.0 DVB-T devices", + .name = "dvb_usb_umt_010", .probe = umt_probe, .disconnect = dvb_usb_device_exit, .id_table = umt_table, diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 72d5d3f7446..5adc5d69ec8 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -44,7 +44,7 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, if (usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0), TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, - outbuf, 20, 2*HZ) != 20) { + outbuf, 20, 2000) != 20) { err("USB control message 'out' went wrong."); ret = -EIO; goto unlock; @@ -55,7 +55,7 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, if (usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, - inbuf, 12, 2*HZ) != 12) { + inbuf, 12, 2000) != 12) { err("USB control message 'in' went wrong."); ret = -EIO; goto unlock; @@ -255,7 +255,7 @@ static struct dvb_usb_properties vp7045_properties = { /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver vp7045_usb_driver = { .owner = THIS_MODULE, - .name = "dvb-usb-vp7045", + .name = "dvb_usb_vp7045", .probe = vp7045_usb_probe, .disconnect = dvb_usb_device_exit, .id_table = vp7045_usb_table, -- cgit v1.2.3 From 4b2bd30eb79c292a83b1dfd3cca6d435c02fd5c0 Mon Sep 17 00:00:00 2001 From: Steffen Motzer Date: Thu, 7 Jul 2005 17:58:31 -0700 Subject: [PATCH] dvb: dst: fix tuning problem Fix tuning failure for 200103A, 200103A failed to tune to low band due to wrong tone setting on the 200103A. Signed-off-by: Steffen Motzer Signed-off-by: Manu Abraham Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index d8f4200065e..9bd12832e3d 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1147,7 +1147,11 @@ static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) switch (tone) { case SEC_TONE_OFF: - state->tx_tuna[2] = 0xff; + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + state->tx_tuna[2] = 0x00; + else + state->tx_tuna[2] = 0xff; + break; case SEC_TONE_ON: -- cgit v1.2.3 From d590f9c20e15620ba708e5bd71d345bf1b7b0d73 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Thu, 7 Jul 2005 17:58:33 -0700 Subject: [PATCH] dvb: usb: add supprt for WideView WT-220U Add support and rewrote some parts with the help of vendor information (Thanks to Steve Chang from WideView, Inc.): o added support for the WT-220U (Pensize DVB-T receiver) o corrected byte order for unc,ber and the pid filter o corrected number of pids that can be fetched at the same time. o added some comments in Kconfig-file o added USB IDs for the WT-220U Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/Kconfig | 4 +- drivers/media/dvb/dvb-usb/dtt200u-fe.c | 72 +++++++++++++-------------- drivers/media/dvb/dvb-usb/dtt200u.c | 86 ++++++++++++++++++++++++++++----- drivers/media/dvb/dvb-usb/dtt200u.h | 38 ++++++--------- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 3 +- 5 files changed, 130 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 91e88b2ed5d..612e5b087b1 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -109,9 +109,11 @@ config DVB_USB_NOVA_T_USB2 Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. config DVB_USB_DTT200U - tristate "WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 support" + tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)" depends on DVB_USB help Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver. The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). + + The WT-220U and its clones are pen-sized. diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c index 7807f33573b..b032523b07b 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c @@ -14,61 +14,58 @@ struct dtt200u_fe_state { struct dvb_usb_device *d; + fe_status_t stat; + struct dvb_frontend_parameters fep; struct dvb_frontend frontend; }; -#define moan(which,what) info("unexpected value in '%s' for cmd '%02x' - please report to linux-dvb@linuxtv.org",which,what) - static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat) { struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_TUNE_STAT; - u8 br[3] = { 0 }; -// u8 bdeb[5] = { 0 }; + u8 st = GET_TUNE_STATUS, b[3]; + + dvb_usb_generic_rw(state->d,&st,1,b,3,0); - dvb_usb_generic_rw(state->d,&bw,1,br,3,0); - switch (br[0]) { + switch (b[0]) { case 0x01: - *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; break; - case 0x00: - *stat = 0; + case 0x00: /* pending */ + *stat = FE_TIMEDOUT; /* during set_frontend */ break; default: - moan("br[0]",GET_TUNE_STAT); + case 0x02: /* failed */ + *stat = 0; break; } - -// bw[0] = 0x88; -// dvb_usb_generic_rw(state->d,bw,1,bdeb,5,0); - -// deb_info("%02x: %02x %02x %02x %02x %02x\n",bw[0],bdeb[0],bdeb[1],bdeb[2],bdeb[3],bdeb[4]); - return 0; } + static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber) { struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_BER; - *ber = 0; - dvb_usb_generic_rw(state->d,&bw,1,(u8*) ber,3,0); + u8 bw = GET_VIT_ERR_CNT,b[3]; + dvb_usb_generic_rw(state->d,&bw,1,b,3,0); + *ber = (b[0] << 16) | (b[1] << 8) | b[2]; return 0; } static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) { struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_UNK; - *unc = 0; - dvb_usb_generic_rw(state->d,&bw,1,(u8*) unc,3,0); + u8 bw = GET_RS_UNCOR_BLK_CNT,b[2]; + + dvb_usb_generic_rw(state->d,&bw,1,b,2,0); + *unc = (b[0] << 8) | b[1]; return 0; } static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) { struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 bw = GET_SIG_STRENGTH, b; + u8 bw = GET_AGC, b; dvb_usb_generic_rw(state->d,&bw,1,&b,1,0); *strength = (b << 8) | b; return 0; @@ -86,7 +83,7 @@ static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr) static int dtt200u_fe_init(struct dvb_frontend* fe) { struct dtt200u_fe_state *state = fe->demodulator_priv; - u8 b = RESET_DEMOD; + u8 b = SET_INIT; return dvb_usb_generic_write(state->d,&b,1); } @@ -98,8 +95,8 @@ static int dtt200u_fe_sleep(struct dvb_frontend* fe) static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) { tune->min_delay_ms = 1500; - tune->step_size = 166667; - tune->max_drift = 166667 * 2; + tune->step_size = 0; + tune->max_drift = 0; return 0; } @@ -107,27 +104,32 @@ static int dtt200u_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dtt200u_fe_state *state = fe->demodulator_priv; + int i; + fe_status_t st; u16 freq = fep->frequency / 250000; - u8 bw,bwbuf[2] = { SET_BANDWIDTH, 0 }, freqbuf[3] = { SET_FREQUENCY, 0, 0 }; + u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 }; switch (fep->u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: bw = 8; break; - case BANDWIDTH_7_MHZ: bw = 7; break; - case BANDWIDTH_6_MHZ: bw = 6; break; + case BANDWIDTH_8_MHZ: bwbuf[1] = 8; break; + case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break; + case BANDWIDTH_6_MHZ: bwbuf[1] = 6; break; case BANDWIDTH_AUTO: return -EOPNOTSUPP; default: return -EINVAL; } - deb_info("set_frontend\n"); - bwbuf[1] = bw; dvb_usb_generic_write(state->d,bwbuf,2); freqbuf[1] = freq & 0xff; freqbuf[2] = (freq >> 8) & 0xff; dvb_usb_generic_write(state->d,freqbuf,3); - memcpy(&state->fep,fep,sizeof(struct dvb_frontend_parameters)); + for (i = 0; i < 30; i++) { + msleep(20); + dtt200u_fe_read_status(fe, &st); + if (st & FE_TIMEDOUT) + continue; + } return 0; } @@ -174,7 +176,7 @@ success: static struct dvb_frontend_ops dtt200u_fe_ops = { .info = { - .name = "DTT200U (Yakumo/Typhoon/Hama) DVB-T", + .name = "WideView USB DVB-T", .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 1ebd3eff96d..47dba6e4596 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -3,6 +3,8 @@ * * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * + * Thanks to Steve Chang from WideView for providing support for the WT-220U. + * * 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. @@ -16,14 +18,24 @@ int dvb_usb_dtt200u_debug; module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS); +static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 b = SET_INIT; + + if (onoff) + dvb_usb_generic_write(d,&b,2); + + return 0; +} + static int dtt200u_streaming_ctrl(struct dvb_usb_device *d, int onoff) { - u8 b_streaming[2] = { SET_TS_CTRL, onoff }; + u8 b_streaming[2] = { SET_STREAMING, onoff }; u8 b_rst_pid = RESET_PID_FILTER; dvb_usb_generic_write(d,b_streaming,2); - if (!onoff) + if (onoff == 0) dvb_usb_generic_write(d,&b_rst_pid,1); return 0; } @@ -36,7 +48,7 @@ static int dtt200u_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int b_pid[0] = SET_PID_FILTER; b_pid[1] = index; b_pid[2] = pid & 0xff; - b_pid[3] = (pid >> 8) & 0xff; + b_pid[3] = (pid >> 8) & 0x1f; return dvb_usb_generic_write(d,b_pid,4); } @@ -54,9 +66,9 @@ static struct dvb_usb_rc_key dtt200u_rc_keys[] = { { 0x80, 0x08, KEY_5 }, { 0x80, 0x09, KEY_6 }, { 0x80, 0x0a, KEY_7 }, - { 0x00, 0x0c, KEY_ZOOM }, + { 0x80, 0x0c, KEY_ZOOM }, { 0x80, 0x0d, KEY_0 }, - { 0x00, 0x0e, KEY_SELECT }, + { 0x80, 0x0e, KEY_SELECT }, { 0x80, 0x12, KEY_POWER }, { 0x80, 0x1a, KEY_CHANNELUP }, { 0x80, 0x1b, KEY_8 }, @@ -66,7 +78,7 @@ static struct dvb_usb_rc_key dtt200u_rc_keys[] = { static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { - u8 key[5],cmd = GET_RC_KEY; + u8 key[5],cmd = GET_RC_CODE; dvb_usb_generic_rw(d,&cmd,1,key,5,0); dvb_usb_nec_rc_key_to_event(d,key,event,state); if (key[0] != 0) @@ -81,32 +93,41 @@ static int dtt200u_frontend_attach(struct dvb_usb_device *d) } static struct dvb_usb_properties dtt200u_properties; +static struct dvb_usb_properties wt220u_properties; static int dtt200u_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE); + if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE) == 0 || + dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE) == 0) + return 0; + + return -ENODEV; } static struct usb_device_id dtt200u_usb_table [] = { +// { USB_DEVICE(0x04b4,0x8613) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); static struct dvb_usb_properties dtt200u_properties = { .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING, - .pid_filter_count = 255, /* It is a guess, but there are at least 10 */ + .pid_filter_count = 15, .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-dtt200u-01.fw", + .power_ctrl = dtt200u_power_ctrl, .streaming_ctrl = dtt200u_streaming_ctrl, .pid_filter = dtt200u_pid_filter, .frontend_attach = dtt200u_frontend_attach, - .rc_interval = 200, + .rc_interval = 300, .rc_key_map = dtt200u_rc_keys, .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys), .rc_query = dtt200u_rc_query, @@ -127,7 +148,7 @@ static struct dvb_usb_properties dtt200u_properties = { .num_device_descs = 1, .devices = { - { .name = "WideView/Yakumo/Hama/Typhoon DVB-T USB2.0)", + { .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)", .cold_ids = { &dtt200u_usb_table[0], NULL }, .warm_ids = { &dtt200u_usb_table[1], NULL }, }, @@ -135,10 +156,51 @@ static struct dvb_usb_properties dtt200u_properties = { } }; +static struct dvb_usb_properties wt220u_properties = { + .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-01.fw", + + .power_ctrl = dtt200u_power_ctrl, + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + + .rc_interval = 300, + .rc_key_map = dtt200u_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys), + .rc_query = dtt200u_rc_query, + + .generic_bulk_ctrl_endpoint = 0x01, + + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (and clones)", + .cold_ids = { &dtt200u_usb_table[2], NULL }, + .warm_ids = { &dtt200u_usb_table[3], NULL }, + }, + { 0 }, + } +}; + /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver dtt200u_usb_driver = { .owner = THIS_MODULE, - .name = "dtt200u", + .name = "dvb_usb_dtt200u", .probe = dtt200u_usb_probe, .disconnect = dvb_usb_device_exit, .id_table = dtt200u_usb_table, @@ -166,6 +228,6 @@ module_init(dtt200u_usb_module_init); module_exit(dtt200u_usb_module_exit); MODULE_AUTHOR("Patrick Boettcher "); -MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 device"); +MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 devices"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h index 9ab081a55b8..6f1f3042e21 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.h +++ b/drivers/media/dvb/dvb-usb/dtt200u.h @@ -22,44 +22,34 @@ extern int dvb_usb_dtt200u_debug; /* guessed protocol description (reverse engineered): * read * 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1 - * 81 - - * 82 - crash - do not touch - * 83 - crash - do not touch - * 84 - remote control - * 85 - crash - do not touch (OK, stop testing here) * 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal) - * 89 - noise-to-signal - * 8a - unkown 1 byte - signal_strength - * 8c - ber ??? - * 8d - ber - * 8e - unc */ -#define GET_SPEED 0x00 -#define GET_TUNE_STAT 0x81 -#define GET_RC_KEY 0x84 -#define GET_STATUS 0x88 -#define GET_SNR 0x89 -#define GET_SIG_STRENGTH 0x8a -#define GET_UNK 0x8c -#define GET_BER 0x8d -#define GET_UNC 0x8e +#define GET_SPEED 0x00 +#define GET_TUNE_STATUS 0x81 +#define GET_RC_CODE 0x84 +#define GET_CONFIGURATION 0x88 +#define GET_AGC 0x89 +#define GET_SNR 0x8a +#define GET_VIT_ERR_CNT 0x8c +#define GET_RS_ERR_CNT 0x8d +#define GET_RS_UNCOR_BLK_CNT 0x8e /* write - * 01 - reset the demod + * 01 - init * 02 - frequency (divided by 250000) * 03 - bandwidth * 04 - pid table (index pid(7:0) pid(12:8)) * 05 - reset the pid table - * 08 - demod transfer enabled or not (FX2 transfer is enabled by default) + * 08 - transfer switch */ -#define RESET_DEMOD 0x01 -#define SET_FREQUENCY 0x02 +#define SET_INIT 0x01 +#define SET_RF_FREQ 0x02 #define SET_BANDWIDTH 0x03 #define SET_PID_FILTER 0x04 #define RESET_PID_FILTER 0x05 -#define SET_TS_CTRL 0x08 +#define SET_STREAMING 0x08 extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 75f4cb18a63..794d513a848 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -72,6 +72,8 @@ #define USB_PID_HANFTEK_UMT_010_WARM 0x0015 #define USB_PID_DTT200U_COLD 0x0201 #define USB_PID_DTT200U_WARM 0x0301 +#define USB_PID_WT220U_COLD 0x0222 +#define USB_PID_WT220U_WARM 0x0221 #define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300 #define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 #define USB_PID_NEBULA_DIGITV 0x0201 @@ -84,5 +86,4 @@ #define USB_PID_KYE_DVB_T_COLD 0x701e #define USB_PID_KYE_DVB_T_WARM 0x701f - #endif -- cgit v1.2.3 From a82decf64d34e79a0cc622997866c754350f18f8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Jul 2005 17:58:36 -0700 Subject: [PATCH] v4l: cx88 update - Add support for ADS Tech Instant TV DVB-T PCI. - Remove obsoleted config options. - Fix DViCO Board names - Remove CABLE type setting from DViCO FusionHDTV3 Gold-T. - Fix compilation with gcc4.0. - V4L2_TUNER_CAP_LOW implemented according with V4L2 API for Radio. - radio range is now defined on tuner-core.c. Cleaning up. - Fix a bug on frequency report for cx88 based cards. - Added support for changing radio mode stereo/mono. - Add remove for MSI TV@nywhere. Signed-off-by: Jorik Jonker . Signed-off-by: Didier Caillaud Signed-off-by: Benoit Laniel . Signed-off-by: Nickolay V Shmyrev Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/cx88/cx88-cards.c | 50 +++++++++++++----- drivers/media/video/cx88/cx88-core.c | 19 ++----- drivers/media/video/cx88/cx88-dvb.c | 3 +- drivers/media/video/cx88/cx88-input.c | 96 ++++++++++++++++++++++++++++++++++- drivers/media/video/cx88/cx88-video.c | 57 ++++++++++----------- drivers/media/video/cx88/cx88.h | 9 ++-- 6 files changed, 169 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index b3fb04356b7..f9e4cb19687 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-cards.c,v 1.76 2005/06/08 01:28:09 mchehab Exp $ + * $Id: cx88-cards.c,v 1.82 2005/06/28 04:33:53 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * card-specific stuff. @@ -401,7 +401,7 @@ struct cx88_board cx88_boards[] = { .dvb = 1, }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = { - .name = "DVICO FusionHDTV DVB-T1", + .name = "DViCO FusionHDTV DVB-T1", .tuner_type = TUNER_ABSENT, /* No analog tuner */ .radio_type = UNSET, .tuner_addr = ADDR_UNSET, @@ -445,8 +445,8 @@ struct cx88_board cx88_boards[] = { .gpio0 = 0x000007f8, }, }, - [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD] = { - .name = "DViCO - FusionHDTV 3 Gold", + [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q] = { + .name = "DViCO FusionHDTV 3 Gold-Q", .tuner_type = TUNER_MICROTUNE_4042FI5, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, @@ -464,6 +464,9 @@ struct cx88_board cx88_boards[] = { GPIO[3] selects RF input connector on tuner module 0 - RF connector labeled CABLE 1 - RF connector labeled ANT + GPIO[4] selects high RF for QAM256 mode + 0 - normal RF + 1 - high RF */ .input = {{ .type = CX88_VMUX_TELEVISION, @@ -520,7 +523,7 @@ struct cx88_board cx88_boards[] = { .blackbird = 1, }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = { - .name = "DVICO FusionHDTV DVB-T Plus", + .name = "DViCO FusionHDTV DVB-T Plus", .tuner_type = TUNER_ABSENT, /* No analog tuner */ .radio_type = UNSET, .tuner_addr = ADDR_UNSET, @@ -700,20 +703,16 @@ struct cx88_board cx88_boards[] = { }, }, [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = { - .name = "DViCO - FusionHDTV 3 Gold-T", + .name = "DViCO FusionHDTV 3 Gold-T", .tuner_type = TUNER_THOMSON_DTT7611, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - /* See DViCO FusionHDTV 3 Gold for GPIO documentation. */ - .input = {{ + /* See DViCO FusionHDTV 3 Gold-Q for GPIO documentation. */ + .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0f0d, - },{ - .type = CX88_VMUX_CABLE, - .vmux = 0, - .gpio0 = 0x0f05, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, @@ -724,6 +723,25 @@ struct cx88_board cx88_boards[] = { .gpio0 = 0x0f00, }}, }, + [CX88_BOARD_ADSTECH_DVB_T_PCI] = { + .name = "ADS Tech Instant TV DVB-T PCI", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0700, + .gpio2 = 0x0101, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0700, + .gpio2 = 0x0101, + }}, + .dvb = 1, + }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -794,7 +812,7 @@ struct cx88_subid cx88_subids[] = { },{ .subvendor = 0x18ac, .subdevice = 0xd810, - .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD, + .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q, },{ .subvendor = 0x18ac, .subdevice = 0xd820, @@ -843,7 +861,11 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x10fc, .subdevice = 0xd035, .card = CX88_BOARD_IODATA_GVBCTV7E, - } + },{ + .subvendor = 0x1421, + .subdevice = 0x0334, + .card = CX88_BOARD_ADSTECH_DVB_T_PCI, + }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index c046a23537d..96cb0ff33bb 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-core.c,v 1.28 2005/06/12 04:19:19 mchehab Exp $ + * $Id: cx88-core.c,v 1.31 2005/06/22 22:58:04 mchehab Exp $ * * device driver for Conexant 2388x based TV cards * driver core @@ -545,12 +545,14 @@ void cx88_sram_channel_dump(struct cx88_core *core, core->name,cx_read(ch->cnt2_reg)); } +/* Used only on cx88-core */ static char *cx88_pci_irqs[32] = { "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1", "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err", "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err", "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1" }; +/* Used only on cx88-video */ char *cx88_vid_irqs[32] = { "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", @@ -558,6 +560,7 @@ char *cx88_vid_irqs[32] = { "y_sync", "u_sync", "v_sync", "vbi_sync", "opc_err", "par_err", "rip_err", "pci_abort", }; +/* Used only on cx88-mpeg */ char *cx88_mpeg_irqs[32] = { "ts_risci1", NULL, NULL, NULL, "ts_risci2", NULL, NULL, NULL, @@ -1006,21 +1009,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm) set_tvaudio(core); // tell i2c chips -#ifdef V4L2_I2C_CLIENTS cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id); -#else - { - struct video_channel c; - memset(&c,0,sizeof(c)); - c.channel = core->input; - c.norm = VIDEO_MODE_PAL; - if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP))) - c.norm = VIDEO_MODE_NTSC; - if (norm->id & V4L2_STD_SECAM) - c.norm = VIDEO_MODE_SECAM; - cx88_call_i2c_clients(core,VIDIOCSCHAN,&c); - } -#endif // done return 0; diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 1a259c3966c..82cc1538c10 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-dvb.c,v 1.33 2005/06/12 04:19:19 mchehab Exp $ + * $Id: cx88-dvb.c,v 1.36 2005/06/21 06:08:12 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * MPEG Transport Stream (DVB) routines @@ -231,6 +231,7 @@ static int dvb_register(struct cx8802_dev *dev) break; case CX88_BOARD_KWORLD_DVB_T: case CX88_BOARD_DNTV_LIVE_DVB_T: + case CX88_BOARD_ADSTECH_DVB_T_PCI: dev->core->pll_addr = 0x61; dev->core->pll_desc = &dvb_pll_unknown_1; dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config, diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index dc0dcf249aa..bdc26e75ab5 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-input.c,v 1.11 2005/05/22 20:57:56 nsh Exp $ + * $Id: cx88-input.c,v 1.13 2005/06/13 16:07:46 nsh Exp $ * * Device driver for GPIO attached remote control interfaces * on Conexant 2388x based TV/DVB cards. @@ -125,6 +125,86 @@ static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = { /* ---------------------------------------------------------------------- */ +/* ADS Tech Instant TV DVB-T PCI Remote */ +static IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = { + [ 0x5b ] = KEY_POWER, + [ 0x5f ] = KEY_MUTE, + [ 0x57 ] = KEY_1, + [ 0x4f ] = KEY_2, + [ 0x53 ] = KEY_3, + [ 0x56 ] = KEY_4, + [ 0x4e ] = KEY_5, + [ 0x5e ] = KEY_6, + [ 0x54 ] = KEY_7, + [ 0x4c ] = KEY_8, + [ 0x5c ] = KEY_9, + [ 0x4d ] = KEY_0, + [ 0x55 ] = KEY_GOTO, + [ 0x5d ] = KEY_SEARCH, + [ 0x17 ] = KEY_EPG, // Guide + [ 0x1f ] = KEY_MENU, + [ 0x0f ] = KEY_UP, + [ 0x46 ] = KEY_DOWN, + [ 0x16 ] = KEY_LEFT, + [ 0x1e ] = KEY_RIGHT, + [ 0x0e ] = KEY_SELECT, // Enter + [ 0x5a ] = KEY_INFO, + [ 0x52 ] = KEY_EXIT, + [ 0x59 ] = KEY_PREVIOUS, + [ 0x51 ] = KEY_NEXT, + [ 0x58 ] = KEY_REWIND, + [ 0x50 ] = KEY_FORWARD, + [ 0x44 ] = KEY_PLAYPAUSE, + [ 0x07 ] = KEY_STOP, + [ 0x1b ] = KEY_RECORD, + [ 0x13 ] = KEY_TUNER, // Live + [ 0x0a ] = KEY_A, + [ 0x12 ] = KEY_B, + [ 0x03 ] = KEY_PROG1, // 1 + [ 0x01 ] = KEY_PROG2, // 2 + [ 0x00 ] = KEY_PROG3, // 3 + [ 0x06 ] = KEY_DVD, + [ 0x48 ] = KEY_AUX, // Photo + [ 0x40 ] = KEY_VIDEO, + [ 0x19 ] = KEY_AUDIO, // Music + [ 0x0b ] = KEY_CHANNELUP, + [ 0x08 ] = KEY_CHANNELDOWN, + [ 0x15 ] = KEY_VOLUMEUP, + [ 0x1c ] = KEY_VOLUMEDOWN, +}; + +/* ---------------------------------------------------------------------- */ + +/* MSI TV@nywhere remote */ +static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = { + [ 0x00 ] = KEY_0, /* '0' */ + [ 0x01 ] = KEY_1, /* '1' */ + [ 0x02 ] = KEY_2, /* '2' */ + [ 0x03 ] = KEY_3, /* '3' */ + [ 0x04 ] = KEY_4, /* '4' */ + [ 0x05 ] = KEY_5, /* '5' */ + [ 0x06 ] = KEY_6, /* '6' */ + [ 0x07 ] = KEY_7, /* '7' */ + [ 0x08 ] = KEY_8, /* '8' */ + [ 0x09 ] = KEY_9, /* '9' */ + [ 0x0c ] = KEY_MUTE, /* 'Mute' */ + [ 0x0f ] = KEY_SCREEN, /* 'Full Screen' */ + [ 0x10 ] = KEY_F, /* 'Funtion' */ + [ 0x11 ] = KEY_T, /* 'Time shift' */ + [ 0x12 ] = KEY_POWER, /* 'Power' */ + [ 0x13 ] = KEY_MEDIA, /* 'MTS' */ + [ 0x14 ] = KEY_SLOW, /* 'Slow' */ + [ 0x16 ] = KEY_REWIND, /* 'backward <<' */ + [ 0x17 ] = KEY_ENTER, /* 'Return' */ + [ 0x18 ] = KEY_FASTFORWARD, /* 'forward >>' */ + [ 0x1a ] = KEY_CHANNELUP, /* 'Channel+' */ + [ 0x1b ] = KEY_VOLUMEUP, /* 'Volume+' */ + [ 0x1e ] = KEY_CHANNELDOWN, /* 'Channel-' */ + [ 0x1f ] = KEY_VOLUMEDOWN, /* 'Volume-' */ +}; + +/* ---------------------------------------------------------------------- */ + struct cx88_IR { struct cx88_core *core; struct input_dev input; @@ -269,6 +349,20 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keyup = 0x80; ir->polling = 1; // ms break; + case CX88_BOARD_ADSTECH_DVB_T_PCI: + ir_codes = ir_codes_adstech_dvb_t_pci; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0xbf; + ir->mask_keyup = 0x40; + ir->polling = 50; // ms + break; + case CX88_BOARD_MSI_TVANYWHERE_MASTER: + ir_codes = ir_codes_msi_tvanywhere; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0x1f; + ir->mask_keyup = 0x40; + ir->polling = 1; + break; } if (NULL == ir_codes) { diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index e4ca7350df1..cd5c2615d8c 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-video.c,v 1.63 2005/06/12 04:19:19 mchehab Exp $ + * $Id: cx88-video.c,v 1.70 2005/06/20 03:36:00 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * video4linux video interface @@ -1350,9 +1350,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file, V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE | -#if 0 - V4L2_TUNER_CAP_LOW | -#endif #if 0 V4L2_CAP_VIDEO_OVERLAY | #endif @@ -1475,7 +1472,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } break; case 1: - if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD == core->board) { + if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q == core->board) { strcpy(a->name,"Line In"); a->capability = V4L2_AUDCAP_STEREO; return 0; @@ -1588,11 +1585,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_frequency *f = arg; + memset(f,0,sizeof(*f)); + if (UNSET == core->tuner_type) return -EINVAL; - if (f->tuner != 0) - return -EINVAL; - memset(f,0,sizeof(*f)); + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->freq; return 0; @@ -1612,11 +1609,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, down(&dev->lock); dev->freq = f->frequency; cx88_newstation(core); -#ifdef V4L2_I2C_CLIENTS cx88_call_i2c_clients(dev->core,VIDIOC_S_FREQUENCY,f); -#else - cx88_call_i2c_clients(dev->core,VIDIOCSFREQ,&dev->freq); -#endif up(&dev->lock); return 0; } @@ -1714,11 +1707,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER -#if 0 - | V4L2_TUNER_CAP_LOW -#endif - ; + cap->capabilities = V4L2_CAP_TUNER; return 0; } case VIDIOC_G_TUNER: @@ -1730,19 +1719,8 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, memset(t,0,sizeof(*t)); strcpy(t->name, "Radio"); - t->rangelow = (int)(65*16); - t->rangehigh = (int)(108*16); -#ifdef V4L2_I2C_CLIENTS cx88_call_i2c_clients(dev->core,VIDIOC_G_TUNER,t); -#else - { - struct video_tuner vt; - memset(&vt,0,sizeof(vt)); - cx88_call_i2c_clients(dev,VIDIOCGTUNER,&vt); - t->signal = vt.signal; - } -#endif return 0; } case VIDIOC_ENUMINPUT: @@ -1775,8 +1753,29 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, *id = 0; return 0; } - case VIDIOC_S_AUDIO: + case VIDIOCSTUNER: + { + struct video_tuner *v = arg; + + if (v->tuner) /* Only tuner 0 */ + return -EINVAL; + + cx88_call_i2c_clients(dev->core,VIDIOCSTUNER,v); + return 0; + } case VIDIOC_S_TUNER: + { + struct v4l2_tuner *t = arg; + + if (0 != t->index) + return -EINVAL; + + cx88_call_i2c_clients(dev->core,VIDIOC_S_TUNER,t); + + return 0; + } + + case VIDIOC_S_AUDIO: case VIDIOC_S_INPUT: case VIDIOC_S_STD: return 0; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 867e988a5a9..0c5311f7e62 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -1,5 +1,5 @@ /* - * $Id: cx88.h,v 1.62 2005/06/12 04:19:19 mchehab Exp $ + * $Id: cx88.h,v 1.66 2005/06/22 22:58:04 mchehab Exp $ * * v4l2 device driver for cx2388x based TV cards * @@ -51,8 +51,6 @@ /* ----------------------------------------------------------- */ /* defines and enums */ -#define V4L2_I2C_CLIENTS 1 - #define FORMAT_FLAGS_PACKED 0x01 #define FORMAT_FLAGS_PLANAR 0x02 @@ -159,7 +157,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_KWORLD_DVB_T 14 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1 15 #define CX88_BOARD_KWORLD_LTV883 16 -#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD 17 +#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q 17 #define CX88_BOARD_HAUPPAUGE_DVB_T1 18 #define CX88_BOARD_CONEXANT_DVB_T1 19 #define CX88_BOARD_PROVIDEO_PV259 20 @@ -167,10 +165,11 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_PCHDTV_HD3000 22 #define CX88_BOARD_DNTV_LIVE_DVB_T 23 #define CX88_BOARD_HAUPPAUGE_ROSLYN 24 -#define CX88_BOARD_DIGITALLOGIC_MEC 25 +#define CX88_BOARD_DIGITALLOGIC_MEC 25 #define CX88_BOARD_IODATA_GVBCTV7E 26 #define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27 #define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T 28 +#define CX88_BOARD_ADSTECH_DVB_T_PCI 29 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, -- cgit v1.2.3 From 9ac4c158b0090462bc356b934024cf0c5d7c8526 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 7 Jul 2005 17:58:38 -0700 Subject: [PATCH] v4l: cx88 hue offset fix Changed hue offset to 128 to correct behavior in cx88 cards. Previously, setting 0% or 100% hue was required to avoid blue/green people on screen. Now, 50% Hue means no offset, just like bt878 stuff. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/cx88/cx88-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index cd5c2615d8c..dc997549b63 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -261,7 +261,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .default_value = 0, .type = V4L2_CTRL_TYPE_INTEGER, }, - .off = 0, + .off = 128, .reg = MO_HUE, .mask = 0x00ff, .shift = 0, -- cgit v1.2.3 From f1798495592c1bcd7871abdc1ef2985d65c34224 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 7 Jul 2005 17:58:39 -0700 Subject: [PATCH] v4l: add DVB support for DViCO FusionHDTV3 Gold-Q Add dvb support in v4l for DViCO FusionHDTV3 Gold-Q using lgdt3302 frontend. Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/cx88/cx88-cards.c | 1 + drivers/media/video/cx88/cx88-dvb.c | 43 +++++++++++++++++++++++++++++++++-- drivers/media/video/cx88/cx88-i2c.c | 3 ++- drivers/media/video/cx88/cx88-mpeg.c | 13 +++++++---- 4 files changed, 53 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index f9e4cb19687..75de9cab4db 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -485,6 +485,7 @@ struct cx88_board cx88_boards[] = { .vmux = 2, .gpio0 = 0x0f00, }}, + .dvb = 1, }, [CX88_BOARD_HAUPPAUGE_DVB_T1] = { .name = "Hauppauge Nova-T DVB-T", diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 82cc1538c10..206c6a0980e 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-dvb.c,v 1.36 2005/06/21 06:08:12 mkrufky Exp $ + * $Id: cx88-dvb.c,v 1.37 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * MPEG Transport Stream (DVB) routines @@ -30,9 +30,10 @@ #include #include -/* those two frontends need merging via linuxtv cvs ... */ +/* these three frontends need merging via linuxtv cvs ... */ #define HAVE_CX22702 1 #define HAVE_OR51132 1 +#define HAVE_LGDT3302 1 #include "cx88.h" #include "dvb-pll.h" @@ -44,6 +45,9 @@ #if HAVE_OR51132 # include "or51132.h" #endif +#if HAVE_LGDT3302 +# include "lgdt3302.h" +#endif MODULE_DESCRIPTION("driver for cx2388x based DVB cards"); MODULE_AUTHOR("Chris Pascoe "); @@ -199,6 +203,25 @@ static struct or51132_config pchdtv_hd3000 = { }; #endif +#if HAVE_LGDT3302 +static int lgdt3302_set_ts_param(struct dvb_frontend* fe, int is_punctured) +{ + struct cx8802_dev *dev= fe->dvb->priv; + if (is_punctured) + dev->ts_gen_cntrl |= 0x04; + else + dev->ts_gen_cntrl &= ~0x04; + return 0; +} + +static struct lgdt3302_config fusionhdtv_3_gold_q = { + .demod_address = 0x0e, + .pll_address = 0x61, + .pll_desc = &dvb_pll_microtune_4042, + .set_ts_params = lgdt3302_set_ts_param, +}; +#endif + static int dvb_register(struct cx8802_dev *dev) { /* init struct videobuf_dvb */ @@ -242,6 +265,22 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend = or51132_attach(&pchdtv_hd3000, &dev->core->i2c_adap); break; +#endif +#if HAVE_LGDT3302 + case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: + dev->ts_gen_cntrl = 0x08; + { + /* Do a hardware reset of chip before using it. */ + struct cx88_core *core = dev->core; + + cx_clear(MO_GP0_IO, 1); + mdelay(100); + cx_set(MO_GP0_IO, 9); // ANT connector too FIXME + mdelay(200); + dev->dvb.frontend = lgdt3302_attach(&fusionhdtv_3_gold_q, + &dev->core->i2c_adap); + } + break; #endif default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index e20adefcfc6..b5342234b30 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -1,5 +1,5 @@ /* - $Id: cx88-i2c.c,v 1.23 2005/06/12 04:19:19 mchehab Exp $ + $Id: cx88-i2c.c,v 1.24 2005/06/17 18:46:23 mkrufky Exp $ cx88-i2c.c -- all the i2c code is here @@ -157,6 +157,7 @@ static struct i2c_client cx8800_i2c_client_template = { }; static char *i2c_devs[128] = { + [ 0x1c >> 1 ] = "lgdt3302", [ 0x86 >> 1 ] = "tda9887/cx22702", [ 0xa0 >> 1 ] = "eeprom", [ 0xc0 >> 1 ] = "tuner (analog)", diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 9ade2ae91e9..c5f4c595239 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-mpeg.c,v 1.26 2005/06/03 13:31:51 mchehab Exp $ + * $Id: cx88-mpeg.c,v 1.28 2005/06/20 03:36:00 mkrufky Exp $ * * Support for the mpeg transport stream transfers * PCI function #2 of the cx2388x. @@ -70,11 +70,16 @@ static int cx8802_start_dma(struct cx8802_dev *dev, if (cx88_boards[core->board].dvb) { /* negedge driven & software reset */ - cx_write(TS_GEN_CNTRL, 0x40); + cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); udelay(100); cx_write(MO_PINMUX_IO, 0x00); - cx_write(TS_HW_SOP_CNTRL,47<<16|188<<4|0x00); - cx_write(TS_SOP_STAT,0x00); + if (core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q) { + cx_write(TS_HW_SOP_CNTRL,0x47<<16 | 188<<4 | 0x00); + cx_write(TS_SOP_STAT, 0<<16 | 0<<14 | 1<<13 | 0<<12); + } else { + cx_write(TS_HW_SOP_CNTRL,47<<16|188<<4|0x00); + cx_write(TS_SOP_STAT,0x00); + } cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); udelay(100); } -- cgit v1.2.3 From e057ee11efb84e559c55e98d33acb341fe68fda1 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 7 Jul 2005 17:58:40 -0700 Subject: [PATCH] v4l: add TerraTec Cinergy 1400 DVB-T Add support for TerraTec Cinergy 1400 DVB-T. Signed-off-by: Uli Luckas Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/cx88/cx88-cards.c | 15 ++++++++++++++- drivers/media/video/cx88/cx88-dvb.c | 3 ++- drivers/media/video/cx88/cx88.h | 3 ++- 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 75de9cab4db..eeca2f3f2a0 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-cards.c,v 1.82 2005/06/28 04:33:53 mkrufky Exp $ + * $Id: cx88-cards.c,v 1.84 2005/07/02 19:42:09 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * card-specific stuff. @@ -743,6 +743,15 @@ struct cx88_board cx88_boards[] = { }}, .dvb = 1, }, + [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = { + .name = "TerraTec Cinergy 1400 DVB-T", + .tuner_type = TUNER_ABSENT, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + }}, + .dvb = 1, + }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -866,6 +875,10 @@ struct cx88_subid cx88_subids[] = { .subvendor = 0x1421, .subdevice = 0x0334, .card = CX88_BOARD_ADSTECH_DVB_T_PCI, + },{ + .subvendor = 0x153b, + .subdevice = 0x1166, + .card = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 206c6a0980e..806afc610d8 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-dvb.c,v 1.37 2005/06/28 23:41:47 mkrufky Exp $ + * $Id: cx88-dvb.c,v 1.39 2005/07/02 20:00:46 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * MPEG Transport Stream (DVB) routines @@ -235,6 +235,7 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config, &dev->core->i2c_adap); break; + case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1: case CX88_BOARD_CONEXANT_DVB_T1: dev->dvb.frontend = cx22702_attach(&connexant_refboard_config, &dev->core->i2c_adap); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 0c5311f7e62..bc5e038bc0f 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -1,5 +1,5 @@ /* - * $Id: cx88.h,v 1.66 2005/06/22 22:58:04 mchehab Exp $ + * $Id: cx88.h,v 1.67 2005/07/01 12:10:07 mkrufky Exp $ * * v4l2 device driver for cx2388x based TV cards * @@ -170,6 +170,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27 #define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T 28 #define CX88_BOARD_ADSTECH_DVB_T_PCI 29 +#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1 30 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, -- cgit v1.2.3 From 0d723c09f03e0b2cb4405c361c927efac373fe0c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 7 Jul 2005 17:58:42 -0700 Subject: [PATCH] v4l: add DVB support for DViCO FusionHDTV3 Gold-T - Correct sync byte for MPEG-2 transport stream packets. - Add lgdt3302 as dependency of cx88-dvb in Kconfig. - Add dvb support in v4l for DViCO FusionHDTV3 Gold-T using lgdt3302 frontend. This adds support for a different board from the previous (Gold-Q) patch. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/dvb-pll.c | 13 +++++++++++++ drivers/media/dvb/frontends/dvb-pll.h | 1 + drivers/media/video/Kconfig | 1 + drivers/media/video/cx88/cx88-cards.c | 3 ++- drivers/media/video/cx88/cx88-dvb.c | 21 +++++++++++++++++++++ drivers/media/video/cx88/cx88-mpeg.c | 8 ++++---- 6 files changed, 42 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 71e06ec7925..5afeaa9b43b 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -106,6 +106,19 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = { }; EXPORT_SYMBOL(dvb_pll_microtune_4042); +struct dvb_pll_desc dvb_pll_thomson_dtt7611 = { + .name = "Thomson dtt7611", + .min = 44000000, + .max = 958000000, + .count = 3, + .entries = { + { 157250000, 44000000, 62500, 0x8e, 0x39 }, + { 454000000, 44000000, 62500, 0x8e, 0x3a }, + { 999999999, 44000000, 62500, 0x8e, 0x3c }, + }, +}; +EXPORT_SYMBOL(dvb_pll_thomson_dtt7611); + struct dvb_pll_desc dvb_pll_unknown_1 = { .name = "unknown 1", /* used by dntv live dvb-t */ .min = 174000000, diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 98312bfe59d..cb794759d89 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -25,6 +25,7 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt759x; extern struct dvb_pll_desc dvb_pll_thomson_dtt7610; extern struct dvb_pll_desc dvb_pll_lg_z201; extern struct dvb_pll_desc dvb_pll_microtune_4042; +extern struct dvb_pll_desc dvb_pll_thomson_dtt7611; extern struct dvb_pll_desc dvb_pll_unknown_1; extern struct dvb_pll_desc dvb_pll_tua6010xs; diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 1b70f8b0feb..e771064689e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -344,6 +344,7 @@ config VIDEO_CX88_DVB select DVB_MT352 select DVB_OR51132 select DVB_CX22702 + select DVB_LGDT3302 ---help--- This adds support for DVB/ATSC cards based on the Connexant 2388x chip. diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index eeca2f3f2a0..b0b47c3cde3 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-cards.c,v 1.84 2005/07/02 19:42:09 mkrufky Exp $ + * $Id: cx88-cards.c,v 1.85 2005/07/04 19:35:05 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * card-specific stuff. @@ -723,6 +723,7 @@ struct cx88_board cx88_boards[] = { .vmux = 2, .gpio0 = 0x0f00, }}, + .dvb = 1, }, [CX88_BOARD_ADSTECH_DVB_T_PCI] = { .name = "ADS Tech Instant TV DVB-T PCI", diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 806afc610d8..690477a6791 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -220,6 +220,13 @@ static struct lgdt3302_config fusionhdtv_3_gold_q = { .pll_desc = &dvb_pll_microtune_4042, .set_ts_params = lgdt3302_set_ts_param, }; + +static struct lgdt3302_config fusionhdtv_3_gold_t = { + .demod_address = 0x0e, + .pll_address = 0x61, + .pll_desc = &dvb_pll_thomson_dtt7611, + .set_ts_params = lgdt3302_set_ts_param, +}; #endif static int dvb_register(struct cx8802_dev *dev) @@ -282,6 +289,20 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); } break; + case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: + dev->ts_gen_cntrl = 0x08; + { + /* Do a hardware reset of chip before using it. */ + struct cx88_core *core = dev->core; + + cx_clear(MO_GP0_IO, 1); + mdelay(100); + cx_set(MO_GP0_IO, 9); /* ANT connector too FIXME */ + mdelay(200); + dev->dvb.frontend = lgdt3302_attach(&fusionhdtv_3_gold_t, + &dev->core->i2c_adap); + } + break; #endif default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index c5f4c595239..85da6dc8d0e 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-mpeg.c,v 1.28 2005/06/20 03:36:00 mkrufky Exp $ + * $Id: cx88-mpeg.c,v 1.30 2005/07/05 19:44:40 mkrufky Exp $ * * Support for the mpeg transport stream transfers * PCI function #2 of the cx2388x. @@ -73,11 +73,11 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); udelay(100); cx_write(MO_PINMUX_IO, 0x00); - if (core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q) { - cx_write(TS_HW_SOP_CNTRL,0x47<<16 | 188<<4 | 0x00); + cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); + if ((core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q) || + (core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T)) { cx_write(TS_SOP_STAT, 0<<16 | 0<<14 | 1<<13 | 0<<12); } else { - cx_write(TS_HW_SOP_CNTRL,47<<16|188<<4|0x00); cx_write(TS_SOP_STAT,0x00); } cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); -- cgit v1.2.3 From 08d805258f69bff5ba8268a969f140ef1f105c71 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Thu, 7 Jul 2005 17:58:43 -0700 Subject: [PATCH] v4l: LGDT3302 read status fix - Fix bug in lgdt3302_read_status to return correct FE_HAS_SIGNAL and FS_HAS_CARRIER status. - Removed #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10). Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/lgdt3302.c | 43 ++++++++++++++-------------------- 1 file changed, 18 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c index d0b91219cf6..09c914256e4 100644 --- a/drivers/media/dvb/frontends/lgdt3302.c +++ b/drivers/media/dvb/frontends/lgdt3302.c @@ -1,5 +1,5 @@ /* - * $Id: lgdt3302.c,v 1.2 2005/06/28 23:50:48 mkrufky Exp $ + * $Id: lgdt3302.c,v 1.5 2005/07/07 03:47:15 mkrufky Exp $ * * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM * @@ -34,7 +34,6 @@ * */ -#include #include #include #include @@ -208,8 +207,6 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) - /* Use 50MHz parameter values from spec sheet since xtal is 50 */ static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; static u8 vsb_freq_cfg[] = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 }; @@ -301,9 +298,6 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, lgdt3302_SwReset(state); state->current_modulation = param->u.vsb.modulation; } -#else - printk("lgdt3302: %s: you need a newer kernel for this, sorry\n",__FUNCTION__); -#endif /* Change only if we are actually changing the channel */ if (state->current_frequency != param->frequency) { @@ -352,11 +346,28 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) * This is done in SwReset(); */ + /* AGC status register */ + i2c_selectreadbytes(state, AGC_STATUS, buf, 1); + dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); + if ((buf[0] & 0x0c) == 0x8){ + /* Test signal does not exist flag */ + /* as well as the AGC lock flag. */ + *status |= FE_HAS_SIGNAL; + } else { + /* Without a signal all other status bits are meaningless */ + return 0; + } + /* signal status */ i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf)); dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]); + +#if 0 + /* Alternative method to check for a signal */ + /* using the SNR good/bad interrupts. */ if ((buf[2] & 0x30) == 0x10) *status |= FE_HAS_SIGNAL; +#endif /* sync status */ if ((buf[2] & 0x03) == 0x01) { @@ -369,17 +380,6 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) *status |= FE_HAS_VITERBI; } -#if 0 - /* Alternative method to check for a signal */ - /* AGC status register */ - i2c_selectreadbytes(state, AGC_STATUS, buf, 1); - dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); - if ((buf[0] & 0x0c) == 0x80) /* Test signal does not exist flag */ - /* Test AGC lock flag */ - *status |= FE_HAS_SIGNAL; - else - return 0; - /* Carrier Recovery Lock Status Register */ i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1); dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]); @@ -389,21 +389,14 @@ static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) /* Need to undestand why there are 3 lock levels here */ if ((buf[0] & 0x07) == 0x07) *status |= FE_HAS_CARRIER; - else - return 0; break; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) case VSB_8: if ((buf[0] & 0x80) == 0x80) *status |= FE_HAS_CARRIER; - else - return 0; break; -#endif default: printk("KERN_WARNING lgdt3302: %s: Modulation set to unsupported value\n", __FUNCTION__); } -#endif return 0; } -- cgit v1.2.3 From 69a4d56bae492b1a5e74459d9d771d9bc7f9320f Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 7 Jul 2005 17:58:52 -0700 Subject: [PATCH] pcmcia: fix i82365 request_region double usage http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=f354942cb301fed273f423fb5c4f57bde3efc5b2 converted the check_region() calls in drivers/pcmcia/i82365.c into request_regions. Unfortunately this seems to have broken things. isa_probe() used to call check_region() and then call add_pcic() which would request_region(). Now isa_probe() calls request_region() and then calls add_pcic() which calls request_region() again, this fails and add_pcic() returns immediately without doing all the setup etc. On the face of it the patch below fixes the problem, by not doing the second request region in add_pcic(). I think this is preferable to remove the call in isa_probe() since identify() touches the I/O regions and is called before add_pcic(). However I haven't fully grokked the meaning of the code which follows the request_region() in isa_probe(), so I'm not sure that the handling WRT multiple sockets and multiple bridge chips is correct. In particular I'm not convinced that the regions for subsequent sockets and/or bridges will be requested at all. I suspect a more thorough reworking by someone who understands what is going on there might be in order. I should mention that I'm actually messing about with this on an ARM platform with wacky memory and i/o mapping offsets etc, it doesn't quite work yet for other reasons which preclude full testing etc, but I think the problem above is still present for more normal x86 stuff. Signed-off-by: Ian Campbell Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/i82365.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index d72f9a35c8b..3546158ef77 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -698,14 +698,6 @@ static void __init add_pcic(int ns, int type) struct i82365_socket *t = &socket[sockets-ns]; base = sockets-ns; - if (t->ioaddr > 0) { - if (!request_region(t->ioaddr, 2, "i82365")) { - printk(KERN_ERR "i82365: IO region conflict at %#lx, not available\n", - t->ioaddr); - return; - } - } - if (base == 0) printk("\n"); printk(KERN_INFO " %s", pcic[type].name); printk(" ISA-to-PCMCIA at port %#lx ofs 0x%02x", -- cgit v1.2.3 From bf45d9b0ac108b11245203ebb082d30f5059846b Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 7 Jul 2005 17:58:58 -0700 Subject: [PATCH] pcmcia: deprecate ioctl Schedule removal of the PCMCIA ioctl (and thus kernel support for the pcmcia-cs userspace package) for November 2005. A big "thank you" to Dave Hinds for his great work on supporting PCMCIA in Linux. Things are just done differently by now, so the ongoing work to make PCMCIA behave like any other hotpluggable bus should continue. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/Kconfig | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 52ea3459436..bb4dd2735d7 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -1,8 +1,5 @@ # -# PCMCIA bus subsystem configuration -# -# Right now the non-CardBus choices are not supported -# by the integrated kernel driver. +# PCCARD (PCMCIA/CardBus) bus subsystem configuration # menu "PCCARD (PCMCIA/CardBus) support" @@ -32,7 +29,7 @@ config PCMCIA_DEBUG The kernel command line options are: pcmcia_core.pc_debug=N - ds.pc_debug=N + pcmcia.pc_debug=N sa11xx_core.pc_debug=N The module option is called pc_debug=N @@ -73,7 +70,7 @@ config PCMCIA_LOAD_CIS If unsure, say Y. config PCMCIA_IOCTL - bool + bool "PCMCIA control ioctl (obsolete)" depends on PCMCIA default y help @@ -81,9 +78,8 @@ config PCMCIA_IOCTL subsystem will be built. It is needed by cardmgr and cardctl (pcmcia-cs) to function properly. - If you do not use the new pcmciautils package, and have a - yenta, Cirrus PD6729, i82092, i82365 or tcic compatible bridge, - you need to say Y here to be able to use 16-bit PCMCIA cards. + You should use the new pcmciautils package instead (see + for location and details). If unsure, say Y. -- cgit v1.2.3 From 1e212f3645a6b355de8c43a23376bc0e2ac49a63 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 7 Jul 2005 17:59:00 -0700 Subject: [PATCH] pcmcia: move event handler Move the "event handler" to struct pcmcia_driver -- the unified event handler will disappear really soon, but switching it to struct pcmcia_driver in the meantime allows for better "step-by-step" patches. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/bluetooth/bluecard_cs.c | 6 +----- drivers/bluetooth/bt3c_cs.c | 6 +----- drivers/bluetooth/btuart_cs.c | 6 +----- drivers/bluetooth/dtl1_cs.c | 6 +----- drivers/char/pcmcia/synclink_cs.c | 6 +----- drivers/ide/legacy/ide-cs.c | 6 +----- drivers/isdn/hardware/avm/avm_cs.c | 6 +----- drivers/isdn/hisax/avma1_cs.c | 6 +----- drivers/isdn/hisax/elsa_cs.c | 6 +----- drivers/isdn/hisax/sedlbauer_cs.c | 6 +----- drivers/isdn/hisax/teles_cs.c | 6 +----- drivers/mtd/maps/pcmciamtd.c | 6 +----- drivers/net/pcmcia/3c574_cs.c | 6 +----- drivers/net/pcmcia/3c589_cs.c | 6 +----- drivers/net/pcmcia/axnet_cs.c | 6 +----- drivers/net/pcmcia/com20020_cs.c | 6 +----- drivers/net/pcmcia/fmvj18x_cs.c | 6 +----- drivers/net/pcmcia/ibmtr_cs.c | 6 +----- drivers/net/pcmcia/nmclan_cs.c | 6 +----- drivers/net/pcmcia/pcnet_cs.c | 6 +----- drivers/net/pcmcia/smc91c92_cs.c | 5 +---- drivers/net/pcmcia/xirc2ps_cs.c | 6 +----- drivers/net/wireless/airo_cs.c | 6 +----- drivers/net/wireless/atmel_cs.c | 16 ++++++---------- drivers/net/wireless/netwave_cs.c | 6 +----- drivers/net/wireless/orinoco_cs.c | 6 +----- drivers/net/wireless/ray_cs.c | 6 +----- drivers/net/wireless/wavelan_cs.c | 7 +------ drivers/net/wireless/wl3501_cs.c | 18 ++++++------------ drivers/parport/parport_cs.c | 6 +----- drivers/pcmcia/cs_internal.h | 3 --- drivers/pcmcia/ds.c | 32 ++++++++++++++++++++------------ drivers/scsi/pcmcia/aha152x_stub.c | 6 +----- drivers/scsi/pcmcia/fdomain_stub.c | 6 +----- drivers/scsi/pcmcia/nsp_cs.c | 16 ++++++---------- drivers/scsi/pcmcia/qlogic_stub.c | 3 +-- drivers/scsi/pcmcia/sym53c500_cs.c | 5 +---- drivers/serial/serial_cs.c | 6 +----- drivers/telephony/ixj_pcmcia.c | 6 +----- drivers/usb/host/sl811_cs.c | 6 +----- 40 files changed, 73 insertions(+), 218 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 5ef9adb9fe7..53661246100 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -895,11 +895,6 @@ static dev_link_t *bluecard_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &bluecard_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -1103,6 +1098,7 @@ static struct pcmcia_driver bluecard_driver = { .name = "bluecard_cs", }, .attach = bluecard_attach, + .event = bluecard_event, .detach = bluecard_detach, .id_table = bluecard_ids, }; diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 9013cd759af..06539a542e9 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -696,11 +696,6 @@ static dev_link_t *bt3c_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &bt3c_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -947,6 +942,7 @@ static struct pcmcia_driver bt3c_driver = { .name = "bt3c_cs", }, .attach = bt3c_attach, + .event = bt3c_event, .detach = bt3c_detach, .id_table = bt3c_ids, }; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index c479484a1f7..f15a9cf2b78 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -615,11 +615,6 @@ static dev_link_t *btuart_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &btuart_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -867,6 +862,7 @@ static struct pcmcia_driver btuart_driver = { .name = "btuart_cs", }, .attach = btuart_attach, + .event = btuart_event, .detach = btuart_detach, .id_table = btuart_ids, }; diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index bb12f7daeb9..58b09a9cc4c 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -594,11 +594,6 @@ static dev_link_t *dtl1_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &dtl1_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -820,6 +815,7 @@ static struct pcmcia_driver dtl1_driver = { .name = "dtl1_cs", }, .attach = dtl1_attach, + .event = dtl1_event, .detach = dtl1_detach, .id_table = dtl1_ids, }; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 8f36b1758eb..ea691561e08 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -593,11 +593,6 @@ static dev_link_t *mgslpc_attach(void) dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &mgslpc_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -3093,6 +3088,7 @@ static struct pcmcia_driver mgslpc_driver = { .name = "synclink_cs", }, .attach = mgslpc_attach, + .event = mgslpc_event, .detach = mgslpc_detach, .id_table = mgslpc_ids, }; diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 978d27d6452..fde0d5f1b87 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -134,11 +134,6 @@ static dev_link_t *ide_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &ide_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -497,6 +492,7 @@ static struct pcmcia_driver ide_cs_driver = { .name = "ide-cs", }, .attach = ide_attach, + .event = ide_event, .detach = ide_detach, .id_table = ide_ids, }; diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index ee750e9456d..a30c74fd75d 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -161,11 +161,6 @@ static dev_link_t *avmcs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &avmcs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -500,6 +495,7 @@ static struct pcmcia_driver avmcs_driver = { .name = "avm_cs", }, .attach = avmcs_attach, + .event = avmcs_event, .detach = avmcs_detach, .id_table = avmcs_ids, }; diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index 67c60e04a37..d3de0e85619 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -183,11 +183,6 @@ static dev_link_t *avma1cs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &avma1cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -514,6 +509,7 @@ static struct pcmcia_driver avma1cs_driver = { .name = "avma1_cs", }, .attach = avma1cs_attach, + .event = avma1cs_event, .detach = avma1cs_detach, .id_table = avma1cs_ids, }; diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index 9146be54704..54f0d68ad79 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -212,11 +212,6 @@ static dev_link_t *elsa_cs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &elsa_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -521,6 +516,7 @@ static struct pcmcia_driver elsa_cs_driver = { .name = "elsa_cs", }, .attach = elsa_cs_attach, + .event = elsa_cs_event, .detach = elsa_cs_detach, .id_table = elsa_ids, }; diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 058147a6957..baf733e8647 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -226,11 +226,6 @@ static dev_link_t *sedlbauer_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &sedlbauer_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -634,6 +629,7 @@ static struct pcmcia_driver sedlbauer_driver = { .name = "sedlbauer_cs", }, .attach = sedlbauer_attach, + .event = sedlbauer_event, .detach = sedlbauer_detach, .id_table = sedlbauer_ids, }; diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index 107376ff5b9..b8eeb789f90 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -193,11 +193,6 @@ static dev_link_t *teles_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &teles_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -501,6 +496,7 @@ static struct pcmcia_driver teles_cs_driver = { .name = "teles_cs", }, .attach = teles_attach, + .event = teles_cs_event, .detach = teles_detach, .id_table = teles_ids, }; diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index c2655a817e3..aa820ee4c31 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -800,11 +800,6 @@ static dev_link_t *pcmciamtd_attach(void) /* Register with Card Services */ client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &pcmciamtd_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; DEBUG(2, "Calling RegisterClient"); @@ -850,6 +845,7 @@ static struct pcmcia_driver pcmciamtd_driver = { .name = "pcmciamtd" }, .attach = pcmciamtd_attach, + .event = pcmciamtd_event, .detach = pcmciamtd_detach, .owner = THIS_MODULE, .id_table = pcmciamtd_ids, diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index f0fc04bd37c..c942964a49d 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -312,11 +312,6 @@ static dev_link_t *tc574_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &tc574_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1299,6 +1294,7 @@ static struct pcmcia_driver tc574_driver = { .name = "3c574_cs", }, .attach = tc574_attach, + .event = tc574_event, .detach = tc574_detach, .id_table = tc574_ids, }; diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 8fa1b5f0fb6..810864c6d1e 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -226,11 +226,6 @@ static dev_link_t *tc589_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &tc589_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1074,6 +1069,7 @@ static struct pcmcia_driver tc589_driver = { .name = "3c589_cs", }, .attach = tc589_attach, + .event = tc589_event, .detach = tc589_detach, .id_table = tc589_ids, }; diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 23ce77b1d5b..3d01079598c 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -181,11 +181,6 @@ static dev_link_t *axnet_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &axnet_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -884,6 +879,7 @@ static struct pcmcia_driver axnet_cs_driver = { .name = "axnet_cs", }, .attach = axnet_attach, + .event = axnet_event, .detach = axnet_detach, .id_table = axnet_ids, }; diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 68d58cc58d3..b5119607d5a 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -200,11 +200,6 @@ static dev_link_t *com20020_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &com20020_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -495,6 +490,7 @@ static struct pcmcia_driver com20020_cs_driver = { .name = "com20020_cs", }, .attach = com20020_attach, + .event = com20020_event, .detach = com20020_detach, .id_table = com20020_ids, }; diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 917adbbf0b5..c7d9bb1da41 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -288,11 +288,6 @@ static dev_link_t *fmvj18x_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &fmvj18x_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -797,6 +792,7 @@ static struct pcmcia_driver fmvj18x_cs_driver = { .name = "fmvj18x_cs", }, .attach = fmvj18x_attach, + .event = fmvj18x_event, .detach = fmvj18x_detach, .id_table = fmvj18x_ids, }; diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index cf6d073ea55..39cec4a1e4b 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -190,11 +190,6 @@ static dev_link_t *ibmtr_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &ibmtr_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -521,6 +516,7 @@ static struct pcmcia_driver ibmtr_cs_driver = { .name = "ibmtr_cs", }, .attach = ibmtr_attach, + .event = ibmtr_event, .detach = ibmtr_detach, .id_table = ibmtr_ids, }; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index b86e7253fbf..49124dc26b3 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -502,11 +502,6 @@ static dev_link_t *nmclan_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &nmclan_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1688,6 +1683,7 @@ static struct pcmcia_driver nmclan_cs_driver = { .name = "nmclan_cs", }, .attach = nmclan_attach, + .event = nmclan_event, .detach = nmclan_detach, .id_table = nmclan_ids, }; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 855a45d062b..b22b354af5c 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -276,11 +276,6 @@ static dev_link_t *pcnet_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &pcnet_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1844,6 +1839,7 @@ static struct pcmcia_driver pcnet_driver = { .name = "pcnet_cs", }, .attach = pcnet_attach, + .event = pcnet_event, .detach = pcnet_detach, .owner = THIS_MODULE, .id_table = pcnet_ids, diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index bc01c88c670..6b5471dfb55 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -370,10 +370,6 @@ static dev_link_t *smc91c92_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &smc91c92_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -2365,6 +2361,7 @@ static struct pcmcia_driver smc91c92_cs_driver = { .name = "smc91c92_cs", }, .attach = smc91c92_attach, + .event = smc91c92_event, .detach = smc91c92_detach, .id_table = smc91c92_ids, }; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 0cd225e1595..03d4c0c6b3f 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -619,11 +619,6 @@ xirc2ps_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &xirc2ps_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; if ((err = pcmcia_register_client(&link->handle, &client_reg))) { @@ -2016,6 +2011,7 @@ static struct pcmcia_driver xirc2ps_cs_driver = { .name = "xirc2ps_cs", }, .attach = xirc2ps_attach, + .event = xirc2ps_event, .detach = xirc2ps_detach, .id_table = xirc2ps_ids, }; diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index f10a9523034..fd46393e743 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -210,11 +210,6 @@ static dev_link_t *airo_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &airo_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -574,6 +569,7 @@ static struct pcmcia_driver airo_driver = { .name = "airo_cs", }, .attach = airo_attach, + .event = airo_event, .detach = airo_detach, .id_table = airo_ids, }; diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 86379d4998a..863be299503 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -218,11 +218,6 @@ static dev_link_t *atmel_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &atmel_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -668,12 +663,13 @@ static struct pcmcia_device_id atmel_ids[] = { MODULE_DEVICE_TABLE(pcmcia, atmel_ids); static struct pcmcia_driver atmel_driver = { - .owner = THIS_MODULE, - .drv = { - .name = "atmel_cs", + .owner = THIS_MODULE, + .drv = { + .name = "atmel_cs", }, - .attach = atmel_attach, - .detach = atmel_detach, + .attach = atmel_attach, + .event = atmel_event, + .detach = atmel_detach, .id_table = atmel_ids, }; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index e12bd75b269..bdd3e7083d9 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -491,11 +491,6 @@ static dev_link_t *netwave_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &netwave_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1680,6 +1675,7 @@ static struct pcmcia_driver netwave_driver = { .name = "netwave_cs", }, .attach = netwave_attach, + .event = netwave_event, .detach = netwave_detach, .id_table = netwave_ids, }; diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 597c4586d04..c883404b1d5 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -186,11 +186,6 @@ orinoco_cs_attach(void) dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &orinoco_cs_event; client_reg.Version = 0x0210; /* FIXME: what does this mean? */ client_reg.event_callback_args.client_data = link; @@ -664,6 +659,7 @@ static struct pcmcia_driver orinoco_driver = { .name = DRIVER_NAME, }, .attach = orinoco_cs_attach, + .event = orinoco_cs_event, .detach = orinoco_cs_detach, .id_table = orinoco_cs_ids, }; diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 31652af52ea..0643b1b94a3 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -393,11 +393,6 @@ static dev_link_t *ray_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &ray_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -2916,6 +2911,7 @@ static struct pcmcia_driver ray_driver = { .name = "ray_cs", }, .attach = ray_attach, + .event = ray_event, .detach = ray_detach, .id_table = ray_ids, }; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 89532fd9294..f6130a53b79 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -4684,12 +4684,6 @@ wavelan_attach(void) /* Register with Card Services */ client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_REGISTRATION_COMPLETE | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &wavelan_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -4904,6 +4898,7 @@ static struct pcmcia_driver wavelan_driver = { .name = "wavelan_cs", }, .attach = wavelan_attach, + .event = wavelan_event, .detach = wavelan_detach, .id_table = wavelan_ids, }; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index e3a900482d9..e3aaaa5efcc 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -2005,13 +2005,6 @@ static dev_link_t *wl3501_attach(void) link->next = wl3501_dev_list; wl3501_dev_list = link; client_reg.dev_info = &wl3501_dev_info; - client_reg.EventMask = CS_EVENT_CARD_INSERTION | - CS_EVENT_RESET_PHYSICAL | - CS_EVENT_CARD_RESET | - CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | - CS_EVENT_PM_RESUME; - client_reg.event_handler = wl3501_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -2246,12 +2239,13 @@ static struct pcmcia_device_id wl3501_ids[] = { MODULE_DEVICE_TABLE(pcmcia, wl3501_ids); static struct pcmcia_driver wl3501_driver = { - .owner = THIS_MODULE, - .drv = { - .name = "wl3501_cs", + .owner = THIS_MODULE, + .drv = { + .name = "wl3501_cs", }, - .attach = wl3501_attach, - .detach = wl3501_detach, + .attach = wl3501_attach, + .event = wl3501_event, + .detach = wl3501_detach, .id_table = wl3501_ids, }; diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index ff45662c4f7..ad8921a260e 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -133,11 +133,6 @@ static dev_link_t *parport_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &parport_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -386,6 +381,7 @@ static struct pcmcia_driver parport_cs_driver = { .name = "parport_cs", }, .attach = parport_attach, + .event = parport_event, .detach = parport_detach, .id_table = parport_ids, diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 0b4c18edfa4..e0ba4b5daa1 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -114,9 +114,6 @@ static inline void cs_socket_put(struct pcmcia_socket *skt) #define CHECK_ERASEQ(q) \ (((q) == NULL) || ((q)->eraseq_magic != ERASEQ_MAGIC)) -#define EVENT(h, e, p) \ - ((h)->event_handler((e), (p), &(h)->event_callback_args)) - /* In cardbus.c */ int cb_alloc(struct pcmcia_socket *s); void cb_free(struct pcmcia_socket *s); diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index d5afd557fe3..367ebf75bee 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -207,6 +207,10 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) unsigned int i; u32 hash; + if (!p_drv->attach || !p_drv->event || !p_drv->detach) + printk(KERN_DEBUG "pcmcia: %s does misses a callback function", + p_drv->drv.name); + while (did && did->match_flags) { for (i=0; i<4; i++) { if (!did->prod_id[i]) @@ -914,6 +918,7 @@ struct send_event_data { static int send_event_callback(struct device *dev, void * _data) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); + struct pcmcia_driver *p_drv; struct send_event_data *data = _data; /* we get called for all sockets, but may only pass the event @@ -921,11 +926,16 @@ static int send_event_callback(struct device *dev, void * _data) if (p_dev->socket != data->skt) return 0; + p_drv = to_pcmcia_drv(p_dev->dev.driver); + if (!p_drv) + return 0; + if (p_dev->client.state & (CLIENT_UNBOUND|CLIENT_STALE)) return 0; - if (p_dev->client.EventMask & data->event) - return EVENT(&p_dev->client, data->event, data->priority); + if (p_drv->event) + return p_drv->event(data->event, data->priority, + &p_dev->event_callback_args); return 0; } @@ -992,6 +1002,7 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) client_t *client = NULL; struct pcmcia_socket *s = NULL; struct pcmcia_device *p_dev = NULL; + struct pcmcia_driver *p_drv = NULL; /* Look for unbound client with matching dev_info */ down_read(&pcmcia_socket_list_rwsem); @@ -1006,7 +1017,6 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) continue; spin_lock_irqsave(&pcmcia_dev_list_lock, flags); list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { - struct pcmcia_driver *p_drv; p_dev = pcmcia_get_dev(p_dev); if (!p_dev) continue; @@ -1036,10 +1046,9 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) *handle = client; client->state &= ~CLIENT_UNBOUND; client->Socket = s; - client->EventMask = req->EventMask; - client->event_handler = req->event_handler; - client->event_callback_args = req->event_callback_args; - client->event_callback_args.client_handle = client; + p_dev->event_callback_args = req->event_callback_args; + p_dev->event_callback_args.client_handle = client; + if (s->state & SOCKET_CARDBUS) client->state |= CLIENT_CARDBUS; @@ -1061,12 +1070,12 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) ds_dbg(1, "register_client(): client 0x%p, dev %s\n", client, p_dev->dev.bus_id); - if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE) - EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW); if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) { - if (client->EventMask & CS_EVENT_CARD_INSERTION) - EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); + if (p_drv->event) + p_drv->event(CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW, + &p_dev->event_callback_args); + } return CS_SUCCESS; @@ -1132,7 +1141,6 @@ int pcmcia_deregister_client(client_handle_t handle) pcmcia_put_dev(p_dev); } else { handle->state = CLIENT_UNBOUND; - handle->event_handler = NULL; } return CS_SUCCESS; diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index f1f6bf596dc..3dc6957bad1 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -134,11 +134,6 @@ static dev_link_t *aha152x_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.event_handler = &aha152x_event; - client_reg.EventMask = - CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -334,6 +329,7 @@ static struct pcmcia_driver aha152x_cs_driver = { .name = "aha152x_cs", }, .attach = aha152x_attach, + .event = aha152x_event, .detach = aha152x_detach, .id_table = aha152x_ids, }; diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index 853e6ee9b71..d2281eba790 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -120,11 +120,6 @@ static dev_link_t *fdomain_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.event_handler = &fdomain_event; - client_reg.EventMask = - CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -314,6 +309,7 @@ static struct pcmcia_driver fdomain_cs_driver = { .name = "fdomain_cs", }, .attach = fdomain_attach, + .event = fdomain_event, .detach = fdomain_detach, .id_table = fdomain_ids, }; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 91b3f28e7a1..c8755adfd91 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1642,11 +1642,6 @@ static dev_link_t *nsp_cs_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME ; - client_reg.event_handler = &nsp_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -2138,12 +2133,13 @@ static struct pcmcia_device_id nsp_cs_ids[] = { MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids); static struct pcmcia_driver nsp_driver = { - .owner = THIS_MODULE, - .drv = { - .name = "nsp_cs", + .owner = THIS_MODULE, + .drv = { + .name = "nsp_cs", }, - .attach = nsp_cs_attach, - .detach = nsp_cs_detach, + .attach = nsp_cs_attach, + .event = nsp_cs_event, + .detach = nsp_cs_detach, .id_table = nsp_cs_ids, }; #endif diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index 0dcf41102ab..e6e496180d1 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -194,8 +194,6 @@ static dev_link_t *qlogic_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.event_handler = &qlogic_event; - client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -423,6 +421,7 @@ static struct pcmcia_driver qlogic_cs_driver = { .name = "qlogic_cs", }, .attach = qlogic_attach, + .event = qlogic_event, .detach = qlogic_detach, .id_table = qlogic_ids, }; diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 7d4b16b6797..b4b3a1a8a0c 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -979,10 +979,6 @@ SYM53C500_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.event_handler = &SYM53C500_event; - client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -1013,6 +1009,7 @@ static struct pcmcia_driver sym53c500_cs_driver = { .name = "sym53c500_cs", }, .attach = SYM53C500_attach, + .event = SYM53C500_event, .detach = SYM53C500_detach, .id_table = sym53c500_ids, }; diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 73a34b18866..83bfd11a1cc 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -232,11 +232,6 @@ static dev_link_t *serial_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &serial_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -883,6 +878,7 @@ static struct pcmcia_driver serial_cs_driver = { .name = "serial_cs", }, .attach = serial_attach, + .event = serial_event, .detach = serial_detach, .id_table = serial_ids, }; diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index ce5ebfe4af2..2fcb4db3abc 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c @@ -69,11 +69,6 @@ static dev_link_t *ixj_attach(void) link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &ixj_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -307,6 +302,7 @@ static struct pcmcia_driver ixj_driver = { .name = "ixj_cs", }, .attach = ixj_attach, + .event = ixj_event, .detach = ixj_detach, .id_table = ixj_ids, }; diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 269d8ef0145..55dfeec6fdb 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -389,11 +389,6 @@ static dev_link_t *sl811_cs_attach(void) dev_list = link; client_reg.dev_info = (dev_info_t *) &driver_name; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &sl811_cs_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); @@ -418,6 +413,7 @@ static struct pcmcia_driver sl811_cs_driver = { .name = (char *)driver_name, }, .attach = sl811_cs_attach, + .event = sl811_cs_event, .detach = sl811_cs_detach, .id_table = sl811_ids, }; -- cgit v1.2.3 From e12a9a93a8417c4f2aa46ce8346c2d27e656b9a2 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 7 Jul 2005 17:59:01 -0700 Subject: [PATCH] pcmcia: remove client_t usage Reduce the occurences of "client_handle_t" which is nothing else than a pointer to struct pcmcia_device by now. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/cs_internal.h | 13 ++----------- drivers/pcmcia/ds.c | 35 +++++++++++++---------------------- drivers/pcmcia/pcmcia_compat.c | 19 ++++--------------- drivers/pcmcia/pcmcia_resource.c | 31 ++++++++----------------------- 4 files changed, 27 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index e0ba4b5daa1..6bbfbd0e02a 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -99,20 +99,11 @@ static inline void cs_socket_put(struct pcmcia_socket *skt) } } -#define CHECK_HANDLE(h) \ - (((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC)) - #define CHECK_SOCKET(s) \ (((s) >= sockets) || (socket_table[s]->ops == NULL)) -#define SOCKET(h) (h->Socket) -#define CONFIG(h) (&SOCKET(h)->config[(h)->Function]) - -#define CHECK_REGION(r) \ - (((r) == NULL) || ((r)->region_magic != REGION_MAGIC)) - -#define CHECK_ERASEQ(q) \ - (((q) == NULL) || ((q)->eraseq_magic != ERASEQ_MAGIC)) +#define SOCKET(h) (h->socket) +#define CONFIG(h) (&SOCKET(h)->config[(h)->func]) /* In cardbus.c */ int cb_alloc(struct pcmcia_socket *s); diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 367ebf75bee..1cae9fda4e4 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -163,7 +163,7 @@ static int pcmcia_report_error(client_handle_t handle, error_info_t *err) int i; char *serv; - if (CHECK_HANDLE(handle)) + if (!handle) printk(KERN_NOTICE); else { struct pcmcia_device *p_dev = handle_to_pdev(handle); @@ -380,7 +380,7 @@ static int pcmcia_device_probe(struct device * dev) if (p_drv->attach) { p_dev->instance = p_drv->attach(); - if ((!p_dev->instance) || (p_dev->client.state & CLIENT_UNBOUND)) { + if ((!p_dev->instance) || (p_dev->state & CLIENT_UNBOUND)) { printk(KERN_NOTICE "ds: unable to create instance " "of '%s'!\n", p_drv->drv.name); ret = -EINVAL; @@ -520,10 +520,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); /* compat */ - p_dev->client.client_magic = CLIENT_MAGIC; - p_dev->client.Socket = s; - p_dev->client.Function = function; - p_dev->client.state = CLIENT_UNBOUND; + p_dev->state = CLIENT_UNBOUND; /* Add to the list in pcmcia_bus_socket */ spin_lock_irqsave(&pcmcia_dev_list_lock, flags); @@ -930,7 +927,7 @@ static int send_event_callback(struct device *dev, void * _data) if (!p_drv) return 0; - if (p_dev->client.state & (CLIENT_UNBOUND|CLIENT_STALE)) + if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE)) return 0; if (p_drv->event) @@ -999,7 +996,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) { - client_t *client = NULL; + struct pcmcia_device *client = NULL; struct pcmcia_socket *s = NULL; struct pcmcia_device *p_dev = NULL; struct pcmcia_driver *p_drv = NULL; @@ -1020,14 +1017,14 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) p_dev = pcmcia_get_dev(p_dev); if (!p_dev) continue; - if (!(p_dev->client.state & CLIENT_UNBOUND) || + if (!(p_dev->state & CLIENT_UNBOUND) || (!p_dev->dev.driver)) { pcmcia_put_dev(p_dev); continue; } p_drv = to_pcmcia_drv(p_dev->dev.driver); if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) { - client = &p_dev->client; + client = p_dev; spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); goto found; } @@ -1043,20 +1040,18 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */ - *handle = client; - client->state &= ~CLIENT_UNBOUND; - client->Socket = s; + *handle = p_dev; + p_dev->state &= ~CLIENT_UNBOUND; p_dev->event_callback_args = req->event_callback_args; - p_dev->event_callback_args.client_handle = client; + p_dev->event_callback_args.client_handle = p_dev; if (s->state & SOCKET_CARDBUS) client->state |= CLIENT_CARDBUS; - if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) && - (client->Function != BIND_FN_ALL)) { + if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0)) { cistpl_longlink_mfc_t mfc; - if (pccard_read_tuple(s, client->Function, CISTPL_LONGLINK_MFC, &mfc) + if (pccard_read_tuple(s, client->func, CISTPL_LONGLINK_MFC, &mfc) == CS_SUCCESS) s->functions = mfc.nfn; else @@ -1108,7 +1103,7 @@ static int unbind_request(struct pcmcia_socket *s) } p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list); list_del(&p_dev->socket_device_list); - p_dev->client.state |= CLIENT_STALE; + p_dev->state |= CLIENT_STALE; spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); device_unregister(&p_dev->dev); @@ -1123,9 +1118,6 @@ int pcmcia_deregister_client(client_handle_t handle) int i; struct pcmcia_device *p_dev = handle_to_pdev(handle); - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - s = SOCKET(handle); ds_dbg(1, "deregister_client(%p)\n", handle); @@ -1136,7 +1128,6 @@ int pcmcia_deregister_client(client_handle_t handle) goto warn_out; if (handle->state & CLIENT_STALE) { - handle->client_magic = 0; handle->state &= ~CLIENT_STALE; pcmcia_put_dev(p_dev); } else { diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c index 1cc83317e7e..916de6f85a2 100644 --- a/drivers/pcmcia/pcmcia_compat.c +++ b/drivers/pcmcia/pcmcia_compat.c @@ -31,28 +31,22 @@ int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple) { struct pcmcia_socket *s; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; s = SOCKET(handle); - return pccard_get_first_tuple(s, handle->Function, tuple); + return pccard_get_first_tuple(s, handle->func, tuple); } EXPORT_SYMBOL(pcmcia_get_first_tuple); int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple) { struct pcmcia_socket *s; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; s = SOCKET(handle); - return pccard_get_next_tuple(s, handle->Function, tuple); + return pccard_get_next_tuple(s, handle->func, tuple); } EXPORT_SYMBOL(pcmcia_get_next_tuple); int pcmcia_get_tuple_data(client_handle_t handle, tuple_t *tuple) { struct pcmcia_socket *s; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; s = SOCKET(handle); return pccard_get_tuple_data(s, tuple); } @@ -67,10 +61,8 @@ EXPORT_SYMBOL(pcmcia_parse_tuple); int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info) { struct pcmcia_socket *s; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; s = SOCKET(handle); - return pccard_validate_cis(s, handle->Function, info); + return pccard_validate_cis(s, handle->func, info); } EXPORT_SYMBOL(pcmcia_validate_cis); @@ -78,9 +70,7 @@ EXPORT_SYMBOL(pcmcia_validate_cis); int pcmcia_reset_card(client_handle_t handle, client_req_t *req) { struct pcmcia_socket *skt; - - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; + skt = SOCKET(handle); if (!skt) return CS_BAD_HANDLE; @@ -88,4 +78,3 @@ int pcmcia_reset_card(client_handle_t handle, client_req_t *req) return pccard_reset_card(skt); } EXPORT_SYMBOL(pcmcia_reset_card); - diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index c01dc6bf152..ac5c3abe70c 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -206,10 +206,8 @@ int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg) { struct pcmcia_socket *s; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; s = SOCKET(handle); - return pccard_access_configuration_register(s, handle->Function, reg); + return pccard_access_configuration_register(s, handle->func, reg); } EXPORT_SYMBOL(pcmcia_access_configuration_register); @@ -276,12 +274,12 @@ int pcmcia_get_configuration_info(client_handle_t handle, { struct pcmcia_socket *s; - if ((CHECK_HANDLE(handle)) || !config) + if (!config) return CS_BAD_HANDLE; s = SOCKET(handle); if (!s) return CS_BAD_HANDLE; - return pccard_get_configuration_info(s, handle->Function, config); + return pccard_get_configuration_info(s, handle->func, config); } EXPORT_SYMBOL(pcmcia_get_configuration_info); @@ -382,10 +380,8 @@ int pccard_get_status(struct pcmcia_socket *s, unsigned int function, int pcmcia_get_status(client_handle_t handle, cs_status_t *status) { struct pcmcia_socket *s; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; s = SOCKET(handle); - return pccard_get_status(s, handle->Function, status); + return pccard_get_status(s, handle->func, status); } EXPORT_SYMBOL(pcmcia_get_status); @@ -432,8 +428,6 @@ int pcmcia_modify_configuration(client_handle_t handle, struct pcmcia_socket *s; config_t *c; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; s = SOCKET(handle); c = CONFIG(handle); if (!(s->state & SOCKET_PRESENT)) @@ -478,8 +472,7 @@ int pcmcia_release_configuration(client_handle_t handle) struct pcmcia_socket *s; int i; - if (CHECK_HANDLE(handle) || - !(handle->state & CLIENT_CONFIG_LOCKED)) + if (!(handle->state & CLIENT_CONFIG_LOCKED)) return CS_BAD_HANDLE; handle->state &= ~CLIENT_CONFIG_LOCKED; s = SOCKET(handle); @@ -527,7 +520,7 @@ int pcmcia_release_io(client_handle_t handle, io_req_t *req) { struct pcmcia_socket *s; - if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ)) + if (!(handle->state & CLIENT_IO_REQ)) return CS_BAD_HANDLE; handle->state &= ~CLIENT_IO_REQ; s = SOCKET(handle); @@ -561,7 +554,7 @@ EXPORT_SYMBOL(pcmcia_release_io); int pcmcia_release_irq(client_handle_t handle, irq_req_t *req) { struct pcmcia_socket *s; - if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ)) + if (!(handle->state & CLIENT_IRQ_REQ)) return CS_BAD_HANDLE; handle->state &= ~CLIENT_IRQ_REQ; s = SOCKET(handle); @@ -632,8 +625,6 @@ int pcmcia_request_configuration(client_handle_t handle, config_t *c; pccard_io_map iomap; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; s = SOCKET(handle); if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; @@ -762,8 +753,6 @@ int pcmcia_request_io(client_handle_t handle, io_req_t *req) struct pcmcia_socket *s; config_t *c; - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; s = SOCKET(handle); if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; @@ -834,8 +823,6 @@ int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) int ret = CS_IN_USE, irq = 0; struct pcmcia_device *p_dev = handle_to_pdev(handle); - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; s = SOCKET(handle); if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; @@ -926,9 +913,7 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle u_long align; int w; - if (CHECK_HANDLE(*handle)) - return CS_BAD_HANDLE; - s = (*handle)->Socket; + s = (*handle)->socket; if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; if (req->Attributes & (WIN_PAGED | WIN_SHARED)) -- cgit v1.2.3 From 2bc5a9bdc56fac6f7cbf95b89443e3809141c247 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 7 Jul 2005 17:59:02 -0700 Subject: [PATCH] pcmcia: reduce client_handle_t usage Reduce the occurences of "client_handle_t" which is nothing else than a pointer to struct pcmcia_device by now. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/ds.c | 46 ++++++-------- drivers/pcmcia/pcmcia_compat.c | 36 ++++------- drivers/pcmcia/pcmcia_resource.c | 125 ++++++++++++++------------------------- 3 files changed, 72 insertions(+), 135 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 1cae9fda4e4..3e3c6f12bbe 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -158,17 +158,15 @@ static const lookup_t service_table[] = { }; -static int pcmcia_report_error(client_handle_t handle, error_info_t *err) +static int pcmcia_report_error(struct pcmcia_device *p_dev, error_info_t *err) { int i; char *serv; - if (!handle) + if (!p_dev) printk(KERN_NOTICE); - else { - struct pcmcia_device *p_dev = handle_to_pdev(handle); + else printk(KERN_NOTICE "%s: ", p_dev->dev.bus_id); - } for (i = 0; i < ARRAY_SIZE(service_table); i++) if (service_table[i].key == err->func) @@ -193,10 +191,10 @@ static int pcmcia_report_error(client_handle_t handle, error_info_t *err) /*======================================================================*/ -void cs_error(client_handle_t handle, int func, int ret) +void cs_error(struct pcmcia_device *p_dev, int func, int ret) { error_info_t err = { func, ret }; - pcmcia_report_error(handle, &err); + pcmcia_report_error(p_dev, &err); } EXPORT_SYMBOL(cs_error); @@ -574,8 +572,6 @@ static int pcmcia_card_add(struct pcmcia_socket *s) else no_funcs = 1; - /* this doesn't handle multifunction devices on one pcmcia function - * yet. */ for (i=0; i < no_funcs; i++) pcmcia_device_add(s, i); @@ -994,9 +990,8 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) -int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) +int pcmcia_register_client(struct pcmcia_device **handle, client_reg_t *req) { - struct pcmcia_device *client = NULL; struct pcmcia_socket *s = NULL; struct pcmcia_device *p_dev = NULL; struct pcmcia_driver *p_drv = NULL; @@ -1024,7 +1019,6 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) } p_drv = to_pcmcia_drv(p_dev->dev.driver); if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) { - client = p_dev; spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); goto found; } @@ -1035,7 +1029,7 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) } found: up_read(&pcmcia_socket_list_rwsem); - if (!p_dev || !client) + if (!p_dev) return -ENODEV; pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */ @@ -1046,12 +1040,9 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) p_dev->event_callback_args.client_handle = p_dev; - if (s->state & SOCKET_CARDBUS) - client->state |= CLIENT_CARDBUS; - - if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0)) { + if (!s->functions) { cistpl_longlink_mfc_t mfc; - if (pccard_read_tuple(s, client->func, CISTPL_LONGLINK_MFC, &mfc) + if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, &mfc) == CS_SUCCESS) s->functions = mfc.nfn; else @@ -1064,7 +1055,7 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) } ds_dbg(1, "register_client(): client 0x%p, dev %s\n", - client, p_dev->dev.bus_id); + p_dev, p_dev->dev.bus_id); if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) { if (p_drv->event) @@ -1112,26 +1103,25 @@ static int unbind_request(struct pcmcia_socket *s) return 0; } /* unbind_request */ -int pcmcia_deregister_client(client_handle_t handle) +int pcmcia_deregister_client(struct pcmcia_device *p_dev) { struct pcmcia_socket *s; int i; - struct pcmcia_device *p_dev = handle_to_pdev(handle); - s = SOCKET(handle); - ds_dbg(1, "deregister_client(%p)\n", handle); + s = p_dev->socket; + ds_dbg(1, "deregister_client(%p)\n", p_dev); - if (handle->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) + if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) goto warn_out; for (i = 0; i < MAX_WIN; i++) - if (handle->state & CLIENT_WIN_REQ(i)) + if (p_dev->state & CLIENT_WIN_REQ(i)) goto warn_out; - if (handle->state & CLIENT_STALE) { - handle->state &= ~CLIENT_STALE; + if (p_dev->state & CLIENT_STALE) { + p_dev->state &= ~CLIENT_STALE; pcmcia_put_dev(p_dev); } else { - handle->state = CLIENT_UNBOUND; + p_dev->state = CLIENT_UNBOUND; } return CS_SUCCESS; diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c index 916de6f85a2..962ca004ac1 100644 --- a/drivers/pcmcia/pcmcia_compat.c +++ b/drivers/pcmcia/pcmcia_compat.c @@ -28,53 +28,39 @@ #include "cs_internal.h" -int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple) +int pcmcia_get_first_tuple(struct pcmcia_device *p_dev, tuple_t *tuple) { - struct pcmcia_socket *s; - s = SOCKET(handle); - return pccard_get_first_tuple(s, handle->func, tuple); + return pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple); } EXPORT_SYMBOL(pcmcia_get_first_tuple); -int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple) +int pcmcia_get_next_tuple(struct pcmcia_device *p_dev, tuple_t *tuple) { - struct pcmcia_socket *s; - s = SOCKET(handle); - return pccard_get_next_tuple(s, handle->func, tuple); + return pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple); } EXPORT_SYMBOL(pcmcia_get_next_tuple); -int pcmcia_get_tuple_data(client_handle_t handle, tuple_t *tuple) +int pcmcia_get_tuple_data(struct pcmcia_device *p_dev, tuple_t *tuple) { - struct pcmcia_socket *s; - s = SOCKET(handle); - return pccard_get_tuple_data(s, tuple); + return pccard_get_tuple_data(p_dev->socket, tuple); } EXPORT_SYMBOL(pcmcia_get_tuple_data); -int pcmcia_parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +int pcmcia_parse_tuple(struct pcmcia_device *p_dev, tuple_t *tuple, cisparse_t *parse) { return pccard_parse_tuple(tuple, parse); } EXPORT_SYMBOL(pcmcia_parse_tuple); -int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info) +int pcmcia_validate_cis(struct pcmcia_device *p_dev, cisinfo_t *info) { - struct pcmcia_socket *s; - s = SOCKET(handle); - return pccard_validate_cis(s, handle->func, info); + return pccard_validate_cis(p_dev->socket, p_dev->func, info); } EXPORT_SYMBOL(pcmcia_validate_cis); -int pcmcia_reset_card(client_handle_t handle, client_req_t *req) +int pcmcia_reset_card(struct pcmcia_device *p_dev, client_req_t *req) { - struct pcmcia_socket *skt; - - skt = SOCKET(handle); - if (!skt) - return CS_BAD_HANDLE; - - return pccard_reset_card(skt); + return pccard_reset_card(p_dev->socket); } EXPORT_SYMBOL(pcmcia_reset_card); diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index ac5c3abe70c..ec2abb37f40 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -202,12 +202,11 @@ int pccard_access_configuration_register(struct pcmcia_socket *s, return CS_SUCCESS; } /* pccard_access_configuration_register */ -int pcmcia_access_configuration_register(client_handle_t handle, +int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg) { - struct pcmcia_socket *s; - s = SOCKET(handle); - return pccard_access_configuration_register(s, handle->func, reg); + return pccard_access_configuration_register(p_dev->socket, + p_dev->func, reg); } EXPORT_SYMBOL(pcmcia_access_configuration_register); @@ -269,17 +268,11 @@ int pccard_get_configuration_info(struct pcmcia_socket *s, return CS_SUCCESS; } /* pccard_get_configuration_info */ -int pcmcia_get_configuration_info(client_handle_t handle, +int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config) { - struct pcmcia_socket *s; - - if (!config) - return CS_BAD_HANDLE; - s = SOCKET(handle); - if (!s) - return CS_BAD_HANDLE; - return pccard_get_configuration_info(s, handle->func, config); + return pccard_get_configuration_info(p_dev->socket, p_dev->func, + config); } EXPORT_SYMBOL(pcmcia_get_configuration_info); @@ -422,14 +415,14 @@ EXPORT_SYMBOL(pcmcia_map_mem_page); * * Modify a locked socket configuration */ -int pcmcia_modify_configuration(client_handle_t handle, +int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod) { struct pcmcia_socket *s; config_t *c; - s = SOCKET(handle); - c = CONFIG(handle); + s = p_dev->socket; + c = CONFIG(p_dev); if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; if (!(c->state & CONFIG_LOCKED)) @@ -466,24 +459,18 @@ int pcmcia_modify_configuration(client_handle_t handle, EXPORT_SYMBOL(pcmcia_modify_configuration); -int pcmcia_release_configuration(client_handle_t handle) +int pcmcia_release_configuration(struct pcmcia_device *p_dev) { pccard_io_map io = { 0, 0, 0, 0, 1 }; - struct pcmcia_socket *s; + struct pcmcia_socket *s = p_dev->socket; int i; - if (!(handle->state & CLIENT_CONFIG_LOCKED)) + if (!(p_dev->state & CLIENT_CONFIG_LOCKED)) return CS_BAD_HANDLE; - handle->state &= ~CLIENT_CONFIG_LOCKED; - s = SOCKET(handle); + p_dev->state &= ~CLIENT_CONFIG_LOCKED; -#ifdef CONFIG_CARDBUS - if (handle->state & CLIENT_CARDBUS) - return CS_SUCCESS; -#endif - - if (!(handle->state & CLIENT_STALE)) { - config_t *c = CONFIG(handle); + if (!(p_dev->state & CLIENT_STALE)) { + config_t *c = CONFIG(p_dev); if (--(s->lock_count) == 0) { s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */ s->socket.Vpp = 0; @@ -516,22 +503,16 @@ EXPORT_SYMBOL(pcmcia_release_configuration); * don't bother checking the port ranges against the current socket * values. */ -int pcmcia_release_io(client_handle_t handle, io_req_t *req) +int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req) { - struct pcmcia_socket *s; + struct pcmcia_socket *s = p_dev->socket; - if (!(handle->state & CLIENT_IO_REQ)) + if (!(p_dev->state & CLIENT_IO_REQ)) return CS_BAD_HANDLE; - handle->state &= ~CLIENT_IO_REQ; - s = SOCKET(handle); - -#ifdef CONFIG_CARDBUS - if (handle->state & CLIENT_CARDBUS) - return CS_SUCCESS; -#endif + p_dev->state &= ~CLIENT_IO_REQ; - if (!(handle->state & CLIENT_STALE)) { - config_t *c = CONFIG(handle); + if (!(p_dev->state & CLIENT_STALE)) { + config_t *c = CONFIG(p_dev); if (c->state & CONFIG_LOCKED) return CS_CONFIGURATION_LOCKED; if ((c->io.BasePort1 != req->BasePort1) || @@ -551,16 +532,15 @@ int pcmcia_release_io(client_handle_t handle, io_req_t *req) EXPORT_SYMBOL(pcmcia_release_io); -int pcmcia_release_irq(client_handle_t handle, irq_req_t *req) +int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req) { - struct pcmcia_socket *s; - if (!(handle->state & CLIENT_IRQ_REQ)) + struct pcmcia_socket *s = p_dev->socket; + if (!(p_dev->state & CLIENT_IRQ_REQ)) return CS_BAD_HANDLE; - handle->state &= ~CLIENT_IRQ_REQ; - s = SOCKET(handle); + p_dev->state &= ~CLIENT_IRQ_REQ; - if (!(handle->state & CLIENT_STALE)) { - config_t *c = CONFIG(handle); + if (!(p_dev->state & CLIENT_STALE)) { + config_t *c = CONFIG(p_dev); if (c->state & CONFIG_LOCKED) return CS_CONFIGURATION_LOCKED; if (c->irq.Attributes != req->Attributes) @@ -616,27 +596,21 @@ int pcmcia_release_window(window_handle_t win) EXPORT_SYMBOL(pcmcia_release_window); -int pcmcia_request_configuration(client_handle_t handle, +int pcmcia_request_configuration(struct pcmcia_device *p_dev, config_req_t *req) { int i; u_int base; - struct pcmcia_socket *s; + struct pcmcia_socket *s = p_dev->socket; config_t *c; pccard_io_map iomap; - s = SOCKET(handle); if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; -#ifdef CONFIG_CARDBUS - if (handle->state & CLIENT_CARDBUS) - return CS_UNSUPPORTED_MODE; -#endif - if (req->IntType & INT_CARDBUS) return CS_UNSUPPORTED_MODE; - c = CONFIG(handle); + c = CONFIG(p_dev); if (c->state & CONFIG_LOCKED) return CS_CONFIGURATION_LOCKED; @@ -737,7 +711,7 @@ int pcmcia_request_configuration(client_handle_t handle, } c->state |= CONFIG_LOCKED; - handle->state |= CLIENT_CONFIG_LOCKED; + p_dev->state |= CLIENT_CONFIG_LOCKED; return CS_SUCCESS; } /* pcmcia_request_configuration */ EXPORT_SYMBOL(pcmcia_request_configuration); @@ -748,27 +722,17 @@ EXPORT_SYMBOL(pcmcia_request_configuration); * Request_io() reserves ranges of port addresses for a socket. * I have not implemented range sharing or alias addressing. */ -int pcmcia_request_io(client_handle_t handle, io_req_t *req) +int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req) { - struct pcmcia_socket *s; + struct pcmcia_socket *s = p_dev->socket; config_t *c; - s = SOCKET(handle); if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; - if (handle->state & CLIENT_CARDBUS) { -#ifdef CONFIG_CARDBUS - handle->state |= CLIENT_IO_REQ; - return CS_SUCCESS; -#else - return CS_UNSUPPORTED_FUNCTION; -#endif - } - if (!req) return CS_UNSUPPORTED_MODE; - c = CONFIG(handle); + c = CONFIG(p_dev); if (c->state & CONFIG_LOCKED) return CS_CONFIGURATION_LOCKED; if (c->state & CONFIG_IO_REQ) @@ -793,7 +757,7 @@ int pcmcia_request_io(client_handle_t handle, io_req_t *req) c->io = *req; c->state |= CONFIG_IO_REQ; - handle->state |= CLIENT_IO_REQ; + p_dev->state |= CLIENT_IO_REQ; return CS_SUCCESS; } /* pcmcia_request_io */ EXPORT_SYMBOL(pcmcia_request_io); @@ -816,17 +780,15 @@ static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs) } #endif -int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) +int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) { - struct pcmcia_socket *s; + struct pcmcia_socket *s = p_dev->socket; config_t *c; int ret = CS_IN_USE, irq = 0; - struct pcmcia_device *p_dev = handle_to_pdev(handle); - s = SOCKET(handle); if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; - c = CONFIG(handle); + c = CONFIG(p_dev); if (c->state & CONFIG_LOCKED) return CS_CONFIGURATION_LOCKED; if (c->state & CONFIG_IRQ_REQ) @@ -890,7 +852,7 @@ int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) s->irq.Config++; c->state |= CONFIG_IRQ_REQ; - handle->state |= CLIENT_IRQ_REQ; + p_dev->state |= CLIENT_IRQ_REQ; #ifdef CONFIG_PCMCIA_PROBE pcmcia_used_irq[irq]++; @@ -906,14 +868,13 @@ EXPORT_SYMBOL(pcmcia_request_irq); * Request_window() establishes a mapping between card memory space * and system memory space. */ -int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh) +int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh) { - struct pcmcia_socket *s; + struct pcmcia_socket *s = (*p_dev)->socket; window_t *win; u_long align; int w; - s = (*handle)->socket; if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; if (req->Attributes & (WIN_PAGED | WIN_SHARED)) @@ -942,7 +903,7 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle win = &s->win[w]; win->magic = WINDOW_MAGIC; win->index = w; - win->handle = *handle; + win->handle = *p_dev; win->sock = s; if (!(s->features & SS_CAP_STATIC_MAP)) { @@ -951,7 +912,7 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle if (!win->ctl.res) return CS_IN_USE; } - (*handle)->state |= CLIENT_WIN_REQ(w); + (*p_dev)->state |= CLIENT_WIN_REQ(w); /* Configure the socket controller */ win->ctl.map = w+1; -- cgit v1.2.3 From a00db1ba7c33619cbd7c3153e4746d15881c0383 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Thu, 7 Jul 2005 17:59:03 -0700 Subject: [PATCH] pcmcia: remove client services version The Linux PCMCIA code has some data that was apparently used (or meant to be used) to ensure that only proper client drivers are loaded. This is now ensured (to a certain degree) by the fact that the most client drivers are part of the kernel. Also, the version information has not been updated despite major changes in PCMCIA API. This has made it meaningless. This patch removes servinfo_t and pcmcia_get_card_services_info. They are not used in any userspace utilities such as pcmcia-cs and pcmciautils. drivers/pcmcia/pcmcia_ioctl.c is adjusted accordingly. CS_RELEASE and CS_RELEASE_CODE are removed. include/pcmcia/version.h is empty now. It will be removed later, but for now it's left in the tree to avoid touching all PCMCIA clients. The only driver that needs to be changed is drivers/scsi/pcmcia/nsp_cs.c, which uses CS_RELEASE_CODE. Signed-off-by: Pavel Roskin Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/pcmcia_ioctl.c | 26 -------------------------- drivers/scsi/pcmcia/nsp_cs.c | 4 ---- 2 files changed, 30 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index b883bc151ed..ee02224dd77 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -71,29 +71,6 @@ extern int ds_pc_debug; #define ds_dbg(lvl, fmt, arg...) do { } while (0) #endif -static const char *release = "Linux Kernel Card Services"; - -/** pcmcia_get_card_services_info - * - * Return information about this version of Card Services - */ -static int pcmcia_get_card_services_info(servinfo_t *info) -{ - unsigned int socket_count = 0; - struct list_head *tmp; - info->Signature[0] = 'C'; - info->Signature[1] = 'S'; - down_read(&pcmcia_socket_list_rwsem); - list_for_each(tmp, &pcmcia_socket_list) - socket_count++; - up_read(&pcmcia_socket_list_rwsem); - info->Count = socket_count; - info->Revision = CS_RELEASE_CODE; - info->CSLevel = 0x0210; - info->VendorString = (char *)release; - return CS_SUCCESS; -} /* get_card_services_info */ - /* backwards-compatible accessing of driver --- by name! */ @@ -591,9 +568,6 @@ static int ds_ioctl(struct inode * inode, struct file * file, case DS_ADJUST_RESOURCE_INFO: ret = pcmcia_adjust_resource_info(&buf->adjust); break; - case DS_GET_CARD_SERVICES_INFO: - ret = pcmcia_get_card_services_info(&buf->servinfo); - break; case DS_GET_CONFIGURATION_INFO: if (buf->config.Function && (buf->config.Function >= s->functions)) diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index c8755adfd91..506bbb446e5 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -2155,10 +2155,6 @@ static int __init nsp_cs_init(void) nsp_msg(KERN_INFO, "loading..."); pcmcia_get_card_services_info(&serv); - if (serv.Revision != CS_RELEASE_CODE) { - nsp_msg(KERN_DEBUG, "Card Services release does not match!"); - return -EINVAL; - } register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach); nsp_dbg(NSP_DEBUG_INIT, "out"); -- cgit v1.2.3 From 2ffe6e280f792790c39f241e7e3c5d2ef8da1b94 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Thu, 7 Jul 2005 17:59:04 -0700 Subject: [PATCH] pcmcia: remove client services version (fix) One correction is needed. Changes are not needed for drivers/scsi/pcmcia/nsp_cs.c because it uses versioning in the compatibility part, which is never used in 2.6 kernels. The only right thing we could to that compatibility code would be to remove it throughout the file, but that would be a separate patch. Cc: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/pcmcia/nsp_cs.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 506bbb446e5..c8755adfd91 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -2155,6 +2155,10 @@ static int __init nsp_cs_init(void) nsp_msg(KERN_INFO, "loading..."); pcmcia_get_card_services_info(&serv); + if (serv.Revision != CS_RELEASE_CODE) { + nsp_msg(KERN_DEBUG, "Card Services release does not match!"); + return -EINVAL; + } register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach); nsp_dbg(NSP_DEBUG_INIT, "out"); -- cgit v1.2.3 From 44670d2b50efd2443c3810239d6ea3fd02f8ef64 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 7 Jul 2005 17:59:05 -0700 Subject: [PATCH] pcmcia: remove references to pcmcia/version.h As a follow-up, remove the inclusion of pcmcia/version.h in many files. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/bluetooth/bluecard_cs.c | 1 - drivers/bluetooth/bt3c_cs.c | 1 - drivers/bluetooth/btuart_cs.c | 1 - drivers/bluetooth/dtl1_cs.c | 1 - drivers/char/pcmcia/synclink_cs.c | 1 - drivers/ide/legacy/ide-cs.c | 1 - drivers/isdn/hardware/avm/avm_cs.c | 1 - drivers/isdn/hisax/avma1_cs.c | 1 - drivers/isdn/hisax/elsa_cs.c | 1 - drivers/isdn/hisax/sedlbauer_cs.c | 1 - drivers/isdn/hisax/teles_cs.c | 1 - drivers/mtd/maps/pcmciamtd.c | 1 - drivers/net/pcmcia/3c574_cs.c | 1 - drivers/net/pcmcia/3c589_cs.c | 1 - drivers/net/pcmcia/axnet_cs.c | 1 - drivers/net/pcmcia/com20020_cs.c | 1 - drivers/net/pcmcia/fmvj18x_cs.c | 1 - drivers/net/pcmcia/ibmtr_cs.c | 1 - drivers/net/pcmcia/nmclan_cs.c | 1 - drivers/net/pcmcia/pcnet_cs.c | 1 - drivers/net/pcmcia/smc91c92_cs.c | 1 - drivers/net/pcmcia/xirc2ps_cs.c | 1 - drivers/net/wireless/airo_cs.c | 1 - drivers/net/wireless/atmel_cs.c | 1 - drivers/net/wireless/netwave_cs.c | 1 - drivers/net/wireless/orinoco_cs.c | 1 - drivers/net/wireless/ray_cs.c | 1 - drivers/net/wireless/wavelan_cs.p.h | 1 - drivers/net/wireless/wl3501_cs.c | 1 - drivers/parport/parport_cs.c | 1 - drivers/pcmcia/au1000_generic.h | 1 - drivers/pcmcia/au1000_pb1x00.c | 1 - drivers/pcmcia/au1000_xxs1500.c | 1 - drivers/pcmcia/cardbus.c | 1 - drivers/pcmcia/cs.c | 1 - drivers/pcmcia/hd64465_ss.c | 1 - drivers/pcmcia/i82365.c | 1 - drivers/pcmcia/m32r_cfc.c | 1 - drivers/pcmcia/m32r_pcc.c | 1 - drivers/pcmcia/pcmcia_compat.c | 1 - drivers/pcmcia/pcmcia_ioctl.c | 1 - drivers/pcmcia/pcmcia_resource.c | 1 - drivers/pcmcia/sa1100_generic.c | 1 - drivers/pcmcia/soc_common.h | 1 - drivers/pcmcia/socket_sysfs.c | 1 - drivers/pcmcia/tcic.c | 1 - drivers/pcmcia/yenta_socket.c | 1 - drivers/scsi/pcmcia/aha152x_stub.c | 1 - drivers/scsi/pcmcia/fdomain_stub.c | 1 - drivers/scsi/pcmcia/nsp_cs.c | 1 - drivers/scsi/pcmcia/qlogic_stub.c | 1 - drivers/serial/serial_cs.c | 1 - drivers/telephony/ixj_pcmcia.c | 1 - drivers/usb/host/sl811_cs.c | 1 - 54 files changed, 54 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 53661246100..bd2ec7e284c 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 06539a542e9..adf1750ea58 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -47,7 +47,6 @@ #include #include -#include #include #include #include diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index f15a9cf2b78..e4c59fdc0e1 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 58b09a9cc4c..e39868c3da4 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index ea691561e08..7a0c7464812 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -71,7 +71,6 @@ #include #include -#include #include #include #include diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index fde0d5f1b87..aac59751e1b 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -46,7 +46,6 @@ #include #include -#include #include #include #include diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index a30c74fd75d..db9bad2b3d1 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index d3de0e85619..0e22991635e 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index 54f0d68ad79..6fc6868de0b 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -47,7 +47,6 @@ #include #include -#include #include #include #include diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index baf733e8647..c6b5bf7d2ac 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -47,7 +47,6 @@ #include #include -#include #include #include #include diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index b8eeb789f90..0ddef1bf778 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -28,7 +28,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index aa820ee4c31..ff7c50d1018 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index c942964a49d..71fd41122c9 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -86,7 +86,6 @@ earlier 3Com products. #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 810864c6d1e..d83fdd8c194 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -40,7 +40,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 3d01079598c..8bb4e85689e 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -37,7 +37,6 @@ #include #include "../8390.h" -#include #include #include #include diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index b5119607d5a..b9355d9498a 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index c7d9bb1da41..9d8197bb293 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -49,7 +49,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 39cec4a1e4b..b6c140eb979 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -57,7 +57,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 49124dc26b3..dbb941004ae 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -146,7 +146,6 @@ Include Files #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index b22b354af5c..e1664aef3df 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -40,7 +40,6 @@ #include #include <../drivers/net/8390.h> -#include #include #include #include diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 6b5471dfb55..fbc2f58ff68 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -42,7 +42,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 03d4c0c6b3f..9f33bad174e 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -81,7 +81,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index fd46393e743..bf25584d68d 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 863be299503..ff031a3985b 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index bdd3e7083d9..5f507c49907 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -62,7 +62,6 @@ #endif /* WIRELESS_EXT > 12 */ #endif -#include #include #include #include diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index c883404b1d5..368d2f962f6 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 0643b1b94a3..0e0ba614259 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -46,7 +46,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index ea2ef8dddb9..677ff71883c 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -452,7 +452,6 @@ #include #include #include -#include /* Wavelan declarations */ #include "i82593.h" /* Definitions for the Intel chip */ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index e3aaaa5efcc..dd902126d01 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -49,7 +49,6 @@ #include -#include #include #include #include diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index ad8921a260e..24e6aacddb7 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -48,7 +48,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h index 417bc1500ba..d5122b1ea94 100644 --- a/drivers/pcmcia/au1000_generic.h +++ b/drivers/pcmcia/au1000_generic.h @@ -22,7 +22,6 @@ #define __ASM_AU1000_PCMCIA_H /* include the world */ -#include #include #include #include diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c index df19ce1ea4f..d414a3bb50b 100644 --- a/drivers/pcmcia/au1000_pb1x00.c +++ b/drivers/pcmcia/au1000_pb1x00.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c index 1dfc7765366..f113b69d699 100644 --- a/drivers/pcmcia/au1000_xxs1500.c +++ b/drivers/pcmcia/au1000_xxs1500.c @@ -38,7 +38,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 3ccb5247ec5..1d755e20880 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -31,7 +31,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index e82859d3227..4d1cc5304e1 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -33,7 +33,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index 5ab55ae0ac3..316f8bcc878 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c @@ -43,7 +43,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 3546158ef77..a713015e822 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -53,7 +53,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index b1111c6bf06..65f3ee3d4d3 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index c0997c4714f..7b14d7efd68 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c index 962ca004ac1..ebb161c4f81 100644 --- a/drivers/pcmcia/pcmcia_compat.c +++ b/drivers/pcmcia/pcmcia_compat.c @@ -18,7 +18,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index ee02224dd77..39ba6406fd5 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -31,7 +31,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index ec2abb37f40..184f4f88b2a 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -23,7 +23,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index f1bb7915302..e98bb3d80e7 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -34,7 +34,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index 700a155fbc7..6f14126889b 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -11,7 +11,6 @@ /* include the world */ #include -#include #include #include #include diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index fcef54c1c2d..1040a6c1a8a 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -29,7 +29,6 @@ #include #define IN_CARD_SERVICES -#include #include #include #include diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index aacbbb5f055..d5a61eae611 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -50,7 +50,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 02b23abc2df..1d593e1dc3d 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 3dc6957bad1..7c530649983 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -50,7 +50,6 @@ #include #include "aha152x.h" -#include #include #include #include diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index d2281eba790..db8f5cd85ff 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -47,7 +47,6 @@ #include #include "fdomain.h" -#include #include #include #include diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index c8755adfd91..3cd3b40b1a4 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -51,7 +51,6 @@ #include #include -#include #include #include #include diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index e6e496180d1..7a516f35834 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -49,7 +49,6 @@ #include #include "../qlogicfas408.h" -#include #include #include #include diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 83bfd11a1cc..de0136cc593 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -45,7 +45,6 @@ #include #include -#include #include #include #include diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index 2fcb4db3abc..57c0c6e3fbe 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c @@ -9,7 +9,6 @@ #include /* error codes */ #include -#include #include #include #include diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 55dfeec6fdb..38aebe361ca 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -20,7 +20,6 @@ #include #include -#include #include #include #include -- cgit v1.2.3 From 5bc6b68a103a6f4055890b5127ddca3a322751b0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 7 Jul 2005 17:59:07 -0700 Subject: [PATCH] yenta: no CardBus if IRQ fails If probing for the correct interrupt fails on yenta bridges, the driver falls back to polling for interrupt actions. However, CardBus cards cannot be used then. Signed-off-by: Russell King Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/cs.c | 15 +++++++++++---- drivers/pcmcia/yenta_socket.c | 10 +++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 4d1cc5304e1..e39178fc59d 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -215,6 +215,13 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) list_add_tail(&socket->socket_list, &pcmcia_socket_list); up_write(&pcmcia_socket_list_rwsem); +#ifndef CONFIG_CARDBUS + /* + * If we do not support Cardbus, ensure that + * the Cardbus socket capability is disabled. + */ + socket->features &= ~SS_CAP_CARDBUS; +#endif /* set proper values in socket->dev */ socket->dev.class_data = socket; @@ -448,11 +455,11 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) } if (status & SS_CARDBUS) { + if (!(skt->features & SS_CAP_CARDBUS)) { + cs_err(skt, "cardbus cards are not supported.\n"); + return CS_BAD_TYPE; + } skt->state |= SOCKET_CARDBUS; -#ifndef CONFIG_CARDBUS - cs_err(skt, "cardbus cards are not supported.\n"); - return CS_BAD_TYPE; -#endif } /* diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 1d593e1dc3d..0e7aa817669 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -868,14 +868,11 @@ static int yenta_probe_cb_irq(struct yenta_socket *socket) */ static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_irq_mask) { - socket->socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS; - socket->socket.map_size = 0x1000; socket->socket.pci_irq = socket->cb_irq; if (isa_probe) socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask); else socket->socket.irq_mask = 0; - socket->socket.cb_dev = socket->dev; printk(KERN_INFO "Yenta: ISA IRQ mask 0x%04x, PCI irq %d\n", socket->socket.irq_mask, socket->cb_irq); @@ -941,6 +938,9 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i socket->socket.dev.dev = &dev->dev; socket->socket.driver_data = socket; socket->socket.owner = THIS_MODULE; + socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD; + socket->socket.map_size = 0x1000; + socket->socket.cb_dev = dev; /* prepare struct yenta_socket */ socket->dev = dev; @@ -1011,6 +1011,10 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i socket->poll_timer.data = (unsigned long)socket; socket->poll_timer.expires = jiffies + HZ; add_timer(&socket->poll_timer); + printk(KERN_INFO "Yenta: no PCI IRQ, CardBus support disabled for this socket.\n" + KERN_INFO "Yenta: check your BIOS CardBus, BIOS IRQ or ACPI settings.\n"); + } else { + socket->socket.features |= SS_CAP_CARDBUS; } /* Figure out what the dang thing can do for the PCMCIA layer... */ -- cgit v1.2.3 From 89b39f5d8d701ddd93546b3d8edbefa5d568529d Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 7 Jul 2005 17:59:09 -0700 Subject: [PATCH] yenta: don't depend on CardBus As a follow-up, we can allow the yenta-driver to be limited to PCMCIA operation. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/Kconfig | 3 ++- drivers/pcmcia/ti113x.h | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index bb4dd2735d7..6485f75d2fb 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -102,7 +102,8 @@ comment "PC-card bridges" config YENTA tristate "CardBus yenta-compatible bridge support" - depends on CARDBUS + depends on PCI + select CARDBUS if !EMBEDDED select PCCARD_NONSTATIC ---help--- This option enables support for CardBus host bridges. Virtually diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index c7ba99871ac..fbe233e19ce 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h @@ -154,8 +154,6 @@ #define ENE_TEST_C9 0xc9 /* 8bit */ #define ENE_TEST_C9_TLTENABLE 0x02 -#ifdef CONFIG_CARDBUS - /* * Texas Instruments CardBus controller overrides. */ @@ -843,7 +841,5 @@ static int ti1250_override(struct yenta_socket *socket) return ti12xx_override(socket); } -#endif /* CONFIG_CARDBUS */ - #endif /* _LINUX_TI113X_H */ -- cgit v1.2.3 From 316240f66a64c95e373d52dc401d882d77a594ee Mon Sep 17 00:00:00 2001 From: Hirokazu Takata Date: Thu, 7 Jul 2005 17:59:32 -0700 Subject: [PATCH] m32r: framebuffer device support This patch is for supporting Epson s1d13xxx framebuffer device for m32r. # Sorry, a little bigger. The Epson s1d13806 is already supported by 2.6.12 kernel, and its driver is placed as drivers/video/s1d13xxxfb.c. For the m32r, a header file include/asm-m32r/s1d13806.h was prepared for several m32r target platforms. It was originally generated by an Epson tool S1D13806CFG.EXE, and modified manually for the m32r platforms. Signed-off-by: Hayato Fujiwara Signed-off-by: Hirokazu Takata Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/logo/Kconfig | 5 + drivers/video/logo/Makefile | 1 + drivers/video/logo/logo.c | 5 + drivers/video/logo/logo_m32r_clut224.ppm | 1292 ++++++++++++++++++++++++++++++ drivers/video/s1d13xxxfb.c | 10 + 5 files changed, 1313 insertions(+) create mode 100644 drivers/video/logo/logo_m32r_clut224.ppm (limited to 'drivers') diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index 6ba10e3acef..3e9ccf370ab 100644 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig @@ -63,5 +63,10 @@ config LOGO_SUPERH_CLUT224 depends on LOGO && SUPERH default y +config LOGO_M32R_CLUT224 + bool "224-color M32R Linux logo" + depends on LOGO && M32R + default y + endmenu diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile index b0d995020bd..d0244c04af5 100644 --- a/drivers/video/logo/Makefile +++ b/drivers/video/logo/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_LOGO_SUN_CLUT224) += logo_sun_clut224.o obj-$(CONFIG_LOGO_SUPERH_MONO) += logo_superh_mono.o obj-$(CONFIG_LOGO_SUPERH_VGA16) += logo_superh_vga16.o obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o +obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o # How to generate logo's diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index 77b62207500..788fa812c87 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -33,6 +33,7 @@ extern const struct linux_logo logo_sun_clut224; extern const struct linux_logo logo_superh_mono; extern const struct linux_logo logo_superh_vga16; extern const struct linux_logo logo_superh_clut224; +extern const struct linux_logo logo_m32r_clut224; const struct linux_logo *fb_find_logo(int depth) @@ -96,6 +97,10 @@ const struct linux_logo *fb_find_logo(int depth) #ifdef CONFIG_LOGO_SUPERH_CLUT224 /* SuperH Linux logo */ logo = &logo_superh_clut224; +#endif +#ifdef CONFIG_LOGO_M32R_CLUT224 + /* M32R Linux logo */ + logo = &logo_m32r_clut224; #endif } return logo; diff --git a/drivers/video/logo/logo_m32r_clut224.ppm b/drivers/video/logo/logo_m32r_clut224.ppm new file mode 100644 index 00000000000..8b2983c5a0b --- /dev/null +++ b/drivers/video/logo/logo_m32r_clut224.ppm @@ -0,0 +1,1292 @@ +P3 +# CREATOR: The GIMP's PNM Filter Version 1.0 +# +# Note: how to convert ppm to pnm(ascii). +# $ convert -posterize 224 m32r.ppm - | pnm2asc -f5 >logo_m32r_clut224.ppm +# +# convert - imagemagick: /usr/bin/convert +# pnm2asc - pnm to ascii-pnm format converter +# http://www.is.aist.go.jp/etlcdb/util/p2a.htm#English + +80 80 +255 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 43 43 43 75 75 75 27 27 27 2 2 3 + 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 59 59 59 123 123 123 67 67 67 27 27 27 + 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 10 6 3 59 59 59 80 80 80 43 43 43 27 27 27 + 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 19 19 19 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 2 2 3 10 6 3 10 6 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 10 6 3 11 11 11 11 11 11 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 2 2 3 2 2 3 27 27 27 10 6 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 19 19 19 2 2 3 2 2 3 51 51 51 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 123 123 123 196 196 196 115 115 115 2 2 3 + 2 2 3 2 2 3 2 2 3 75 75 75 141 141 140 + 172 172 172 196 196 196 190 189 188 2 2 3 11 11 11 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 27 27 27 164 164 164 228 228 228 221 221 220 10 6 3 + 2 2 3 2 2 3 2 2 3 172 172 172 245 245 245 + 254 254 252 254 254 252 221 221 220 35 35 35 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 164 164 164 228 228 228 35 35 35 236 236 236 236 236 236 + 2 2 3 11 11 11 2 2 3 254 254 252 245 245 245 + 2 2 3 75 75 75 245 245 245 245 245 245 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 212 212 212 2 2 3 51 51 51 11 11 11 245 245 245 + 27 27 27 80 80 80 10 6 3 254 254 252 2 2 3 + 2 2 3 91 91 91 19 19 19 254 254 252 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 196 196 196 10 6 3 2 2 3 11 11 11 107 107 107 + 49 35 5 57 42 11 31 22 3 236 236 236 2 2 3 + 2 2 3 2 2 3 2 2 3 254 254 252 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 107 107 107 221 221 220 2 2 3 64 43 7 194 148 10 + 236 188 10 225 180 10 170 126 10 236 188 10 94 86 67 + 2 2 3 2 2 3 204 204 204 236 236 236 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 228 228 228 182 126 10 218 164 9 236 188 10 + 236 188 10 237 204 14 236 205 40 246 214 48 246 214 48 + 245 189 11 209 156 9 196 196 196 11 11 11 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 165 114 10 207 148 7 229 172 9 236 180 10 + 236 196 11 237 204 14 242 218 43 246 218 75 246 218 19 + 246 213 13 246 218 19 244 205 11 218 164 9 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 164 109 5 192 133 7 224 165 9 236 180 10 236 188 10 + 236 196 11 241 212 42 246 218 75 246 218 19 246 218 19 + 246 218 19 236 196 11 150 114 10 229 172 9 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 165 114 10 201 142 7 229 172 9 242 182 11 236 188 10 + 237 204 14 245 213 67 246 218 19 246 213 13 246 213 13 + 154 119 10 207 148 7 218 164 9 216 156 8 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 120 78 3 225 180 10 245 189 11 236 205 40 + 241 212 42 241 212 17 237 204 14 148 107 9 182 126 10 + 216 156 8 218 164 9 207 148 7 82 70 43 2 2 3 + 2 2 3 123 123 123 35 35 35 2 2 3 2 2 3 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 10 6 3 180 180 180 156 102 5 135 88 5 142 106 7 + 126 98 11 165 114 10 185 132 9 207 148 7 215 150 13 + 199 140 8 188 148 71 196 196 196 190 189 188 2 2 3 + 2 2 3 11 11 11 132 132 132 75 75 75 2 2 3 + 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 10 6 3 190 189 188 190 189 188 151 97 5 192 133 7 + 207 148 7 206 142 8 199 140 8 180 121 7 180 132 31 + 190 189 188 190 189 188 212 212 212 212 212 212 107 107 107 + 2 2 3 2 2 3 99 99 99 51 51 51 2 2 3 + 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 190 189 188 190 189 188 190 189 188 136 95 7 + 151 97 5 151 97 5 151 97 5 183 156 91 190 189 188 + 190 189 188 228 228 228 254 254 252 254 254 252 221 221 220 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 10 6 3 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3 + 75 75 75 245 245 245 196 196 196 190 189 188 190 189 188 + 190 189 188 196 196 196 190 189 188 190 189 188 204 204 204 + 236 236 236 254 254 252 254 254 252 254 254 252 254 254 252 + 35 35 35 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 2 2 3 27 27 27 2 2 3 + 245 245 245 254 254 252 245 245 245 190 189 188 190 189 188 + 190 189 188 190 189 188 190 189 188 212 212 212 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 10 6 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 2 2 3 2 2 3 132 132 132 + 254 254 252 254 254 252 254 254 252 236 236 236 196 196 196 + 190 189 188 204 204 204 245 245 245 245 245 245 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 80 80 80 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 2 2 3 2 2 3 2 2 3 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245 + 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 2 2 3 2 2 3 2 2 3 212 212 212 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 2 2 3 2 2 3 204 204 204 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 245 245 245 236 236 236 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3 + 2 2 3 2 2 3 11 11 11 164 164 164 212 212 212 + 236 236 236 245 245 245 254 254 252 236 236 236 221 221 220 + 221 221 220 228 228 228 245 245 245 245 245 245 245 245 245 + 236 236 236 221 221 220 212 212 212 204 204 204 204 204 204 + 196 196 196 204 204 204 59 59 59 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3 + 2 2 3 2 2 3 27 27 27 172 172 172 212 212 212 + 236 236 236 254 254 252 254 254 252 254 254 252 228 228 228 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 245 245 245 221 221 220 204 204 204 196 196 196 + 196 196 196 196 196 196 228 228 228 19 19 19 2 2 3 + 80 80 80 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 2 2 3 2 2 3 2 2 3 + 11 11 11 2 2 3 164 164 164 236 236 236 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 236 236 236 212 212 212 196 196 196 245 245 245 2 2 3 + 2 2 3 11 11 11 51 51 51 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 2 2 3 2 2 3 86 86 83 + 2 2 3 27 27 27 236 236 236 254 254 252 254 254 252 + 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 212 212 212 196 196 196 91 91 91 + 2 2 3 2 2 3 2 2 3 11 11 11 2 2 3 + 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 2 2 3 2 2 3 2 2 3 + 2 2 3 245 245 245 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245 + 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252 + 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 221 221 220 245 245 245 + 2 2 3 11 11 11 43 43 43 19 19 19 10 6 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 2 2 3 80 80 80 2 2 3 + 2 2 3 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 43 43 43 27 27 27 80 80 80 19 19 19 80 80 80 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 2 2 3 2 2 3 2 2 3 2 2 3 + 245 245 245 254 254 252 254 254 252 17 11 233 254 254 252 + 254 254 252 254 254 252 254 254 252 236 236 236 17 11 233 + 17 11 233 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 11 11 11 11 11 11 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 2 2 3 67 67 67 2 2 3 19 19 19 + 254 254 252 254 254 252 245 245 245 17 11 233 245 245 245 + 254 254 252 254 254 252 17 11 233 228 228 228 17 11 233 + 17 11 233 17 11 233 17 11 233 254 254 252 17 11 233 + 17 11 233 254 254 252 254 254 252 17 11 233 17 11 233 + 17 11 233 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3 + 11 11 11 2 2 3 2 2 3 2 2 3 2 2 3 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 2 2 3 10 6 3 11 11 11 2 2 3 228 228 228 + 254 254 252 254 254 252 254 254 252 17 11 233 254 254 252 + 254 254 252 17 11 233 17 11 233 17 11 233 245 245 245 + 254 254 252 254 254 252 17 11 233 17 11 233 17 11 233 + 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233 + 17 11 233 17 11 233 254 254 252 254 254 252 254 254 252 + 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3 + 27 27 27 2 2 3 2 2 3 2 2 3 2 2 3 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 2 2 3 2 2 3 2 2 3 2 2 3 254 254 252 + 254 254 252 254 254 252 254 254 252 17 11 233 17 11 233 + 17 11 233 17 11 233 17 11 233 17 11 233 254 254 252 + 17 11 233 17 11 233 17 11 233 254 254 252 254 254 252 + 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233 + 254 254 252 17 11 233 254 254 252 254 254 252 254 254 252 + 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3 + 11 11 11 2 2 3 2 2 3 2 2 3 2 2 3 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 19 19 19 2 2 3 2 2 3 254 254 252 + 254 254 252 254 254 252 17 11 233 245 245 245 17 11 233 + 17 11 233 245 245 245 254 254 252 17 11 233 254 254 252 + 17 11 233 17 11 233 17 11 233 254 254 252 254 254 252 + 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233 + 17 11 233 17 11 233 254 254 252 254 254 252 254 254 252 + 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3 + 2 2 3 19 19 19 2 2 3 19 19 19 254 254 252 + 254 254 252 245 245 245 17 11 233 254 254 252 17 11 233 + 17 11 233 254 254 252 254 254 252 17 11 233 254 254 252 + 254 254 252 254 254 252 17 11 233 17 11 233 254 254 252 + 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233 + 17 11 233 17 11 233 17 11 233 254 254 252 254 254 252 + 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3 + 2 2 3 43 43 43 2 2 3 43 43 43 254 254 252 + 245 245 245 254 254 252 17 11 233 254 254 252 17 11 233 + 254 254 252 254 254 252 254 254 252 17 11 233 17 11 233 + 17 11 233 17 11 233 17 11 233 254 254 252 17 11 233 + 17 11 233 17 11 233 17 11 233 17 11 233 17 11 233 + 245 245 245 254 254 252 17 11 233 254 254 252 254 254 252 + 245 245 245 2 2 3 2 2 3 2 2 3 11 11 11 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3 + 2 2 3 75 75 75 2 2 3 99 99 99 254 254 252 + 254 254 252 254 254 252 17 11 233 254 254 252 254 254 252 + 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252 + 254 254 252 17 11 233 245 245 245 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 17 11 233 17 11 233 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 2 2 3 2 2 3 2 2 3 75 75 75 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3 + 2 2 3 2 2 3 11 11 11 107 107 107 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 245 245 245 254 254 252 245 245 245 236 236 236 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 2 2 3 2 2 3 11 11 11 19 19 19 + 11 11 11 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 2 2 3 11 11 11 + 140 102 3 11 11 11 10 6 3 67 67 67 254 254 252 + 245 245 245 245 245 245 254 254 252 254 254 252 245 245 245 + 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 245 245 245 254 254 252 254 254 252 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 2 2 3 43 43 43 2 2 3 2 2 3 + 2 2 3 11 11 11 67 67 67 11 11 11 2 2 3 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 185 132 9 242 182 11 + 245 189 11 245 189 11 49 35 5 2 2 3 228 228 228 + 254 254 252 254 254 252 254 254 252 245 245 245 254 254 252 + 254 254 252 254 254 252 254 254 252 228 228 228 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 245 238 222 232 189 94 + 226 186 99 43 43 43 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 59 59 59 2 2 3 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 216 156 8 236 180 22 + 245 189 11 245 189 11 245 189 11 49 35 5 11 11 11 + 212 212 212 245 245 245 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252 + 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 245 245 245 254 254 252 254 254 252 229 172 9 246 218 19 + 246 218 19 41 27 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 19 19 19 27 27 27 196 154 14 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 199 140 8 229 172 9 242 182 11 + 245 189 11 245 189 11 245 189 11 244 196 10 2 2 3 + 2 2 3 115 115 115 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252 + 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 224 165 9 245 189 11 + 236 196 11 19 19 19 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 11 11 11 236 196 11 + 244 205 11 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 182 126 10 209 156 9 215 150 13 + 193 140 10 207 148 24 216 156 8 242 182 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 209 156 9 + 2 2 3 2 2 3 43 43 43 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 236 236 236 216 156 8 245 189 11 + 229 172 9 64 43 7 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 207 148 7 236 188 10 + 245 189 11 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 180 121 7 216 156 8 242 182 11 236 180 10 + 229 172 9 242 182 11 242 182 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 237 204 14 + 170 126 10 2 2 3 2 2 3 11 11 11 236 236 236 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 204 204 204 196 196 196 216 156 8 236 180 10 + 224 165 9 182 126 10 73 48 6 2 2 3 2 2 3 + 2 2 3 41 27 3 199 140 8 229 172 9 236 180 10 + 245 189 11 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 185 132 9 229 172 9 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 226 188 11 2 2 3 2 2 3 2 2 3 11 11 11 + 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 196 196 196 196 196 196 215 150 13 236 180 10 + 229 172 9 201 142 7 185 132 9 180 121 7 173 120 10 + 180 121 7 192 133 7 229 172 9 242 182 11 245 189 11 + 245 189 11 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 180 126 47 224 165 9 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 236 188 10 193 140 10 2 2 3 2 2 3 2 2 3 + 2 2 3 212 212 212 254 254 252 245 245 245 245 245 245 + 254 254 252 254 254 252 254 254 252 245 245 245 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 204 204 204 196 196 196 199 140 8 229 172 9 + 236 180 10 218 164 9 215 150 13 207 148 7 207 148 7 + 216 156 8 229 172 9 245 189 11 245 189 11 245 189 11 + 245 189 11 242 182 11 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 185 132 9 216 156 8 242 182 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 236 196 11 19 19 19 2 2 3 2 2 3 + 2 2 3 11 11 11 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 245 245 245 254 254 252 254 254 252 + 245 245 245 221 221 220 196 196 196 185 132 9 229 172 9 + 242 182 11 229 172 9 224 165 9 218 164 9 224 165 9 + 229 172 9 236 180 10 245 189 11 245 189 11 245 189 11 + 245 189 11 236 180 22 242 182 11 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 236 180 22 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 236 188 10 225 180 10 2 2 3 2 2 3 + 2 2 3 11 11 11 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 221 221 220 19 19 19 185 132 9 224 165 9 + 245 189 11 245 189 11 242 182 11 236 180 10 236 180 10 + 242 182 11 242 182 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 196 154 14 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 207 148 7 236 180 22 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 242 182 11 + 245 189 11 245 189 11 237 204 14 135 88 5 2 2 3 + 27 27 27 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 245 245 245 254 254 252 254 254 252 245 245 245 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 67 67 67 19 13 3 185 132 9 229 172 9 + 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 236 180 22 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 245 189 11 242 182 11 + 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 236 188 10 226 188 11 104 83 48 + 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245 + 254 254 252 254 254 252 245 245 245 254 254 252 245 245 245 + 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252 + 2 2 3 2 2 3 56 38 5 185 132 9 229 172 9 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 242 182 11 + 229 172 9 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 182 126 10 215 150 13 242 182 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 242 182 11 245 189 11 236 196 11 216 156 8 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 245 245 245 2 2 3 + 2 2 3 2 2 3 75 54 3 182 126 10 229 172 9 + 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 229 172 9 + 207 148 24 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 192 133 7 229 172 9 242 182 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 242 182 11 225 180 10 224 165 9 + 107 69 5 245 245 245 254 254 252 254 254 252 254 254 252 + 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252 + 254 254 252 236 236 236 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 91 67 9 182 126 10 229 172 9 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 242 182 11 242 182 11 216 156 8 180 126 47 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 206 142 8 224 165 9 245 189 11 242 182 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 242 182 11 + 245 189 11 245 189 11 242 182 11 242 182 11 216 156 8 + 156 102 5 19 13 3 43 43 43 196 196 196 254 254 252 + 245 245 245 254 254 252 254 254 252 204 204 204 51 51 51 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 95 62 5 185 132 9 229 172 9 + 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 242 182 11 245 189 11 245 189 11 + 236 180 22 216 156 8 206 142 8 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 192 133 7 215 150 13 229 172 9 229 172 9 + 236 180 10 236 180 22 242 182 11 242 182 11 245 189 11 + 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 245 189 11 245 189 11 229 172 9 216 156 8 + 156 102 5 83 54 6 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 115 73 3 185 132 9 229 172 9 + 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11 + 245 189 11 242 182 11 229 172 9 229 172 9 216 156 8 + 180 121 7 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 180 121 7 182 126 10 192 133 7 199 140 8 + 207 148 7 215 150 13 216 156 8 224 165 9 229 172 9 + 236 180 22 245 189 11 242 182 11 245 189 11 242 182 11 + 245 189 11 245 189 11 242 182 11 229 172 9 199 140 8 + 151 97 5 101 67 7 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 115 73 3 180 121 7 216 156 8 + 236 180 22 242 182 11 245 189 11 245 189 11 242 182 11 + 236 180 10 224 165 9 215 150 13 206 142 8 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 156 102 5 164 109 5 172 114 5 180 121 7 180 121 7 + 192 133 7 201 142 7 216 156 8 224 165 9 236 180 22 + 245 189 11 242 182 11 229 172 9 201 142 7 172 114 5 + 125 83 5 83 54 6 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3 + 2 2 3 2 2 3 91 58 5 156 102 5 192 133 7 + 216 156 8 229 172 9 236 180 10 236 180 10 229 172 9 + 215 150 13 199 140 8 164 109 5 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 120 78 3 132 82 3 + 151 97 5 157 106 7 180 121 7 185 132 9 193 140 10 + 207 148 7 207 148 7 192 133 7 172 114 5 132 82 3 + 101 67 7 41 27 3 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 73 48 6 143 90 3 180 121 7 + 192 133 7 207 148 7 207 148 7 201 142 7 185 132 9 + 173 120 10 136 95 7 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 91 58 5 125 83 5 135 88 5 + 144 95 7 151 97 5 132 82 3 115 73 3 95 62 5 + 64 43 7 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 64 43 7 91 58 5 151 97 5 + 157 106 7 172 114 5 172 114 5 164 109 5 151 97 5 + 85 59 6 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 73 48 6 + 91 58 5 95 62 5 95 62 5 91 58 5 56 38 5 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 83 54 6 + 107 69 5 132 82 3 125 83 5 101 67 7 71 47 31 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 + 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13 diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c index 789de13f461..3848be2b9d2 100644 --- a/drivers/video/s1d13xxxfb.c +++ b/drivers/video/s1d13xxxfb.c @@ -67,12 +67,18 @@ static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = { static inline u8 s1d13xxxfb_readreg(struct s1d13xxxfb_par *par, u16 regno) { +#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3) + regno=((regno & 1) ? (regno & ~1L) : (regno + 1)); +#endif return readb(par->regs + regno); } static inline void s1d13xxxfb_writereg(struct s1d13xxxfb_par *par, u16 regno, u8 value) { +#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3) + regno=((regno & 1) ? (regno & ~1L) : (regno + 1)); +#endif writeb(value, par->regs + regno); } @@ -259,7 +265,11 @@ s1d13xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, dbg("s1d13xxxfb_setcolreg: pseudo %d, val %08x\n", regno, pseudo_val); +#if defined(CONFIG_PLAT_MAPPI) + ((u32 *)info->pseudo_palette)[regno] = cpu_to_le16(pseudo_val); +#else ((u32 *)info->pseudo_palette)[regno] = pseudo_val; +#endif break; case FB_VISUAL_PSEUDOCOLOR: -- cgit v1.2.3 From d88854f08961d26f3a63cfae7972188d26a128e4 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Thu, 7 Jul 2005 17:59:34 -0700 Subject: [PATCH] device-mapper: dm-raid1: Limit bios to size of mirror region Set the target's split_io field when building a dm-mirror device so incoming bios won't span the mirror's internal regions. Without this, regions can be accessed while not holding correct locks and data corruption is possible. Reported-By: "Zhao Qian" From: Kevin Corry Signed-Off-By: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-raid1.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 6e3cf7e1345..12031c9d3f1 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1060,6 +1060,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) } ti->private = ms; + ti->split_io = ms->rh.region_size; r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client); if (r) { -- cgit v1.2.3 From b03efcfb2180289718991bb984044ce6c5b7d1b0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 8 Jul 2005 14:57:23 -0700 Subject: [NET]: Transform skb_queue_len() binary tests into skb_queue_empty() This is part of the grand scheme to eliminate the qlen member of skb_queue_head, and subsequently remove the 'list' member of sk_buff. Most users of skb_queue_len() want to know if the queue is empty or not, and that's trivially done with skb_queue_empty() which doesn't use the skb_queue_head->qlen member and instead uses the queue list emptyness as the test. Signed-off-by: David S. Miller --- drivers/bluetooth/hci_vhci.c | 2 +- drivers/isdn/hisax/isdnl1.c | 3 ++- drivers/isdn/hisax/isdnl2.c | 17 +++++++++-------- drivers/isdn/hisax/isdnl3.c | 2 +- drivers/isdn/i4l/isdn_tty.c | 4 ++-- drivers/isdn/icn/icn.c | 4 ++-- drivers/net/hamradio/scc.c | 5 ++--- drivers/net/ppp_async.c | 2 +- drivers/net/ppp_generic.c | 12 ++++++------ drivers/net/ppp_synctty.c | 2 +- drivers/net/tun.c | 2 +- drivers/net/wireless/airo.c | 4 ++-- drivers/s390/net/claw.c | 4 ++-- drivers/s390/net/ctctty.c | 6 +++--- drivers/usb/net/usbnet.c | 6 +++--- 15 files changed, 38 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 3256192dcde..f9b956fb2b8 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -120,7 +120,7 @@ static unsigned int hci_vhci_chr_poll(struct file *file, poll_table * wait) poll_wait(file, &hci_vhci->read_wait, wait); - if (skb_queue_len(&hci_vhci->readq)) + if (!skb_queue_empty(&hci_vhci->readq)) return POLLIN | POLLRDNORM; return POLLOUT | POLLWRNORM; diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index ac899503a74..bab35688648 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -279,7 +279,8 @@ BChannel_proc_xmt(struct BCState *bcs) if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) { - if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) { + if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && + skb_queue_empty(&bcs->squeue)) { st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); } } diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index 9022583fd6a..1615c1a76ab 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c @@ -108,7 +108,8 @@ static int l2addrsize(struct Layer2 *l2); static void set_peer_busy(struct Layer2 *l2) { test_and_set_bit(FLG_PEER_BUSY, &l2->flag); - if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue)) + if (!skb_queue_empty(&l2->i_queue) || + !skb_queue_empty(&l2->ui_queue)) test_and_set_bit(FLG_L2BLOCK, &l2->flag); } @@ -754,7 +755,7 @@ l2_restart_multi(struct FsmInst *fi, int event, void *arg) st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL); if ((ST_L2_7==state) || (ST_L2_8 == state)) - if (skb_queue_len(&st->l2.i_queue) && cansend(st)) + if (!skb_queue_empty(&st->l2.i_queue) && cansend(st)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } @@ -810,7 +811,7 @@ l2_connected(struct FsmInst *fi, int event, void *arg) if (pr != -1) st->l2.l2l3(st, pr, NULL); - if (skb_queue_len(&st->l2.i_queue) && cansend(st)) + if (!skb_queue_empty(&st->l2.i_queue) && cansend(st)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } @@ -1014,7 +1015,7 @@ l2_st7_got_super(struct FsmInst *fi, int event, void *arg) if(typ != RR) FsmDelTimer(&st->l2.t203, 9); restart_t200(st, 12); } - if (skb_queue_len(&st->l2.i_queue) && (typ == RR)) + if (!skb_queue_empty(&st->l2.i_queue) && (typ == RR)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } else nrerrorrecovery(fi); @@ -1120,7 +1121,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg) return; } - if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7)) + if (!skb_queue_empty(&st->l2.i_queue) && (fi->state == ST_L2_7)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag)) enquiry_cr(st, RR, RSP, 0); @@ -1138,7 +1139,7 @@ l2_got_tei(struct FsmInst *fi, int event, void *arg) test_and_set_bit(FLG_L3_INIT, &st->l2.flag); } else FsmChangeState(fi, ST_L2_4); - if (skb_queue_len(&st->l2.ui_queue)) + if (!skb_queue_empty(&st->l2.ui_queue)) tx_ui(st); } @@ -1301,7 +1302,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) FsmDelTimer(&st->l2.t203, 13); FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11); } - if (skb_queue_len(&l2->i_queue) && cansend(st)) + if (!skb_queue_empty(&l2->i_queue) && cansend(st)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } @@ -1347,7 +1348,7 @@ l2_st8_got_super(struct FsmInst *fi, int event, void *arg) } invoke_retransmission(st, nr); FsmChangeState(fi, ST_L2_7); - if (skb_queue_len(&l2->i_queue) && cansend(st)) + if (!skb_queue_empty(&l2->i_queue) && cansend(st)) st->l2.l2l1(st, PH_PULL | REQUEST, NULL); } else nrerrorrecovery(fi); diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c index abcc9530eb3..c9917cd2132 100644 --- a/drivers/isdn/hisax/isdnl3.c +++ b/drivers/isdn/hisax/isdnl3.c @@ -302,7 +302,7 @@ release_l3_process(struct l3_process *p) !test_bit(FLG_PTP, &p->st->l2.flag)) { if (p->debug) l3_debug(p->st, "release_l3_process: last process"); - if (!skb_queue_len(&p->st->l3.squeue)) { + if (skb_queue_empty(&p->st->l3.squeue)) { if (p->debug) l3_debug(p->st, "release_l3_process: release link"); if (p->st->protocol != ISDN_PTYPE_NI1) diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index ad5aa38fb5a..b37ef1f06b3 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1223,7 +1223,7 @@ isdn_tty_write(struct tty_struct *tty, const u_char * buf, int count) total += c; } atomic_dec(&info->xmit_lock); - if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) { + if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) { if (m->mdmreg[REG_DXMT] & BIT_DXMT) { isdn_tty_senddown(info); isdn_tty_tint(info); @@ -1284,7 +1284,7 @@ isdn_tty_flush_chars(struct tty_struct *tty) if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars")) return; - if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) + if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); } diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 9fc0c1e0373..e0d1b01cc74 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -304,12 +304,12 @@ icn_pollbchan_send(int channel, icn_card * card) isdn_ctrl cmd; if (!(card->sndcount[channel] || card->xskb[channel] || - skb_queue_len(&card->spqueue[channel]))) + !skb_queue_empty(&card->spqueue[channel]))) return; if (icn_trymaplock_channel(card, mch)) { while (sbfree && (card->sndcount[channel] || - skb_queue_len(&card->spqueue[channel]) || + !skb_queue_empty(&card->spqueue[channel]) || card->xskb[channel])) { spin_lock_irqsave(&card->lock, flags); if (card->xmit_lock[channel]) { diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index ece1b1a1318..c27e417f32b 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -304,7 +304,7 @@ static inline void scc_discard_buffers(struct scc_channel *scc) scc->tx_buff = NULL; } - while (skb_queue_len(&scc->tx_queue)) + while (!skb_queue_empty(&scc->tx_queue)) dev_kfree_skb(skb_dequeue(&scc->tx_queue)); spin_unlock_irqrestore(&scc->lock, flags); @@ -1126,8 +1126,7 @@ static void t_dwait(unsigned long channel) if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */ { - if (skb_queue_len(&scc->tx_queue) == 0) /* nothing to send */ - { + if (skb_queue_empty(&scc->tx_queue)) { /* nothing to send */ scc->stat.tx_state = TXS_IDLE; netif_wake_queue(scc->dev); /* t_maxkeyup locked it. */ return; diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index 5e48b9ab304..59e8183c639 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -364,7 +364,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, spin_lock_irqsave(&ap->recv_lock, flags); ppp_async_input(ap, buf, cflags, count); spin_unlock_irqrestore(&ap->recv_lock, flags); - if (skb_queue_len(&ap->rqueue)) + if (!skb_queue_empty(&ap->rqueue)) tasklet_schedule(&ap->tsk); ap_put(ap); if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index ab726ab4379..a32668e88e0 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1237,8 +1237,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) pch = list_entry(list, struct channel, clist); navail += pch->avail = (pch->chan != NULL); if (pch->avail) { - if (skb_queue_len(&pch->file.xq) == 0 - || !pch->had_frag) { + if (skb_queue_empty(&pch->file.xq) || + !pch->had_frag) { pch->avail = 2; ++nfree; } @@ -1374,8 +1374,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) /* try to send it down the channel */ chan = pch->chan; - if (skb_queue_len(&pch->file.xq) - || !chan->ops->start_xmit(chan, frag)) + if (!skb_queue_empty(&pch->file.xq) || + !chan->ops->start_xmit(chan, frag)) skb_queue_tail(&pch->file.xq, frag); pch->had_frag = 1; p += flen; @@ -1412,7 +1412,7 @@ ppp_channel_push(struct channel *pch) spin_lock_bh(&pch->downl); if (pch->chan != 0) { - while (skb_queue_len(&pch->file.xq) > 0) { + while (!skb_queue_empty(&pch->file.xq)) { skb = skb_dequeue(&pch->file.xq); if (!pch->chan->ops->start_xmit(pch->chan, skb)) { /* put the packet back and try again later */ @@ -1426,7 +1426,7 @@ ppp_channel_push(struct channel *pch) } spin_unlock_bh(&pch->downl); /* see if there is anything from the attached unit to be sent */ - if (skb_queue_len(&pch->file.xq) == 0) { + if (skb_queue_empty(&pch->file.xq)) { read_lock_bh(&pch->upl); ppp = pch->ppp; if (ppp != 0) diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index fd9f5018035..4d51c0c8023 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -406,7 +406,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf, spin_lock_irqsave(&ap->recv_lock, flags); ppp_sync_input(ap, buf, cflags, count); spin_unlock_irqrestore(&ap->recv_lock, flags); - if (skb_queue_len(&ap->rqueue)) + if (!skb_queue_empty(&ap->rqueue)) tasklet_schedule(&ap->tsk); sp_put(ap); if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 7bfee366297..effab0b9adc 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -215,7 +215,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) poll_wait(file, &tun->read_wait, wait); - if (skb_queue_len(&tun->readq)) + if (!skb_queue_empty(&tun->readq)) mask |= POLLIN | POLLRDNORM; return mask; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index c12648d8192..47f3c5d0203 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2374,7 +2374,7 @@ void stop_airo_card( struct net_device *dev, int freeres ) /* * Clean out tx queue */ - if (test_bit(FLAG_MPI, &ai->flags) && skb_queue_len (&ai->txq) > 0) { + if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) { struct sk_buff *skb = NULL; for (;(skb = skb_dequeue(&ai->txq));) dev_kfree_skb(skb); @@ -3287,7 +3287,7 @@ exitrx: if (status & EV_TXEXC) get_tx_error(apriv, -1); spin_lock_irqsave(&apriv->aux_lock, flags); - if (skb_queue_len (&apriv->txq)) { + if (!skb_queue_empty(&apriv->txq)) { spin_unlock_irqrestore(&apriv->aux_lock,flags); mpi_send_packet (dev); } else { diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 60440dbe3a2..24c0af49c25 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -428,7 +428,7 @@ claw_pack_skb(struct claw_privbk *privptr) new_skb = NULL; /* assume no dice */ pkt_cnt = 0; CLAW_DBF_TEXT(4,trace,"PackSKBe"); - if (skb_queue_len(&p_ch->collect_queue) > 0) { + if (!skb_queue_empty(&p_ch->collect_queue)) { /* some data */ held_skb = skb_dequeue(&p_ch->collect_queue); if (p_env->packing != DO_PACKED) @@ -1254,7 +1254,7 @@ claw_write_next ( struct chbk * p_ch ) privptr = (struct claw_privbk *) dev->priv; claw_free_wrt_buf( dev ); if ((privptr->write_free_count > 0) && - (skb_queue_len(&p_ch->collect_queue) > 0)) { + !skb_queue_empty(&p_ch->collect_queue)) { pk_skb = claw_pack_skb(privptr); while (pk_skb != NULL) { rc = claw_hw_tx( pk_skb, dev,1); diff --git a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c index 3080393e823..968f2c113ef 100644 --- a/drivers/s390/net/ctctty.c +++ b/drivers/s390/net/ctctty.c @@ -156,7 +156,7 @@ ctc_tty_readmodem(ctc_tty_info *info) skb_queue_head(&info->rx_queue, skb); else { kfree_skb(skb); - ret = skb_queue_len(&info->rx_queue); + ret = !skb_queue_empty(&info->rx_queue); } } } @@ -530,7 +530,7 @@ ctc_tty_write(struct tty_struct *tty, const u_char * buf, int count) total += c; count -= c; } - if (skb_queue_len(&info->tx_queue)) { + if (!skb_queue_empty(&info->tx_queue)) { info->lsr &= ~UART_LSR_TEMT; tasklet_schedule(&info->tasklet); } @@ -594,7 +594,7 @@ ctc_tty_flush_chars(struct tty_struct *tty) return; if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_chars")) return; - if (tty->stopped || tty->hw_stopped || (!skb_queue_len(&info->tx_queue))) + if (tty->stopped || tty->hw_stopped || skb_queue_empty(&info->tx_queue)) return; tasklet_schedule(&info->tasklet); } diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 8a945f4f369..576f3b852fc 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -3227,9 +3227,9 @@ static int usbnet_stop (struct net_device *net) temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq); // maybe wait for deletions to finish. - while (skb_queue_len (&dev->rxq) - && skb_queue_len (&dev->txq) - && skb_queue_len (&dev->done)) { + while (!skb_queue_empty(&dev->rxq) && + !skb_queue_empty(&dev->txq) && + !skb_queue_empty(&dev->done)) { msleep(UNLINK_TIMEOUT_MS); if (netif_msg_ifdown (dev)) devdbg (dev, "waited for %d urb completions", temp); -- cgit v1.2.3 From f179bc77d09b9087bfc559d0368bba350342ac76 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 10 Jul 2005 12:46:19 +1000 Subject: drm: fix stupid missing semicolon. I fixed this in one git tree but that wasn't the one I pushed... Signed-off-by: Dave Airlie --- drivers/char/drm/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index e58bdac1640..9c37d2367dd 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -121,7 +121,7 @@ extern void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap); extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) + unsigned long arg); #define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, reg) -- cgit v1.2.3 From 1934b8b6561ee7804b0a671b48cf642fcd936b2c Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Sat, 9 Jul 2005 20:01:23 -0400 Subject: [PATCH] Sync up ieee-1394 Lots of this patch is trivial code cleanups (static vars were being intialized to 0, etc). There's also some fixes for ISO transmits (max buffer handling). Aswell, we have a few fixes to disable IRM capabilites correctly. We've also disabled, by default some generally unused EXPORT symbols for the sake of cleanliness in the kernel. However, instead of removing them completely, we felt it necessary to have a config option that allowed them to be enabled for the many projects outside of the main kernel tree that use our API for driver development. The primary reason for this patch is to revert a MODE6->MODE10 RBC conversion patch from the SCSI maintainers. The new conversions handled directly in the scsi layer do not seem to work for SBP2. This patch reverts to our old working code so that users can enjoy using Firewire disks and dvd drives again. We are working with the SCSI maintainers to resolve this issue outside of the main kernel tree. We'll merge the patch once the SCSI layer's handling of the MODE10 conversion is working for us. Signed-off-by: Linus Torvalds --- drivers/ieee1394/Kconfig | 12 ++++ drivers/ieee1394/csr.c | 3 +- drivers/ieee1394/csr1212.c | 37 ++++++++--- drivers/ieee1394/dma.c | 2 +- drivers/ieee1394/eth1394.c | 6 +- drivers/ieee1394/ieee1394_core.c | 35 ++++++---- drivers/ieee1394/iso.c | 27 ++++++-- drivers/ieee1394/iso.h | 13 +++- drivers/ieee1394/nodemgr.c | 2 +- drivers/ieee1394/ohci1394.c | 40 ++++++------ drivers/ieee1394/pcilynx.c | 4 +- drivers/ieee1394/raw1394.c | 7 +- drivers/ieee1394/sbp2.c | 135 +++++++++++++++++++++++++++++++++++++-- 13 files changed, 260 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig index 7d58af1ae30..25103a0ef9b 100644 --- a/drivers/ieee1394/Kconfig +++ b/drivers/ieee1394/Kconfig @@ -66,6 +66,18 @@ config IEEE1394_CONFIG_ROM_IP1394 with MacOSX and WinXP IP-over-1394), enable this option and the eth1394 option below. +config IEEE1394_EXPORT_FULL_API + bool "Export all symbols of ieee1394's API" + depends on IEEE1394 + default n + help + Export all symbols of ieee1394's driver programming interface, even + those that are not currently used by the standard IEEE 1394 drivers. + + This option does not affect the interface to userspace applications. + Say Y here if you want to compile externally developed drivers that + make extended use of ieee1394's API. It is otherwise safe to say N. + comment "Device Drivers" depends on IEEE1394 diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c index 1b98684aebc..149573db91c 100644 --- a/drivers/ieee1394/csr.c +++ b/drivers/ieee1394/csr.c @@ -28,6 +28,7 @@ #include "hosts.h" #include "ieee1394.h" #include "highlevel.h" +#include "ieee1394_core.h" /* Module Parameters */ /* this module parameter can be used to disable mapping of the FCP registers */ @@ -232,7 +233,7 @@ static void add_host(struct hpsb_host *host) host->csr.generation = 2; bus_info[1] = __constant_cpu_to_be32(0x31333934); - bus_info[2] = cpu_to_be32((1 << CSR_IRMC_SHIFT) | + bus_info[2] = cpu_to_be32((hpsb_disable_irm ? 0 : 1 << CSR_IRMC_SHIFT) | (1 << CSR_CMC_SHIFT) | (1 << CSR_ISC_SHIFT) | (0 << CSR_BMC_SHIFT) | diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c index 7c4330e2e87..61ddd5d37ef 100644 --- a/drivers/ieee1394/csr1212.c +++ b/drivers/ieee1394/csr1212.c @@ -209,7 +209,15 @@ void csr1212_init_local_csr(struct csr1212_csr *csr, { static const int mr_map[] = { 4, 64, 1024, 0 }; +#ifdef __KERNEL__ + BUG_ON(max_rom & ~0x3); csr->max_rom = mr_map[max_rom]; +#else + if (max_rom & ~0x3) /* caller supplied invalid argument */ + csr->max_rom = 0; + else + csr->max_rom = mr_map[max_rom]; +#endif memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len); } @@ -533,12 +541,15 @@ struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version, static const int pd[4] = { 0, 4, 16, 256 }; static const int cs[16] = { 4, 2 }; struct csr1212_keyval *kv; - int palette_size = pd[palette_depth] * cs[color_space]; + int palette_size; int pixel_size = (hscan * vscan + 3) & ~0x3; - if ((palette_depth && !palette) || !pixels) + if (!pixels || (!palette && palette_depth) || + (palette_depth & ~0x3) || (color_space & ~0xf)) return NULL; + palette_size = pd[palette_depth] * cs[color_space]; + kv = csr1212_new_descriptor_leaf(1, 0, NULL, palette_size + pixel_size + CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD); @@ -760,9 +771,9 @@ static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize) struct csr1212_csr_rom_cache *cache; u_int64_t csr_addr; - if (!csr || !csr->ops->allocate_addr_range || - !csr->ops->release_addr) - return CSR1212_ENOMEM; + if (!csr || !csr->ops || !csr->ops->allocate_addr_range || + !csr->ops->release_addr || csr->max_rom < 1) + return CSR1212_EINVAL; /* ROM size must be a multiple of csr->max_rom */ romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1); @@ -1145,6 +1156,8 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) /* Make sure the Extended ROM leaf is a multiple of * max_rom in size. */ + if (csr->max_rom < 1) + return CSR1212_EINVAL; leaf_size = (cache->len + (csr->max_rom - 1)) & ~(csr->max_rom - 1); @@ -1409,7 +1422,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) u_int32_t *cache_ptr; u_int16_t kv_len = 0; - if (!csr || !kv) + if (!csr || !kv || csr->max_rom < 1) return CSR1212_EINVAL; /* First find which cache the data should be in (or go in if not read @@ -1572,7 +1585,7 @@ int csr1212_parse_csr(struct csr1212_csr *csr) struct csr1212_dentry *dentry; int ret; - if (!csr || !csr->ops->bus_read) + if (!csr || !csr->ops || !csr->ops->bus_read) return CSR1212_EINVAL; ret = csr1212_parse_bus_info_block(csr); @@ -1581,9 +1594,13 @@ int csr1212_parse_csr(struct csr1212_csr *csr) if (!csr->ops->get_max_rom) csr->max_rom = mr_map[0]; /* default value */ - else - csr->max_rom = mr_map[csr->ops->get_max_rom(csr->bus_info_data, - csr->private)]; + else { + int i = csr->ops->get_max_rom(csr->bus_info_data, + csr->private); + if (i & ~0x3) + return CSR1212_EINVAL; + csr->max_rom = mr_map[i]; + } csr->cache_head->layout_head = csr->root_kv; csr->cache_head->layout_tail = csr->root_kv; diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c index 758819d1999..b79ddb43e74 100644 --- a/drivers/ieee1394/dma.c +++ b/drivers/ieee1394/dma.c @@ -158,7 +158,7 @@ static inline int dma_region_find(struct dma_region *dma, unsigned long offset, dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset) { - unsigned long rem; + unsigned long rem = 0; struct scatterlist *sg = &dma->sglist[dma_region_find(dma, offset, &rem)]; return sg_dma_address(sg) + rem; diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 654da76bf81..cd53c174ced 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -89,7 +89,7 @@ #define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__) static char version[] __devinitdata = - "$Rev: 1247 $ Ben Collins "; + "$Rev: 1264 $ Ben Collins "; struct fragment_info { struct list_head list; @@ -706,7 +706,7 @@ static void ether1394_host_reset (struct hpsb_host *host) return; dev = hi->dev; - priv = netdev_priv(dev); + priv = (struct eth1394_priv *)netdev_priv(dev); /* Reset our private host data, but not our mtu */ netif_stop_queue (dev); @@ -1770,7 +1770,7 @@ fail: static void ether1394_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strcpy (info->driver, driver_name); - strcpy (info->version, "$Rev: 1247 $"); + strcpy (info->version, "$Rev: 1264 $"); /* FIXME XXX provide sane businfo */ strcpy (info->bus_info, "ieee1394"); } diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 629070b83a3..b248d89de8b 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -52,7 +52,7 @@ /* * Disable the nodemgr detection and config rom reading functionality. */ -static int disable_nodemgr = 0; +static int disable_nodemgr; module_param(disable_nodemgr, int, 0444); MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality."); @@ -520,6 +520,9 @@ int hpsb_send_packet(struct hpsb_packet *packet) if (!packet->no_waiter || packet->expect_response) { atomic_inc(&packet->refcnt); + /* Set the initial "sendtime" to 10 seconds from now, to + prevent premature expiry. If a packet takes more than + 10 seconds to hit the wire, we have bigger problems :) */ packet->sendtime = jiffies + 10 * HZ; skb_queue_tail(&host->pending_packet_queue, packet->skb); } @@ -1223,9 +1226,7 @@ EXPORT_SYMBOL(hpsb_protocol_class); EXPORT_SYMBOL(hpsb_set_packet_complete_task); EXPORT_SYMBOL(hpsb_alloc_packet); EXPORT_SYMBOL(hpsb_free_packet); -EXPORT_SYMBOL(hpsb_send_phy_config); EXPORT_SYMBOL(hpsb_send_packet); -EXPORT_SYMBOL(hpsb_send_packet_and_wait); EXPORT_SYMBOL(hpsb_reset_bus); EXPORT_SYMBOL(hpsb_bus_reset); EXPORT_SYMBOL(hpsb_selfid_received); @@ -1233,6 +1234,10 @@ EXPORT_SYMBOL(hpsb_selfid_complete); EXPORT_SYMBOL(hpsb_packet_sent); EXPORT_SYMBOL(hpsb_packet_received); EXPORT_SYMBOL_GPL(hpsb_disable_irm); +#ifdef CONFIG_IEEE1394_EXPORT_FULL_API +EXPORT_SYMBOL(hpsb_send_phy_config); +EXPORT_SYMBOL(hpsb_send_packet_and_wait); +#endif /** ieee1394_transactions.c **/ EXPORT_SYMBOL(hpsb_get_tlabel); @@ -1262,9 +1267,11 @@ EXPORT_SYMBOL(hpsb_destroy_hostinfo); EXPORT_SYMBOL(hpsb_set_hostinfo_key); EXPORT_SYMBOL(hpsb_get_hostinfo_bykey); EXPORT_SYMBOL(hpsb_set_hostinfo); +EXPORT_SYMBOL(highlevel_host_reset); +#ifdef CONFIG_IEEE1394_EXPORT_FULL_API EXPORT_SYMBOL(highlevel_add_host); EXPORT_SYMBOL(highlevel_remove_host); -EXPORT_SYMBOL(highlevel_host_reset); +#endif /** nodemgr.c **/ EXPORT_SYMBOL(hpsb_node_fill_packet); @@ -1272,7 +1279,9 @@ EXPORT_SYMBOL(hpsb_node_write); EXPORT_SYMBOL(hpsb_register_protocol); EXPORT_SYMBOL(hpsb_unregister_protocol); EXPORT_SYMBOL(ieee1394_bus_type); +#ifdef CONFIG_IEEE1394_EXPORT_FULL_API EXPORT_SYMBOL(nodemgr_for_each_host); +#endif /** csr.c **/ EXPORT_SYMBOL(hpsb_update_config_rom); @@ -1309,19 +1318,21 @@ EXPORT_SYMBOL(hpsb_iso_wake); EXPORT_SYMBOL(hpsb_iso_recv_flush); /** csr1212.c **/ -EXPORT_SYMBOL(csr1212_create_csr); -EXPORT_SYMBOL(csr1212_init_local_csr); -EXPORT_SYMBOL(csr1212_new_immediate); EXPORT_SYMBOL(csr1212_new_directory); -EXPORT_SYMBOL(csr1212_associate_keyval); EXPORT_SYMBOL(csr1212_attach_keyval_to_directory); -EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf); EXPORT_SYMBOL(csr1212_detach_keyval_from_directory); EXPORT_SYMBOL(csr1212_release_keyval); -EXPORT_SYMBOL(csr1212_destroy_csr); EXPORT_SYMBOL(csr1212_read); -EXPORT_SYMBOL(csr1212_generate_csr_image); EXPORT_SYMBOL(csr1212_parse_keyval); -EXPORT_SYMBOL(csr1212_parse_csr); EXPORT_SYMBOL(_csr1212_read_keyval); EXPORT_SYMBOL(_csr1212_destroy_keyval); +#ifdef CONFIG_IEEE1394_EXPORT_FULL_API +EXPORT_SYMBOL(csr1212_create_csr); +EXPORT_SYMBOL(csr1212_init_local_csr); +EXPORT_SYMBOL(csr1212_new_immediate); +EXPORT_SYMBOL(csr1212_associate_keyval); +EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf); +EXPORT_SYMBOL(csr1212_destroy_csr); +EXPORT_SYMBOL(csr1212_generate_csr_image); +EXPORT_SYMBOL(csr1212_parse_csr); +#endif diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c index f05759107f7..615541b8b90 100644 --- a/drivers/ieee1394/iso.c +++ b/drivers/ieee1394/iso.c @@ -62,10 +62,10 @@ static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_i if ((dma_mode < HPSB_ISO_DMA_DEFAULT) || (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER)) dma_mode=HPSB_ISO_DMA_DEFAULT; + if ((irq_interval < 0) || (irq_interval > buf_packets / 4)) + irq_interval = buf_packets / 4; if (irq_interval == 0) /* really interrupt for each packet*/ irq_interval = 1; - else if ((irq_interval < 0) || (irq_interval > buf_packets / 4)) - irq_interval = buf_packets / 4; if (channel < -1 || channel >= 64) return NULL; @@ -106,6 +106,7 @@ static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_i } atomic_set(&iso->overflows, 0); + iso->bytes_discarded = 0; iso->flags = 0; iso->prebuffer = 0; @@ -241,12 +242,12 @@ int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer) iso->xmit_cycle = cycle; if (prebuffer < 0) - prebuffer = iso->buf_packets; + prebuffer = iso->buf_packets - 1; else if (prebuffer == 0) prebuffer = 1; - if (prebuffer > iso->buf_packets) - prebuffer = iso->buf_packets; + if (prebuffer >= iso->buf_packets) + prebuffer = iso->buf_packets - 1; iso->prebuffer = prebuffer; @@ -395,7 +396,7 @@ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error) } void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, - u16 cycle, u8 channel, u8 tag, u8 sy) + u16 total_len, u16 cycle, u8 channel, u8 tag, u8 sy) { unsigned long flags; spin_lock_irqsave(&iso->lock, flags); @@ -403,10 +404,13 @@ void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, if (iso->n_ready_packets == iso->buf_packets) { /* overflow! */ atomic_inc(&iso->overflows); + /* Record size of this discarded packet */ + iso->bytes_discarded += total_len; } else { struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma]; info->offset = offset; info->len = len; + info->total_len = total_len; info->cycle = cycle; info->channel = channel; info->tag = tag; @@ -437,6 +441,17 @@ int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) iso->first_packet = (iso->first_packet+1) % iso->buf_packets; iso->n_ready_packets--; + + /* release memory from packets discarded when queue was full */ + if (iso->n_ready_packets == 0) { /* Release only after all prior packets handled */ + if (iso->bytes_discarded != 0) { + struct hpsb_iso_packet_info inf; + inf.total_len = iso->bytes_discarded; + iso->host->driver->isoctl(iso, RECV_RELEASE, + (unsigned long) &inf); + iso->bytes_discarded = 0; + } + } } spin_unlock_irqrestore(&iso->lock, flags); return rv; diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h index fb654d9639a..3efc60b33a8 100644 --- a/drivers/ieee1394/iso.h +++ b/drivers/ieee1394/iso.h @@ -47,6 +47,14 @@ struct hpsb_iso_packet_info { /* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */ __u8 tag; __u8 sy; + + /* + * length in bytes of the packet including header/trailer. + * MUST be at structure end, since the first part of this structure is also + * defined in raw1394.h (i.e. struct raw1394_iso_packet_info), is copied to + * userspace and is accessed there through libraw1394. + */ + __u16 total_len; }; enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 }; @@ -111,6 +119,9 @@ struct hpsb_iso { /* how many times the buffer has overflowed or underflowed */ atomic_t overflows; + /* Current number of bytes lost in discarded packets */ + int bytes_discarded; + /* private flags to track initialization progress */ #define HPSB_ISO_DRIVER_INIT (1<<0) #define HPSB_ISO_DRIVER_STARTED (1<<1) @@ -193,7 +204,7 @@ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error); /* call after a packet has been received (interrupt context OK) */ void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, - u16 cycle, u8 channel, u8 tag, u8 sy); + u16 total_len, u16 cycle, u8 channel, u8 tag, u8 sy); /* call to wake waiting processes after buffer space has opened up. */ void hpsb_iso_wake(struct hpsb_iso *iso); diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 9a46c3b44bf..bebcc47ab06 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -30,7 +30,7 @@ #include "csr.h" #include "nodemgr.h" -static int ignore_drivers = 0; +static int ignore_drivers; module_param(ignore_drivers, int, 0444); MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers."); diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index b3d3d22fde6..a485f47bb21 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -162,7 +162,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args) printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args) static char version[] __devinitdata = - "$Rev: 1250 $ Ben Collins "; + "$Rev: 1299 $ Ben Collins "; /* Module Parameters */ static int phys_dma = 1; @@ -483,7 +483,9 @@ static void ohci_initialize(struct ti_ohci *ohci) /* Put some defaults to these undefined bus options */ buf = reg_read(ohci, OHCI1394_BusOptions); buf |= 0x60000000; /* Enable CMC and ISC */ - if (!hpsb_disable_irm) + if (hpsb_disable_irm) + buf &= ~0x80000000; + else buf |= 0x80000000; /* Enable IRMC */ buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */ buf &= ~0x18000000; /* Disable PMC and BMC */ @@ -503,8 +505,12 @@ static void ohci_initialize(struct ti_ohci *ohci) reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_CycleTimerEnable | OHCI1394_LinkControl_CycleMaster); - set_phy_reg_mask(ohci, 4, PHY_04_LCTRL | - (hpsb_disable_irm ? 0 : PHY_04_CONTENDER)); + i = get_phy_reg(ohci, 4) | PHY_04_LCTRL; + if (hpsb_disable_irm) + i &= ~PHY_04_CONTENDER; + else + i |= PHY_04_CONTENDER; + set_phy_reg(ohci, 4, i); /* Set up self-id dma buffer */ reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus); @@ -1566,6 +1572,10 @@ static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block) struct dma_cmd *next = &recv->block[next_i]; struct dma_cmd *prev = &recv->block[prev_i]; + + /* ignore out-of-range requests */ + if ((block < 0) || (block > recv->nblocks)) + return; /* 'next' becomes the new end of the DMA chain, so disable branch and enable interrupt */ @@ -1593,19 +1603,8 @@ static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block) static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv, struct hpsb_iso_packet_info *info) { - int len; - /* release the memory where the packet was */ - len = info->len; - - /* add the wasted space for padding to 4 bytes */ - if (len % 4) - len += 4 - (len % 4); - - /* add 8 bytes for the OHCI DMA data format overhead */ - len += 8; - - recv->released_bytes += len; + recv->released_bytes += info->total_len; /* have we released enough memory for one block? */ while (recv->released_bytes > recv->buf_stride) { @@ -1637,7 +1636,7 @@ static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso /* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */ unsigned int offset; - unsigned short len, cycle; + unsigned short len, cycle, total_len; unsigned char channel, tag, sy; unsigned char *p = iso->data_buf.kvirt; @@ -1688,9 +1687,11 @@ static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso /* advance to xferStatus/timeStamp */ recv->dma_offset += len; + total_len = len + 8; /* 8 bytes header+trailer in OHCI packet */ /* payload is padded to 4 bytes */ if (len % 4) { recv->dma_offset += 4 - (len%4); + total_len += 4 - (len%4); } /* check for wrap-around */ @@ -1724,7 +1725,7 @@ static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso recv->dma_offset -= recv->buf_stride*recv->nblocks; } - hpsb_iso_packet_received(iso, offset, len, cycle, channel, tag, sy); + hpsb_iso_packet_received(iso, offset, len, total_len, cycle, channel, tag, sy); } if (wake) @@ -1850,7 +1851,8 @@ static void ohci_iso_recv_packetperbuf_task(struct hpsb_iso *iso, struct ohci_is tag = hdr[5] >> 6; sy = hdr[4] & 0xF; - hpsb_iso_packet_received(iso, offset, packet_len, cycle, channel, tag, sy); + hpsb_iso_packet_received(iso, offset, packet_len, + recv->buf_stride, cycle, channel, tag, sy); } /* reset the DMA descriptor */ diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index bdb3a85cafa..36074e6eeeb 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -76,7 +76,7 @@ /* Module Parameters */ -static int skip_eeprom = 0; +static int skip_eeprom; module_param(skip_eeprom, int, 0444); MODULE_PARM_DESC(skip_eeprom, "Use generic bus info block instead of serial eeprom (default = 0)."); @@ -1422,7 +1422,7 @@ static int __devinit add_card(struct pci_dev *dev, i = get_phy_reg(lynx, 4); i |= PHY_04_LCTRL; if (hpsb_disable_irm) - i &= !PHY_04_CONTENDER; + i &= ~PHY_04_CONTENDER; else i |= PHY_04_CONTENDER; if (i != -1) set_phy_reg(lynx, 4, i); diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 7419af450bd..b4fa14793fe 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -98,7 +98,7 @@ static struct hpsb_address_ops arm_ops = { static void queue_complete_cb(struct pending_request *req); -static struct pending_request *__alloc_pending_request(int flags) +static struct pending_request *__alloc_pending_request(unsigned int __nocast flags) { struct pending_request *req; @@ -2506,9 +2506,12 @@ static int raw1394_iso_send_packets(struct file_info *fi, void __user * uaddr) if (copy_from_user(&upackets, uaddr, sizeof(upackets))) return -EFAULT; - if (upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle)) + if (upackets.n_packets >= fi->iso_handle->buf_packets) return -EINVAL; + if (upackets.n_packets >= hpsb_iso_n_ready(fi->iso_handle)) + return -EAGAIN; + /* ensure user-supplied buffer is accessible and big enough */ if (!access_ok(VERIFY_READ, upackets.infos, upackets.n_packets * diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 32368f3428e..fe3e1703fa6 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -81,7 +81,7 @@ #include "sbp2.h" static char version[] __devinitdata = - "$Rev: 1219 $ Ben Collins "; + "$Rev: 1306 $ Ben Collins "; /* * Module load parameter definitions @@ -104,7 +104,7 @@ MODULE_PARM_DESC(max_speed, "Force max speed (3 = 800mb, 2 = 400mb default, 1 = * down to us at a time (debugging). This might be necessary for very * badly behaved sbp2 devices. */ -static int serialize_io = 0; +static int serialize_io; module_param(serialize_io, int, 0444); MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)"); @@ -145,7 +145,7 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device (default = 1)" * please submit the logged sbp2_firmware_revision value of this device to * the linux1394-devel mailing list. */ -static int force_inquiry_hack = 0; +static int force_inquiry_hack; module_param(force_inquiry_hack, int, 0444); MODULE_PARM_DESC(force_inquiry_hack, "Force SCSI inquiry hack (default = 0)"); @@ -2112,6 +2112,102 @@ static int sbp2_send_command(struct scsi_id_instance_data *scsi_id, */ static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd) { + unchar new_cmd[16]; + u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun); + + SBP2_DEBUG("sbp2_check_sbp2_command"); + + switch (*cmd) { + + case READ_6: + + if (sbp2_command_conversion_device_type(device_type)) { + + SBP2_DEBUG("Convert READ_6 to READ_10"); + + /* + * Need to turn read_6 into read_10 + */ + new_cmd[0] = 0x28; + new_cmd[1] = (cmd[1] & 0xe0); + new_cmd[2] = 0x0; + new_cmd[3] = (cmd[1] & 0x1f); + new_cmd[4] = cmd[2]; + new_cmd[5] = cmd[3]; + new_cmd[6] = 0x0; + new_cmd[7] = 0x0; + new_cmd[8] = cmd[4]; + new_cmd[9] = cmd[5]; + + memcpy(cmd, new_cmd, 10); + + } + + break; + + case WRITE_6: + + if (sbp2_command_conversion_device_type(device_type)) { + + SBP2_DEBUG("Convert WRITE_6 to WRITE_10"); + + /* + * Need to turn write_6 into write_10 + */ + new_cmd[0] = 0x2a; + new_cmd[1] = (cmd[1] & 0xe0); + new_cmd[2] = 0x0; + new_cmd[3] = (cmd[1] & 0x1f); + new_cmd[4] = cmd[2]; + new_cmd[5] = cmd[3]; + new_cmd[6] = 0x0; + new_cmd[7] = 0x0; + new_cmd[8] = cmd[4]; + new_cmd[9] = cmd[5]; + + memcpy(cmd, new_cmd, 10); + + } + + break; + + case MODE_SENSE: + + if (sbp2_command_conversion_device_type(device_type)) { + + SBP2_DEBUG("Convert MODE_SENSE_6 to MODE_SENSE_10"); + + /* + * Need to turn mode_sense_6 into mode_sense_10 + */ + new_cmd[0] = 0x5a; + new_cmd[1] = cmd[1]; + new_cmd[2] = cmd[2]; + new_cmd[3] = 0x0; + new_cmd[4] = 0x0; + new_cmd[5] = 0x0; + new_cmd[6] = 0x0; + new_cmd[7] = 0x0; + new_cmd[8] = cmd[4]; + new_cmd[9] = cmd[5]; + + memcpy(cmd, new_cmd, 10); + + } + + break; + + case MODE_SELECT: + + /* + * TODO. Probably need to change mode select to 10 byte version + */ + + default: + break; + } + + return; } /* @@ -2152,6 +2248,7 @@ static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, struct scsi_cmnd *SCpnt) { u8 *scsi_buf = SCpnt->request_buffer; + u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun); SBP2_DEBUG("sbp2_check_sbp2_response"); @@ -2175,6 +2272,14 @@ static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, scsi_buf[4] = 36 - 5; } + /* + * Check for Simple Direct Access Device and change it to TYPE_DISK + */ + if ((scsi_buf[0] & 0x1f) == TYPE_RBC) { + SBP2_DEBUG("Changing TYPE_RBC to TYPE_DISK"); + scsi_buf[0] &= 0xe0; + } + /* * Fix ansi revision and response data format */ @@ -2183,6 +2288,27 @@ static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, break; + case MODE_SENSE: + + if (sbp2_command_conversion_device_type(device_type)) { + + SBP2_DEBUG("Modify mode sense response (10 byte version)"); + + scsi_buf[0] = scsi_buf[1]; /* Mode data length */ + scsi_buf[1] = scsi_buf[2]; /* Medium type */ + scsi_buf[2] = scsi_buf[3]; /* Device specific parameter */ + scsi_buf[3] = scsi_buf[7]; /* Block descriptor length */ + memcpy(scsi_buf + 4, scsi_buf + 8, scsi_buf[0]); + } + + break; + + case MODE_SELECT: + + /* + * TODO. Probably need to change mode select to 10 byte version + */ + default: break; } @@ -2559,8 +2685,7 @@ static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id, static int sbp2scsi_slave_configure (struct scsi_device *sdev) { blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); - sdev->use_10_for_rw = 1; - sdev->use_10_for_ms = 1; + return 0; } -- cgit v1.2.3 From 6328c0e163abfce679b1beffb166f72900bf0a22 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Wed, 22 Jun 2005 10:25:13 +0300 Subject: [PATCH] I2C: Coding style cleanups to via686a On Wednesday 22 June 2005 08:17, Greg KH wrote: > [PATCH] I2C: Coding style cleanups to via686a > > The via686a hardware monitoring driver has infamous coding style at the > moment. I'd like to clean up the mess before I start working on other > changes to this driver. Is the following patch acceptable? No code > change, only coding style (indentation, alignments, trailing white > space, a few parentheses and a typo). > > Signed-off-by: Jean Delvare > Signed-off-by: Greg Kroah-Hartman Nice. You missed some. This one is on top of your patch: Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/via686a.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c index 137d9b7cacd..164d4794839 100644 --- a/drivers/i2c/chips/via686a.c +++ b/drivers/i2c/chips/via686a.c @@ -1,9 +1,9 @@ /* via686a.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring + for hardware monitoring Copyright (c) 1998 - 2002 Frodo Looijaard , - Kyösti Mälkki , + Kyösti Mälkki , Mark Studebaker , and Bob Dougherty (Some conversion-factor data were contributed by Jonathan Teh Soon Yew @@ -171,18 +171,18 @@ static inline u8 FAN_TO_REG(long rpm, int div) /******** TEMP CONVERSIONS (Bob Dougherty) *********/ /* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) if(temp<169) - return double(temp)*0.427-32.08; + return double(temp)*0.427-32.08; else if(temp>=169 && temp<=202) - return double(temp)*0.582-58.16; + return double(temp)*0.582-58.16; else - return double(temp)*0.924-127.33; + return double(temp)*0.924-127.33; A fifth-order polynomial fits the unofficial data (provided by Alex van Kaam ) a bit better. It also give more reasonable numbers on my machine (ie. they agree with what my BIOS tells me). Here's the fifth-order fit to the 8-bit data: temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - - 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. + 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. (2000-10-25- RFD: thanks to Uwe Andersen for finding my typos in this formula!) -- cgit v1.2.3 From 65fc50e50ff9f8b82c3756eccd7e7db6a267ffe9 Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Wed, 29 Jun 2005 07:13:00 -0700 Subject: [PATCH] I2C: minor TPS6501x cleanups This includes various small cleanups and fixes to the TPS 6501x driver that came mostly from review feedback by Jean Delvare; thanks Jean! Also some goofy whitespace gets fixed. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/Kconfig | 1 - drivers/i2c/chips/tps65010.c | 59 +++++++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index a0982da0980..b28964b0800 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -509,7 +509,6 @@ config TPS65010 This driver can also be built as a module. If so, the module will be called tps65010. - config SENSORS_M41T00 tristate "ST M41T00 RTC chip" depends on I2C && PPC32 diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index c0ac01b6003..280e9638c0f 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -18,7 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#undef DEBUG #include #include @@ -49,11 +48,7 @@ MODULE_DESCRIPTION("TPS6501x Power Management Driver"); MODULE_LICENSE("GPL"); -/* only two addresses possible */ -#define TPS_BASE 0x48 -static unsigned short normal_i2c[] = { - TPS_BASE, - I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END }; static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; @@ -102,7 +97,7 @@ struct tps65010 { u8 chgstatus, regstatus, chgconf; u8 nmask1, nmask2; - /* plus four GPIOs, probably used to switch power */ + /* not currently tracking GPIO state */ }; #define POWER_POLL_DELAY msecs_to_jiffies(800) @@ -135,7 +130,7 @@ static void dbg_regstat(char *buf, size_t len, u8 regstatus) (regstatus & TPS_REG_COVER) ? " uncover" : "", (regstatus & TPS_REG_UVLO) ? " UVLO" : "", (regstatus & TPS_REG_NO_CHG) ? " NO_CHG" : "", - (regstatus & TPS_REG_PG_LD02) ? " ld01_bad" : "", + (regstatus & TPS_REG_PG_LD02) ? " ld02_bad" : "", (regstatus & TPS_REG_PG_LD01) ? " ld01_bad" : "", (regstatus & TPS_REG_PG_MAIN) ? " main_bad" : "", (regstatus & TPS_REG_PG_CORE) ? " core_bad" : ""); @@ -143,7 +138,7 @@ static void dbg_regstat(char *buf, size_t len, u8 regstatus) static void dbg_chgconf(int por, char *buf, size_t len, u8 chgconfig) { - char *hibit; + const char *hibit; if (por) hibit = (chgconfig & TPS_CHARGE_POR) @@ -295,7 +290,7 @@ static int dbg_show(struct seq_file *s, void *_) seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2); for (i = 0; i < 4; i++) { - if (value & (1 << (4 +i))) + if (value & (1 << (4 + i))) seq_printf(s, " gpio%d-out %s\n", i + 1, (value & (1 << i)) ? "low" : "hi "); else @@ -481,7 +476,7 @@ static int __exit tps65010_detach_client(struct i2c_client *client) debugfs_remove(tps->file); if (i2c_detach_client(client) == 0) kfree(tps); - the_tps = 0; + the_tps = NULL; return 0; } @@ -514,7 +509,6 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) INIT_WORK(&tps->work, tps65010_work, tps); tps->irq = -1; tps->client.addr = address; - i2c_set_clientdata(&tps->client, tps); tps->client.adapter = bus; tps->client.driver = &tps65010_driver; strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE); @@ -523,9 +517,7 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind) if (status < 0) { dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", DRIVER_NAME, address, status); -fail1: - kfree(tps); - return 0; + goto fail1; } #ifdef CONFIG_ARM @@ -535,7 +527,7 @@ fail1: tps->irq = OMAP_GPIO_IRQ(58); omap_request_gpio(58); omap_set_gpio_direction(58, 1); - omap_set_gpio_edge_ctrl(58, OMAP_GPIO_FALLING_EDGE); + set_irq_type(tps->irq, IRQT_FALLING); } if (machine_is_omap_osk()) { tps->model = TPS65010; @@ -543,7 +535,7 @@ fail1: tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)); omap_request_gpio(OMAP_MPUIO(1)); omap_set_gpio_direction(OMAP_MPUIO(1), 1); - omap_set_gpio_edge_ctrl(OMAP_MPUIO(1), OMAP_GPIO_FALLING_EDGE); + set_irq_type(tps->irq, IRQT_FALLING); } if (machine_is_omap_h3()) { tps->model = TPS65013; @@ -633,6 +625,9 @@ fail1: tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL, tps, DEBUG_FOPS); return 0; +fail1: + kfree(tps); + return 0; } static int __init tps65010_scan_bus(struct i2c_adapter *bus) @@ -645,7 +640,6 @@ static int __init tps65010_scan_bus(struct i2c_adapter *bus) static struct i2c_driver tps65010_driver = { .owner = THIS_MODULE, .name = "tps65010", - .id = 888, /* FIXME assign "official" value */ .flags = I2C_DF_NOTIFY, .attach_adapter = tps65010_scan_bus, .detach_client = __exit_p(tps65010_detach_client), @@ -744,7 +738,7 @@ int tps65010_set_led(unsigned led, unsigned mode) if (!the_tps) return -ENODEV; - if(led == LED1) + if (led == LED1) offs = 0; else { offs = 2; @@ -753,11 +747,13 @@ int tps65010_set_led(unsigned led, unsigned mode) down(&the_tps->lock); - dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, - i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); + pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, + i2c_smbus_read_byte_data(&the_tps->client, + TPS_LED1_ON + offs)); - dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, - i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); + pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, + i2c_smbus_read_byte_data(&the_tps->client, + TPS_LED1_PER + offs)); switch (mode) { case OFF: @@ -773,7 +769,7 @@ int tps65010_set_led(unsigned led, unsigned mode) led_per = 0x08 | (1 << 7); break; default: - printk(KERN_ERR "%s: Wrong mode parameter for tps65010_set_led()\n", + printk(KERN_ERR "%s: Wrong mode parameter for set_led()\n", DRIVER_NAME); up(&the_tps->lock); return -EINVAL; @@ -789,7 +785,7 @@ int tps65010_set_led(unsigned led, unsigned mode) return status; } - dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, + pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led, i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); status = i2c_smbus_write_byte_data(&the_tps->client, @@ -802,8 +798,9 @@ int tps65010_set_led(unsigned led, unsigned mode) return status; } - dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, - i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); + pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led, + i2c_smbus_read_byte_data(&the_tps->client, + TPS_LED1_PER + offs)); up(&the_tps->lock); @@ -874,7 +871,7 @@ int tps65010_set_low_pwr(unsigned mode) if (status != 0) printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", - DRIVER_NAME); + DRIVER_NAME); else pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); @@ -900,14 +897,14 @@ int tps65010_config_vregs1(unsigned value) down(&the_tps->lock); pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, - i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); status = i2c_smbus_write_byte_data(&the_tps->client, TPS_VREGS1, value); if (status != 0) printk(KERN_ERR "%s: Failed to write vregs1 register\n", - DRIVER_NAME); + DRIVER_NAME); else pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); @@ -1009,7 +1006,7 @@ static int __init tps_init(void) msleep(10); } -#if defined(CONFIG_ARM) +#ifdef CONFIG_ARM if (machine_is_omap_osk()) { // FIXME: More should be placed in the initialization code -- cgit v1.2.3 From 541e6a02768404efb06bd1ea5f33d614732f41fc Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 23 Jun 2005 22:18:08 +0200 Subject: [PATCH] I2C: Strip trailing whitespace from strings Here is a simple patch originally from Denis Vlasenko, which strips a useless trailing whitespace from 8 strings in 4 i2c drivers. Please apply, thanks. From: Denis Vlasenko Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/algos/i2c-algo-ite.c | 8 ++++---- drivers/i2c/busses/i2c-i801.c | 4 ++-- drivers/i2c/busses/i2c-piix4.c | 2 +- drivers/i2c/busses/i2c-sis5595.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c index 68e9e6832ca..e6cae39f47a 100644 --- a/drivers/i2c/algos/i2c-algo-ite.c +++ b/drivers/i2c/algos/i2c-algo-ite.c @@ -208,7 +208,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) { goto bailout; } sdalo(adap); - printk("test_bus:1 scl: %d sda: %d \n",getscl(adap), + printk("test_bus:1 scl: %d sda: %d\n", getscl(adap), getsda(adap)); if ( 0 != getsda(adap) ) { printk("test_bus: %s SDA stuck high!\n",name); @@ -221,7 +221,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) { goto bailout; } sdahi(adap); - printk("test_bus:2 scl: %d sda: %d \n",getscl(adap), + printk("test_bus:2 scl: %d sda: %d\n", getscl(adap), getsda(adap)); if ( 0 == getsda(adap) ) { printk("test_bus: %s SDA stuck low!\n",name); @@ -234,7 +234,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) { goto bailout; } scllo(adap); - printk("test_bus:3 scl: %d sda: %d \n",getscl(adap), + printk("test_bus:3 scl: %d sda: %d\n", getscl(adap), getsda(adap)); if ( 0 != getscl(adap) ) { @@ -247,7 +247,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) { goto bailout; } sclhi(adap); - printk("test_bus:4 scl: %d sda: %d \n",getscl(adap), + printk("test_bus:4 scl: %d sda: %d\n", getscl(adap), getsda(adap)); if ( 0 == getscl(adap) ) { printk("test_bus: %s SCL stuck low!\n",name); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 45e6efb1dcd..0ab7e37f5b0 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -194,7 +194,7 @@ static int i801_transaction(void) /* Make sure the SMBus host is ready to start transmitting */ /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { - dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting... \n", + dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting...\n", temp); outb_p(temp, SMBHSTSTS); if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { @@ -315,7 +315,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, } if (temp & errmask) { dev_dbg(&I801_dev->dev, "SMBus busy (%02x). " - "Resetting... \n", temp); + "Resetting...\n", temp); outb_p(temp, SMBHSTSTS); if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) { dev_err(&I801_dev->dev, diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 1f80ba9da6f..6d34ee381ce 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -243,7 +243,7 @@ static int piix4_transaction(void) /* Make sure the SMBus host is ready to start transmitting */ if ((temp = inb_p(SMBHSTSTS)) != 0x00) { dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). " - "Resetting... \n", temp); + "Resetting...\n", temp); outb_p(temp, SMBHSTSTS); if ((temp = inb_p(SMBHSTSTS)) != 0x00) { dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 2b5911cfb7b..bbd5e4e52f0 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -228,7 +228,7 @@ static int sis5595_transaction(struct i2c_adapter *adap) /* Make sure the SMBus host is ready to start transmitting */ temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8); if (temp != 0x00) { - dev_dbg(&adap->dev, "SMBus busy (%04x). Resetting... \n", temp); + dev_dbg(&adap->dev, "SMBus busy (%04x). Resetting...\n", temp); sis5595_write(SMB_STS_LO, temp & 0xff); sis5595_write(SMB_STS_HI, temp >> 8); if ((temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != 0x00) { -- cgit v1.2.3 From 9ab1ee2ab7d65979c0f14a60ee1f29f8988f5811 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 24 Jun 2005 21:14:16 +0200 Subject: [PATCH] I2C: New max6875 driver may corrupt EEPROMs After a careful code analysis on the new max6875 driver (drivers/i2c/chips/max6875.c), I have come to the conclusion that this driver may cause EEPROM corruptions if used on random systems. The EEPROM part of the MAX6875 chip is accessed using rather uncommon I2C sequences. What is seen by the MAX6875 as reads can be seen by a standard EEPROM (24C02) as writes. If you check the detection method used by the driver, you'll find that the first SMBus command it will send on the bus is i2c_smbus_write_byte_data(client, 0x80, 0x40). For the MAX6875 it makes an internal pointer point to a specific offset of the EEPROM waiting for a subsequent read command, so it's not an actual data write operation, but for a standard EEPROM, this instead means writing value 0x40 to offset 0x80. Blame Philips and Intel for the obscure protocol. Since the MAX6875 and the standard, common 24C02 EEPROMs share two I2C addresses (0x50 and 0x52), loading the max6875 driver on a system with standard EEPROMs at either address will trigger a write on these EEPROMs, which will lead to their corruption if they happen not to be write protected. This kind of EEPROMs can be found on memory modules (SPD), ethernet adapters (MAC address), laptops (proprietary data) and displays (EDID/DDC). Most of these are hopefully write-protected, but not all of them. For this reason, I would recommend that the max6875 driver be neutralized, in a way that nobody can corrupt his/her EEPROMs by just loading the driver. This means either deleting the driver completely, or not listing any default address for it. I'd like this to be done before 2.6.13-rc1 is released. Additionally, the max6875 driver lacks the 24RF08 corruption preventer present in the eeprom driver, which means that loading this driver in a system with such a chip would corrupt it as well. Here is a proposed quick patch addressing the issue, although I wouldn't mind a complete removal if it makes everyone feel safer. I think Ben has plans to replace this driver by a much simplified one anyway. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/max6875.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index fe6b150ec4c..c4f14d9623c 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -37,7 +37,8 @@ #include /* Addresses to scan */ -static unsigned short normal_i2c[] = {0x50, 0x52, I2C_CLIENT_END}; +/* No address scanned by default, as this could corrupt standard EEPROMS. */ +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END}; /* Insmod parameters */ @@ -369,6 +370,9 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) new_client->driver = &max6875_driver; new_client->flags = 0; + /* Prevent 24RF08 corruption */ + i2c_smbus_write_quick(new_client, 0); + /* Setup the user section */ data->blocks[max6875_eeprom_user].type = max6875_eeprom_user; data->blocks[max6875_eeprom_user].slices = USER_EEPROM_SLICES; -- cgit v1.2.3 From 2146fec20c38d926f0d88413977f941f42a14588 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 23 Jun 2005 23:41:39 +0200 Subject: [PATCH] I2C: max6875 Kconfig update Here is a proposed Kconfig update for the new max6875 i2c chip driver. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/Kconfig | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index b28964b0800..5bd72c480c9 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -519,13 +519,16 @@ config SENSORS_M41T00 will be called m41t00. config SENSORS_MAX6875 - tristate "MAXIM MAX6875 Power supply supervisor" + tristate "Maxim MAX6875 Power supply supervisor" depends on I2C && EXPERIMENTAL help - If you say yes here you get support for the MAX6875 - EEPROM-Programmable, Hex/Quad, Power-Suppy Sequencers/Supervisors. + If you say yes here you get support for the Maxim MAX6875 + EEPROM-programmable, quad power-supply sequencer/supervisor. - This provides a interface to program the EEPROM and reset the chip. + This provides an interface to program the EEPROM and reset the chip. + + This driver also supports the Maxim MAX6874 hex power-supply + sequencer/supervisor if found at a compatible address. This driver can also be built as a module. If so, the module will be called max6875. -- cgit v1.2.3 From 5da69ba42aa42a479c0f5d8cb8351ebb6b51c12e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 1 Jul 2005 14:28:15 +0200 Subject: [PATCH] I2C: m41t00: fix incorrect kfree Here is a simple path fixing an incorrect kfree in the m41t00 i2c chip driver. The current code happens to work by accident, but the freed pointer isn't the one which was allocated in the first place, which could cause problems later. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/m41t00.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index 5e463c47bfb..778d7e12859 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -207,7 +207,7 @@ m41t00_detach(struct i2c_client *client) int rc; if ((rc = i2c_detach_client(client)) == 0) { - kfree(i2c_get_clientdata(client)); + kfree(client); tasklet_kill(&m41t00_tasklet); } return rc; -- cgit v1.2.3 From a0920e10438e9fe8b22aba607083347c84458ed8 Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Tue, 28 Jun 2005 00:21:30 -0400 Subject: [PATCH] i2c: make better use of IDR in i2c-core This patch uses the already existing IDR mechanism to simplify and improve the i2c_get_adapter function in i2c-core. Signed-off-by: Mark M. Hoffman Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/i2c-core.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 51ce268998c..4fd4f52c8e9 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -156,7 +156,7 @@ int i2c_add_adapter(struct i2c_adapter *adap) goto out_unlock; } - res = idr_get_new(&i2c_adapter_idr, NULL, &id); + res = idr_get_new(&i2c_adapter_idr, adap, &id); if (res < 0) { if (res == -EAGAIN) res = -ENOMEM; @@ -765,20 +765,15 @@ int i2c_adapter_id(struct i2c_adapter *adap) struct i2c_adapter* i2c_get_adapter(int id) { - struct list_head *item; struct i2c_adapter *adapter; down(&core_lists); - list_for_each(item,&adapters) { - adapter = list_entry(item, struct i2c_adapter, list); - if (id == adapter->nr && - try_module_get(adapter->owner)) { - up(&core_lists); - return adapter; - } - } + adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); + if (adapter && !try_module_get(adapter->owner)) + adapter = NULL; + up(&core_lists); - return NULL; + return adapter; } void i2c_put_adapter(struct i2c_adapter *adap) -- cgit v1.2.3 From 2db32767874fe53faff4f80de878ca19927efc1f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 23 Jun 2005 23:43:00 +0200 Subject: [PATCH] I2C: drop bogus eeprom comment This simple patch drops an out-of-date comment in the eeprom i2c chip driver. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/eeprom.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index addf0adc24d..6ea413f6d5e 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -173,9 +173,6 @@ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) | I2C_FUNC_SMBUS_BYTE)) goto exit; - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access eeprom_{read,write}_value. */ if (!(data = kmalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; -- cgit v1.2.3 From 80efa8c72006a1c04004f8fb07b22073348e4bf2 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 1 Jul 2005 00:17:27 +0200 Subject: [PATCH] I2C: SENSORS_ATXP1 must select I2C_SENSOR On Thu, Jun 30, 2005 at 11:47:09PM +0200, Sebastian Pigulak wrote: > I've tried patching linux-2.6.13-RC1 with patch-2.6.13-rc1-git2 and > building atxp1(it allows Vcore voltage changing) into the kernel. > Unfortunately, the kernel compilation stops with: > > LD init/built-in.o > LD vmlinux > drivers/built-in.o(.text+0x92298): In function `atxp1_detect': > : undefined reference to `i2c_which_vrm' > drivers/built-in.o(.text+0x921ae): In function `atxp1_attach_adapter': > : undefined reference to `i2c_detect' > make: *** [vmlinux] B??d 1 > ==> ERROR: Build Failed. Aborting... > > Could someone have a look at the module and possibly fix it up? SENSORS_ATXP1 must select I2C_SENSOR. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 5bd72c480c9..fddfc11b297 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -80,6 +80,7 @@ config SENSORS_ASB100 config SENSORS_ATXP1 tristate "Attansic ATXP1 VID controller" depends on I2C && EXPERIMENTAL + select I2C_SENSOR help If you say yes here you get support for the Attansic ATXP1 VID controller. -- cgit v1.2.3 From 0e65f82814e9828d3ff54988de9e7c0b36794daa Mon Sep 17 00:00:00 2001 From: Evgeniy Polyakov Date: Thu, 30 Jun 2005 22:52:38 +0400 Subject: [PATCH] w1: fix CRC calculation on bigendian platforms. In the 2.6.13-rc1 code the "rn" structure is in the wrong-endianness when passed to w1_attach_slave_device(). This causes problems like the family and crc being swapped around. Signed-off-by: Roger Blofeld Signed-off-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman --- drivers/w1/w1.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 312cf3220f1..8a9c4282250 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -516,6 +516,7 @@ static void w1_slave_found(unsigned long data, u64 rn) struct w1_reg_num *tmp; int family_found = 0; struct w1_master *dev; + u64 rn_le = cpu_to_le64(rn); dev = w1_search_master(data); if (!dev) { @@ -544,10 +545,8 @@ static void w1_slave_found(unsigned long data, u64 rn) slave_count++; } - rn = cpu_to_le64(rn); - if (slave_count == dev->slave_count && - rn && ((le64_to_cpu(rn) >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) { + rn && ((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn_le, 7)) { w1_attach_slave_device(dev, tmp); } -- cgit v1.2.3 From ad2f931dcb41bcfae38cc77d78b7821dfef83cf2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 2 Jul 2005 18:15:49 +0200 Subject: [PATCH] I2C: Move hwmon drivers (1/3) Part 1: Configuration files and Makefiles. From: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/hwmon/Kconfig | 420 +++++++++++++++++++++++++++++++++++++++++++++ drivers/hwmon/Makefile | 44 +++++ drivers/i2c/chips/Kconfig | 402 +------------------------------------------ drivers/i2c/chips/Makefile | 38 +--- 6 files changed, 470 insertions(+), 437 deletions(-) create mode 100644 drivers/hwmon/Kconfig create mode 100644 drivers/hwmon/Makefile (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index aed4a9b97c1..cf087de3b3a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -44,6 +44,8 @@ source "drivers/i2c/Kconfig" source "drivers/w1/Kconfig" +source "drivers/hwmon/Kconfig" + source "drivers/misc/Kconfig" source "drivers/media/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 3167be54fed..126a851d565 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_W1) += w1/ +obj-$(CONFIG_HWMON) += hwmon/ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig new file mode 100644 index 00000000000..140d5f851a5 --- /dev/null +++ b/drivers/hwmon/Kconfig @@ -0,0 +1,420 @@ +# +# I2C Sensor chip drivers configuration +# + +menu "Hardware Monitoring support" + +config HWMON + tristate "Hardware Monitoring support" + default y + help + Hardware monitoring devices let you monitor the hardware health + of a system. Most modern motherboards include such a device. It + can include temperature sensors, voltage sensors, fan speed + sensors and various additional features such as the ability to + control the speed of the fans. + +config SENSORS_ADM1021 + tristate "Analog Devices ADM1021 and compatibles" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM1021 + and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, + Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10, + and the XEON processor built-in sensor. + + This driver can also be built as a module. If so, the module + will be called adm1021. + +config SENSORS_ADM1025 + tristate "Analog Devices ADM1025 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM1025 + and Philips NE1619 sensor chips. + + This driver can also be built as a module. If so, the module + will be called adm1025. + +config SENSORS_ADM1026 + tristate "Analog Devices ADM1026 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM1026 + sensor chip. + + This driver can also be built as a module. If so, the module + will be called adm1026. + +config SENSORS_ADM1031 + tristate "Analog Devices ADM1031 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM1031 + and ADM1030 sensor chips. + + This driver can also be built as a module. If so, the module + will be called adm1031. + +config SENSORS_ADM9240 + tristate "Analog Devices ADM9240 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Analog Devices ADM9240, + Dallas DS1780, National Semiconductor LM81 sensor chips. + + This driver can also be built as a module. If so, the module + will be called adm9240. + +config SENSORS_ASB100 + tristate "Asus ASB100 Bach" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for the ASB100 Bach sensor + chip found on some Asus mainboards. + + This driver can also be built as a module. If so, the module + will be called asb100. + +config SENSORS_ATXP1 + tristate "Attansic ATXP1 VID controller" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for the Attansic ATXP1 VID + controller. + + If your board have such a chip, you are able to control your CPU + core and other voltages. + + This driver can also be built as a module. If so, the module + will be called atxp1. + +config SENSORS_DS1621 + tristate "Dallas Semiconductor DS1621 and DS1625" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Dallas Semiconductor + DS1621 and DS1625 sensor chips. + + This driver can also be built as a module. If so, the module + will be called ds1621. + +config SENSORS_FSCHER + tristate "FSC Hermes" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Fujitsu Siemens + Computers Hermes sensor chips. + + This driver can also be built as a module. If so, the module + will be called fscher. + +config SENSORS_FSCPOS + tristate "FSC Poseidon" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Fujitsu Siemens + Computers Poseidon sensor chips. + + This driver can also be built as a module. If so, the module + will be called fscpos. + +config SENSORS_GL518SM + tristate "Genesys Logic GL518SM" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for Genesys Logic GL518SM + sensor chips. + + This driver can also be built as a module. If so, the module + will be called gl518sm. + +config SENSORS_GL520SM + tristate "Genesys Logic GL520SM" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for Genesys Logic GL520SM + sensor chips. + + This driver can also be built as a module. If so, the module + will be called gl520sm. + +config SENSORS_IT87 + tristate "ITE IT87xx and compatibles" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for ITE IT87xx sensor chips + and clones: SiS960. + + This driver can also be built as a module. If so, the module + will be called it87. + +config SENSORS_LM63 + tristate "National Semiconductor LM63" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for the National Semiconductor + LM63 remote diode digital temperature sensor with integrated fan + control. Such chips are found on the Tyan S4882 (Thunder K8QS Pro) + motherboard, among others. + + This driver can also be built as a module. If so, the module + will be called lm63. + +config SENSORS_LM75 + tristate "National Semiconductor LM75 and compatibles" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM75 + sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in + 9-bit precision mode), and TelCom (now Microchip) TCN75. + + The DS75 and DS1775 in 10- to 12-bit precision modes will require + a force module parameter. The driver will not handle the extra + precision anyhow. + + This driver can also be built as a module. If so, the module + will be called lm75. + +config SENSORS_LM77 + tristate "National Semiconductor LM77" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM77 + sensor chips. + + This driver can also be built as a module. If so, the module + will be called lm77. + +config SENSORS_LM78 + tristate "National Semiconductor LM78 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM78, + LM78-J and LM79. + + This driver can also be built as a module. If so, the module + will be called lm78. + +config SENSORS_LM80 + tristate "National Semiconductor LM80" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor + LM80 sensor chips. + + This driver can also be built as a module. If so, the module + will be called lm80. + +config SENSORS_LM83 + tristate "National Semiconductor LM83" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor + LM83 sensor chips. + + This driver can also be built as a module. If so, the module + will be called lm83. + +config SENSORS_LM85 + tristate "National Semiconductor LM85 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM85 + sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027. + + This driver can also be built as a module. If so, the module + will be called lm85. + +config SENSORS_LM87 + tristate "National Semiconductor LM87" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM87 + sensor chips. + + This driver can also be built as a module. If so, the module + will be called lm87. + +config SENSORS_LM90 + tristate "National Semiconductor LM90 and compatibles" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM90, + LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and + MAX6658 sensor chips. + + The Analog Devices ADT7461 sensor chip is also supported, but only + if found in ADM1032 compatibility mode. + + This driver can also be built as a module. If so, the module + will be called lm90. + +config SENSORS_LM92 + tristate "National Semiconductor LM92 and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for National Semiconductor LM92 + and Maxim MAX6635 sensor chips. + + This driver can also be built as a module. If so, the module + will be called lm92. + +config SENSORS_MAX1619 + tristate "Maxim MAX1619 sensor chip" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for MAX1619 sensor chip. + + This driver can also be built as a module. If so, the module + will be called max1619. + +config SENSORS_PC87360 + tristate "National Semiconductor PC87360 family" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get access to the hardware monitoring + functions of the National Semiconductor PC8736x Super-I/O chips. + The PC87360, PC87363 and PC87364 only have fan monitoring and + control. The PC87365 and PC87366 additionally have voltage and + temperature monitoring. + + This driver can also be built as a module. If so, the module + will be called pc87360. + +config SENSORS_SIS5595 + tristate "Silicon Integrated Systems Corp. SiS5595" + depends on HWMON && I2C && PCI && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the integrated sensors in + SiS5595 South Bridges. + + This driver can also be built as a module. If so, the module + will be called sis5595. + +config SENSORS_SMSC47M1 + tristate "SMSC LPC47M10x and compatibles" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the integrated fan + monitoring and control capabilities of the SMSC LPC47B27x, + LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips. + + This driver can also be built as a module. If so, the module + will be called smsc47m1. + +config SENSORS_SMSC47B397 + tristate "SMSC LPC47B397-NC" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the SMSC LPC47B397-NC + sensor chip. + + This driver can also be built as a module. If so, the module + will be called smsc47b397. + +config SENSORS_VIA686A + tristate "VIA686A" + depends on HWMON && I2C && PCI + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the integrated sensors in + Via 686A/B South Bridges. + + This driver can also be built as a module. If so, the module + will be called via686a. + +config SENSORS_W83781D + tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F" + depends on HWMON && I2C + select I2C_SENSOR + help + If you say yes here you get support for the Winbond W8378x series + of sensor chips: the W83781D, W83782D, W83783S and W83627HF, + and the similar Asus AS99127F. + + This driver can also be built as a module. If so, the module + will be called w83781d. + +config SENSORS_W83L785TS + tristate "Winbond W83L785TS-S" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + help + If you say yes here you get support for the Winbond W83L785TS-S + sensor chip, which is used on the Asus A7N8X, among other + motherboards. + + This driver can also be built as a module. If so, the module + will be called w83l785ts. + +config SENSORS_W83627HF + tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get support for the Winbond W836X7 series + of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF + + This driver can also be built as a module. If so, the module + will be called w83627hf. + +config SENSORS_W83627EHF + tristate "Winbond W83627EHF" + depends on HWMON && I2C && EXPERIMENTAL + select I2C_SENSOR + select I2C_ISA + help + If you say yes here you get preliminary support for the hardware + monitoring functionality of the Winbond W83627EHF Super-I/O chip. + Only fan and temperature inputs are supported at the moment, while + the chip does much more than that. + + This driver can also be built as a module. If so, the module + will be called w83627ehf. + +config HWMON_DEBUG_CHIP + bool "Hardware Monitoring Chip debugging messages" + depends on HWMON + default n + help + Say Y here if you want the I2C chip drivers to produce a bunch of + debug messages to the system log. Select this if you are having + a problem with I2C support and want to see more of what is going + on. + +endmenu diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile new file mode 100644 index 00000000000..2781403a023 --- /dev/null +++ b/drivers/hwmon/Makefile @@ -0,0 +1,44 @@ +# +# Makefile for sensor chip drivers. +# + +# asb100, then w83781d go first, as they can override other drivers' addresses. +obj-$(CONFIG_SENSORS_ASB100) += asb100.o +obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o +obj-$(CONFIG_SENSORS_W83781D) += w83781d.o + +obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o +obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o +obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o +obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o +obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o +obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o +obj-$(CONFIG_SENSORS_DS1621) += ds1621.o +obj-$(CONFIG_SENSORS_FSCHER) += fscher.o +obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o +obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o +obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o +obj-$(CONFIG_SENSORS_IT87) += it87.o +obj-$(CONFIG_SENSORS_LM63) += lm63.o +obj-$(CONFIG_SENSORS_LM75) += lm75.o +obj-$(CONFIG_SENSORS_LM77) += lm77.o +obj-$(CONFIG_SENSORS_LM78) += lm78.o +obj-$(CONFIG_SENSORS_LM80) += lm80.o +obj-$(CONFIG_SENSORS_LM83) += lm83.o +obj-$(CONFIG_SENSORS_LM85) += lm85.o +obj-$(CONFIG_SENSORS_LM87) += lm87.o +obj-$(CONFIG_SENSORS_LM90) += lm90.o +obj-$(CONFIG_SENSORS_LM92) += lm92.o +obj-$(CONFIG_SENSORS_MAX1619) += max1619.o +obj-$(CONFIG_SENSORS_PC87360) += pc87360.o +obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o +obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o +obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o +obj-$(CONFIG_SENSORS_VIA686A) += via686a.o +obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o +obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o + +ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y) +EXTRA_CFLAGS += -DDEBUG +endif + diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index fddfc11b297..43f70dbfc03 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -1,410 +1,12 @@ # -# I2C Sensor and "other" chip configuration +# Miscellaneous I2C chip drivers configuration # -menu "Hardware Sensors Chip support" - depends on I2C - config I2C_SENSOR tristate default n -config SENSORS_ADM1021 - tristate "Analog Devices ADM1021 and compatibles" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for Analog Devices ADM1021 - and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, - Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10, - and the XEON processor built-in sensor. - - This driver can also be built as a module. If so, the module - will be called adm1021. - -config SENSORS_ADM1025 - tristate "Analog Devices ADM1025 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Analog Devices ADM1025 - and Philips NE1619 sensor chips. - - This driver can also be built as a module. If so, the module - will be called adm1025. - -config SENSORS_ADM1026 - tristate "Analog Devices ADM1026 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Analog Devices ADM1026 - sensor chip. - - This driver can also be built as a module. If so, the module - will be called adm1026. - -config SENSORS_ADM1031 - tristate "Analog Devices ADM1031 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Analog Devices ADM1031 - and ADM1030 sensor chips. - - This driver can also be built as a module. If so, the module - will be called adm1031. - -config SENSORS_ADM9240 - tristate "Analog Devices ADM9240 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Analog Devices ADM9240, - Dallas DS1780, National Semiconductor LM81 sensor chips. - - This driver can also be built as a module. If so, the module - will be called adm9240. - -config SENSORS_ASB100 - tristate "Asus ASB100 Bach" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for the ASB100 Bach sensor - chip found on some Asus mainboards. - - This driver can also be built as a module. If so, the module - will be called asb100. - -config SENSORS_ATXP1 - tristate "Attansic ATXP1 VID controller" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for the Attansic ATXP1 VID - controller. - - If your board have such a chip, you are able to control your CPU - core and other voltages. - - This driver can also be built as a module. If so, the module - will be called atxp1. - -config SENSORS_DS1621 - tristate "Dallas Semiconductor DS1621 and DS1625" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Dallas Semiconductor - DS1621 and DS1625 sensor chips. - - This driver can also be built as a module. If so, the module - will be called ds1621. - -config SENSORS_FSCHER - tristate "FSC Hermes" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Fujitsu Siemens - Computers Hermes sensor chips. - - This driver can also be built as a module. If so, the module - will be called fscher. - -config SENSORS_FSCPOS - tristate "FSC Poseidon" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Fujitsu Siemens - Computers Poseidon sensor chips. - - This driver can also be built as a module. If so, the module - will be called fscpos. - -config SENSORS_GL518SM - tristate "Genesys Logic GL518SM" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for Genesys Logic GL518SM - sensor chips. - - This driver can also be built as a module. If so, the module - will be called gl518sm. - -config SENSORS_GL520SM - tristate "Genesys Logic GL520SM" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for Genesys Logic GL520SM - sensor chips. - - This driver can also be built as a module. If so, the module - will be called gl520sm. - -config SENSORS_IT87 - tristate "ITE IT87xx and compatibles" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for ITE IT87xx sensor chips - and clones: SiS960. - - This driver can also be built as a module. If so, the module - will be called it87. - -config SENSORS_LM63 - tristate "National Semiconductor LM63" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for the National Semiconductor - LM63 remote diode digital temperature sensor with integrated fan - control. Such chips are found on the Tyan S4882 (Thunder K8QS Pro) - motherboard, among others. - - This driver can also be built as a module. If so, the module - will be called lm63. - -config SENSORS_LM75 - tristate "National Semiconductor LM75 and compatibles" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM75 - sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in - 9-bit precision mode), and TelCom (now Microchip) TCN75. - - The DS75 and DS1775 in 10- to 12-bit precision modes will require - a force module parameter. The driver will not handle the extra - precision anyhow. - - This driver can also be built as a module. If so, the module - will be called lm75. - -config SENSORS_LM77 - tristate "National Semiconductor LM77" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM77 - sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm77. - -config SENSORS_LM78 - tristate "National Semiconductor LM78 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM78, - LM78-J and LM79. - - This driver can also be built as a module. If so, the module - will be called lm78. - -config SENSORS_LM80 - tristate "National Semiconductor LM80" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor - LM80 sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm80. - -config SENSORS_LM83 - tristate "National Semiconductor LM83" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor - LM83 sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm83. - -config SENSORS_LM85 - tristate "National Semiconductor LM85 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM85 - sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027. - - This driver can also be built as a module. If so, the module - will be called lm85. - -config SENSORS_LM87 - tristate "National Semiconductor LM87" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM87 - sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm87. - -config SENSORS_LM90 - tristate "National Semiconductor LM90 and compatibles" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM90, - LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and - MAX6658 sensor chips. - - The Analog Devices ADT7461 sensor chip is also supported, but only - if found in ADM1032 compatibility mode. - - This driver can also be built as a module. If so, the module - will be called lm90. - -config SENSORS_LM92 - tristate "National Semiconductor LM92 and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for National Semiconductor LM92 - and Maxim MAX6635 sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm92. - -config SENSORS_MAX1619 - tristate "Maxim MAX1619 sensor chip" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for MAX1619 sensor chip. - - This driver can also be built as a module. If so, the module - will be called max1619. - -config SENSORS_PC87360 - tristate "National Semiconductor PC87360 family" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get access to the hardware monitoring - functions of the National Semiconductor PC8736x Super-I/O chips. - The PC87360, PC87363 and PC87364 only have fan monitoring and - control. The PC87365 and PC87366 additionally have voltage and - temperature monitoring. - - This driver can also be built as a module. If so, the module - will be called pc87360. - -config SENSORS_SMSC47B397 - tristate "SMSC LPC47B397-NC" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get support for the SMSC LPC47B397-NC - sensor chip. - - This driver can also be built as a module. If so, the module - will be called smsc47b397. - -config SENSORS_SIS5595 - tristate "Silicon Integrated Systems Corp. SiS5595" - depends on I2C && PCI && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get support for the integrated sensors in - SiS5595 South Bridges. - - This driver can also be built as a module. If so, the module - will be called sis5595. - -config SENSORS_SMSC47M1 - tristate "SMSC LPC47M10x and compatibles" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get support for the integrated fan - monitoring and control capabilities of the SMSC LPC47B27x, - LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips. - - This driver can also be built as a module. If so, the module - will be called smsc47m1. - -config SENSORS_VIA686A - tristate "VIA686A" - depends on I2C && PCI - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get support for the integrated sensors in - Via 686A/B South Bridges. - - This driver can also be built as a module. If so, the module - will be called via686a. - -config SENSORS_W83781D - tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F" - depends on I2C - select I2C_SENSOR - help - If you say yes here you get support for the Winbond W8378x series - of sensor chips: the W83781D, W83782D, W83783S and W83627HF, - and the similar Asus AS99127F. - - This driver can also be built as a module. If so, the module - will be called w83781d. - -config SENSORS_W83L785TS - tristate "Winbond W83L785TS-S" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - help - If you say yes here you get support for the Winbond W83L785TS-S - sensor chip, which is used on the Asus A7N8X, among other - motherboards. - - This driver can also be built as a module. If so, the module - will be called w83l785ts. - -config SENSORS_W83627HF - tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get support for the Winbond W836X7 series - of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF - - This driver can also be built as a module. If so, the module - will be called w83627hf. - -config SENSORS_W83627EHF - tristate "Winbond W83627EHF" - depends on I2C && EXPERIMENTAL - select I2C_SENSOR - select I2C_ISA - help - If you say yes here you get preliminary support for the hardware - monitoring functionality of the Winbond W83627EHF Super-I/O chip. - Only fan and temperature inputs are supported at the moment, while - the chip does much more than that. - - This driver can also be built as a module. If so, the module - will be called w83627ehf. - -endmenu - -menu "Other I2C Chip support" +menu "Miscellaneous I2C Chip support" depends on I2C config SENSORS_DS1337 diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index b5e6d2f84f9..a876dd42b86 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -1,52 +1,16 @@ # -# Makefile for sensor and "other" I2C chip drivers. +# Makefile for miscellaneous I2C chip drivers. # -# asb100, then w83781d go first, as they can override other drivers' addresses. -obj-$(CONFIG_SENSORS_ASB100) += asb100.o -obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o -obj-$(CONFIG_SENSORS_W83781D) += w83781d.o - -obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o -obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o -obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o -obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o -obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o -obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_DS1337) += ds1337.o obj-$(CONFIG_SENSORS_DS1374) += ds1374.o -obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o -obj-$(CONFIG_SENSORS_FSCHER) += fscher.o -obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o -obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o -obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o -obj-$(CONFIG_SENSORS_IT87) += it87.o -obj-$(CONFIG_SENSORS_LM63) += lm63.o -obj-$(CONFIG_SENSORS_LM75) += lm75.o -obj-$(CONFIG_SENSORS_LM77) += lm77.o -obj-$(CONFIG_SENSORS_LM78) += lm78.o -obj-$(CONFIG_SENSORS_LM80) += lm80.o -obj-$(CONFIG_SENSORS_LM83) += lm83.o -obj-$(CONFIG_SENSORS_LM85) += lm85.o -obj-$(CONFIG_SENSORS_LM87) += lm87.o -obj-$(CONFIG_SENSORS_LM90) += lm90.o -obj-$(CONFIG_SENSORS_LM92) += lm92.o -obj-$(CONFIG_SENSORS_MAX1619) += max1619.o obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_M41T00) += m41t00.o -obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o -obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o -obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o -obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o -obj-$(CONFIG_SENSORS_VIA686A) += via686a.o -obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o -obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o - obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TPS65010) += tps65010.o -- cgit v1.2.3 From 8d5d45fb14680326f833295f2316a4ec5e357220 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 2 Jul 2005 18:20:26 +0200 Subject: [PATCH] I2C: Move hwmon drivers (2/3) Part 2: Move the driver files themselves. Note that the patch "adds trailing whitespace", because it does move the files as-is, and some files happen to have trailing whitespace. From: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/adm1021.c | 402 ++++++++++ drivers/hwmon/adm1025.c | 577 ++++++++++++++ drivers/hwmon/adm1026.c | 1714 ++++++++++++++++++++++++++++++++++++++++ drivers/hwmon/adm1031.c | 977 +++++++++++++++++++++++ drivers/hwmon/adm9240.c | 791 ++++++++++++++++++ drivers/hwmon/asb100.c | 1065 +++++++++++++++++++++++++ drivers/hwmon/atxp1.c | 361 +++++++++ drivers/hwmon/ds1621.c | 341 ++++++++ drivers/hwmon/fscher.c | 691 ++++++++++++++++ drivers/hwmon/fscpos.c | 641 +++++++++++++++ drivers/hwmon/gl518sm.c | 604 ++++++++++++++ drivers/hwmon/gl520sm.c | 769 ++++++++++++++++++ drivers/hwmon/it87.c | 1184 +++++++++++++++++++++++++++ drivers/hwmon/lm63.c | 597 ++++++++++++++ drivers/hwmon/lm75.c | 296 +++++++ drivers/hwmon/lm75.h | 49 ++ drivers/hwmon/lm77.c | 420 ++++++++++ drivers/hwmon/lm78.c | 795 +++++++++++++++++++ drivers/hwmon/lm80.c | 601 ++++++++++++++ drivers/hwmon/lm83.c | 408 ++++++++++ drivers/hwmon/lm85.c | 1575 ++++++++++++++++++++++++++++++++++++ drivers/hwmon/lm87.c | 828 +++++++++++++++++++ drivers/hwmon/lm90.c | 655 +++++++++++++++ drivers/hwmon/lm92.c | 429 ++++++++++ drivers/hwmon/max1619.c | 372 +++++++++ drivers/hwmon/pc87360.c | 1348 +++++++++++++++++++++++++++++++ drivers/hwmon/sis5595.c | 817 +++++++++++++++++++ drivers/hwmon/smsc47b397.c | 352 +++++++++ drivers/hwmon/smsc47m1.c | 593 ++++++++++++++ drivers/hwmon/via686a.c | 875 ++++++++++++++++++++ drivers/hwmon/w83627ehf.c | 846 ++++++++++++++++++++ drivers/hwmon/w83627hf.c | 1511 +++++++++++++++++++++++++++++++++++ drivers/hwmon/w83781d.c | 1632 ++++++++++++++++++++++++++++++++++++++ drivers/hwmon/w83l785ts.c | 328 ++++++++ drivers/i2c/chips/adm1021.c | 402 ---------- drivers/i2c/chips/adm1025.c | 577 -------------- drivers/i2c/chips/adm1026.c | 1714 ---------------------------------------- drivers/i2c/chips/adm1031.c | 977 ----------------------- drivers/i2c/chips/adm9240.c | 791 ------------------ drivers/i2c/chips/asb100.c | 1065 ------------------------- drivers/i2c/chips/atxp1.c | 361 --------- drivers/i2c/chips/ds1621.c | 341 -------- drivers/i2c/chips/fscher.c | 691 ---------------- drivers/i2c/chips/fscpos.c | 641 --------------- drivers/i2c/chips/gl518sm.c | 604 -------------- drivers/i2c/chips/gl520sm.c | 769 ------------------ drivers/i2c/chips/it87.c | 1184 --------------------------- drivers/i2c/chips/lm63.c | 597 -------------- drivers/i2c/chips/lm75.c | 296 ------- drivers/i2c/chips/lm75.h | 49 -- drivers/i2c/chips/lm77.c | 420 ---------- drivers/i2c/chips/lm78.c | 795 ------------------- drivers/i2c/chips/lm80.c | 601 -------------- drivers/i2c/chips/lm83.c | 408 ---------- drivers/i2c/chips/lm85.c | 1575 ------------------------------------ drivers/i2c/chips/lm87.c | 828 ------------------- drivers/i2c/chips/lm90.c | 655 --------------- drivers/i2c/chips/lm92.c | 429 ---------- drivers/i2c/chips/max1619.c | 372 --------- drivers/i2c/chips/pc87360.c | 1348 ------------------------------- drivers/i2c/chips/sis5595.c | 817 ------------------- drivers/i2c/chips/smsc47b397.c | 352 --------- drivers/i2c/chips/smsc47m1.c | 593 -------------- drivers/i2c/chips/via686a.c | 875 -------------------- drivers/i2c/chips/w83627ehf.c | 846 -------------------- drivers/i2c/chips/w83627hf.c | 1511 ----------------------------------- drivers/i2c/chips/w83781d.c | 1632 -------------------------------------- drivers/i2c/chips/w83l785ts.c | 328 -------- 68 files changed, 25444 insertions(+), 25444 deletions(-) create mode 100644 drivers/hwmon/adm1021.c create mode 100644 drivers/hwmon/adm1025.c create mode 100644 drivers/hwmon/adm1026.c create mode 100644 drivers/hwmon/adm1031.c create mode 100644 drivers/hwmon/adm9240.c create mode 100644 drivers/hwmon/asb100.c create mode 100644 drivers/hwmon/atxp1.c create mode 100644 drivers/hwmon/ds1621.c create mode 100644 drivers/hwmon/fscher.c create mode 100644 drivers/hwmon/fscpos.c create mode 100644 drivers/hwmon/gl518sm.c create mode 100644 drivers/hwmon/gl520sm.c create mode 100644 drivers/hwmon/it87.c create mode 100644 drivers/hwmon/lm63.c create mode 100644 drivers/hwmon/lm75.c create mode 100644 drivers/hwmon/lm75.h create mode 100644 drivers/hwmon/lm77.c create mode 100644 drivers/hwmon/lm78.c create mode 100644 drivers/hwmon/lm80.c create mode 100644 drivers/hwmon/lm83.c create mode 100644 drivers/hwmon/lm85.c create mode 100644 drivers/hwmon/lm87.c create mode 100644 drivers/hwmon/lm90.c create mode 100644 drivers/hwmon/lm92.c create mode 100644 drivers/hwmon/max1619.c create mode 100644 drivers/hwmon/pc87360.c create mode 100644 drivers/hwmon/sis5595.c create mode 100644 drivers/hwmon/smsc47b397.c create mode 100644 drivers/hwmon/smsc47m1.c create mode 100644 drivers/hwmon/via686a.c create mode 100644 drivers/hwmon/w83627ehf.c create mode 100644 drivers/hwmon/w83627hf.c create mode 100644 drivers/hwmon/w83781d.c create mode 100644 drivers/hwmon/w83l785ts.c delete mode 100644 drivers/i2c/chips/adm1021.c delete mode 100644 drivers/i2c/chips/adm1025.c delete mode 100644 drivers/i2c/chips/adm1026.c delete mode 100644 drivers/i2c/chips/adm1031.c delete mode 100644 drivers/i2c/chips/adm9240.c delete mode 100644 drivers/i2c/chips/asb100.c delete mode 100644 drivers/i2c/chips/atxp1.c delete mode 100644 drivers/i2c/chips/ds1621.c delete mode 100644 drivers/i2c/chips/fscher.c delete mode 100644 drivers/i2c/chips/fscpos.c delete mode 100644 drivers/i2c/chips/gl518sm.c delete mode 100644 drivers/i2c/chips/gl520sm.c delete mode 100644 drivers/i2c/chips/it87.c delete mode 100644 drivers/i2c/chips/lm63.c delete mode 100644 drivers/i2c/chips/lm75.c delete mode 100644 drivers/i2c/chips/lm75.h delete mode 100644 drivers/i2c/chips/lm77.c delete mode 100644 drivers/i2c/chips/lm78.c delete mode 100644 drivers/i2c/chips/lm80.c delete mode 100644 drivers/i2c/chips/lm83.c delete mode 100644 drivers/i2c/chips/lm85.c delete mode 100644 drivers/i2c/chips/lm87.c delete mode 100644 drivers/i2c/chips/lm90.c delete mode 100644 drivers/i2c/chips/lm92.c delete mode 100644 drivers/i2c/chips/max1619.c delete mode 100644 drivers/i2c/chips/pc87360.c delete mode 100644 drivers/i2c/chips/sis5595.c delete mode 100644 drivers/i2c/chips/smsc47b397.c delete mode 100644 drivers/i2c/chips/smsc47m1.c delete mode 100644 drivers/i2c/chips/via686a.c delete mode 100644 drivers/i2c/chips/w83627ehf.c delete mode 100644 drivers/i2c/chips/w83627hf.c delete mode 100644 drivers/i2c/chips/w83781d.c delete mode 100644 drivers/i2c/chips/w83l785ts.c (limited to 'drivers') diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c new file mode 100644 index 00000000000..d2c774c32f4 --- /dev/null +++ b/drivers/hwmon/adm1021.c @@ -0,0 +1,402 @@ +/* + adm1021.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard and + Philip Edelbrock + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, + 0x29, 0x2a, 0x2b, + 0x4c, 0x4d, 0x4e, + I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066); + +/* adm1021 constants specified below */ + +/* The adm1021 registers */ +/* Read-only */ +#define ADM1021_REG_TEMP 0x00 +#define ADM1021_REG_REMOTE_TEMP 0x01 +#define ADM1021_REG_STATUS 0x02 +#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ +#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */ +#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ +/* These use different addresses for reading/writing */ +#define ADM1021_REG_CONFIG_R 0x03 +#define ADM1021_REG_CONFIG_W 0x09 +#define ADM1021_REG_CONV_RATE_R 0x04 +#define ADM1021_REG_CONV_RATE_W 0x0A +/* These are for the ADM1023's additional precision on the remote temp sensor */ +#define ADM1021_REG_REM_TEMP_PREC 0x010 +#define ADM1021_REG_REM_OFFSET 0x011 +#define ADM1021_REG_REM_OFFSET_PREC 0x012 +#define ADM1021_REG_REM_TOS_PREC 0x013 +#define ADM1021_REG_REM_THYST_PREC 0x014 +/* limits */ +#define ADM1021_REG_TOS_R 0x05 +#define ADM1021_REG_TOS_W 0x0B +#define ADM1021_REG_REMOTE_TOS_R 0x07 +#define ADM1021_REG_REMOTE_TOS_W 0x0D +#define ADM1021_REG_THYST_R 0x06 +#define ADM1021_REG_THYST_W 0x0C +#define ADM1021_REG_REMOTE_THYST_R 0x08 +#define ADM1021_REG_REMOTE_THYST_W 0x0E +/* write-only */ +#define ADM1021_REG_ONESHOT 0x0F + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +/* Conversions note: 1021 uses normal integer signed-byte format*/ +#define TEMP_FROM_REG(val) (val > 127 ? (val-256)*1000 : val*1000) +#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255)) + +/* Initial values */ + +/* Note: Even though I left the low and high limits named os and hyst, +they don't quite work like a thermostat the way the LM75 does. I.e., +a lower temp than THYST actually triggers an alarm instead of +clearing it. Weird, ey? --Phil */ + +/* Each client has this additional data */ +struct adm1021_data { + struct i2c_client client; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 temp_max; /* Register values */ + u8 temp_hyst; + u8 temp_input; + u8 remote_temp_max; + u8 remote_temp_hyst; + u8 remote_temp_input; + u8 alarms; + /* Special values for ADM1023 only */ + u8 remote_temp_prec; + u8 remote_temp_os_prec; + u8 remote_temp_hyst_prec; + u8 remote_temp_offset; + u8 remote_temp_offset_prec; +}; + +static int adm1021_attach_adapter(struct i2c_adapter *adapter); +static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind); +static void adm1021_init_client(struct i2c_client *client); +static int adm1021_detach_client(struct i2c_client *client); +static int adm1021_read_value(struct i2c_client *client, u8 reg); +static int adm1021_write_value(struct i2c_client *client, u8 reg, + u16 value); +static struct adm1021_data *adm1021_update_device(struct device *dev); + +/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ +static int read_only = 0; + + +/* This is the driver that will be inserted */ +static struct i2c_driver adm1021_driver = { + .owner = THIS_MODULE, + .name = "adm1021", + .id = I2C_DRIVERID_ADM1021, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm1021_attach_adapter, + .detach_client = adm1021_detach_client, +}; + +#define show(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1021_data *data = adm1021_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ +} +show(temp_max); +show(temp_hyst); +show(temp_input); +show(remote_temp_max); +show(remote_temp_hyst); +show(remote_temp_input); + +#define show2(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1021_data *data = adm1021_update_device(dev); \ + return sprintf(buf, "%d\n", data->value); \ +} +show2(alarms); + +#define set(value, reg) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1021_data *data = i2c_get_clientdata(client); \ + int temp = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_TO_REG(temp); \ + adm1021_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} +set(temp_max, ADM1021_REG_TOS_W); +set(temp_hyst, ADM1021_REG_THYST_W); +set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W); +set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W); + +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); +static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); +static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max); +static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst); +static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + + +static int adm1021_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, adm1021_detect); +} + +static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i; + struct i2c_client *new_client; + struct adm1021_data *data; + int err = 0; + const char *type_name = ""; + + /* Make sure we aren't probing the ISA bus!! This is just a safety check + at this moment; i2c_detect really won't call us. */ +#ifdef DEBUG + if (i2c_is_isa_adapter(adapter)) { + dev_dbg(&adapter->dev, "adm1021_detect called for an ISA bus adapter?!?\n"); + return 0; + } +#endif + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto error0; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access adm1021_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { + err = -ENOMEM; + goto error0; + } + memset(data, 0, sizeof(struct adm1021_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm1021_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + if (kind < 0) { + if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00 + || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00 + || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) { + err = -ENODEV; + goto error1; + } + } + + /* Determine the chip type. */ + if (kind <= 0) { + i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID); + if (i == 0x41) + if ((adm1021_read_value(new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030) + kind = adm1023; + else + kind = adm1021; + else if (i == 0x49) + kind = thmc10; + else if (i == 0x23) + kind = gl523sm; + else if ((i == 0x4d) && + (adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01)) + kind = max1617a; + else if (i == 0x54) + kind = mc1066; + /* LM84 Mfr ID in a different place, and it has more unused bits */ + else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00 + && (kind == 0 /* skip extra detection */ + || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00 + && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00))) + kind = lm84; + else + kind = max1617; + } + + if (kind == max1617) { + type_name = "max1617"; + } else if (kind == max1617a) { + type_name = "max1617a"; + } else if (kind == adm1021) { + type_name = "adm1021"; + } else if (kind == adm1023) { + type_name = "adm1023"; + } else if (kind == thmc10) { + type_name = "thmc10"; + } else if (kind == lm84) { + type_name = "lm84"; + } else if (kind == gl523sm) { + type_name = "gl523sm"; + } else if (kind == mc1066) { + type_name = "mc1066"; + } + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, type_name, I2C_NAME_SIZE); + data->type = kind; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto error1; + + /* Initialize the ADM1021 chip */ + if (kind != lm84) + adm1021_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +error1: + kfree(data); +error0: + return err; +} + +static void adm1021_init_client(struct i2c_client *client) +{ + /* Enable ADC and disable suspend mode */ + adm1021_write_value(client, ADM1021_REG_CONFIG_W, + adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF); + /* Set Conversion rate to 1/sec (this can be tinkered with) */ + adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); +} + +static int adm1021_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +/* All registers are byte-sized */ +static int adm1021_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (!read_only) + return i2c_smbus_write_byte_data(client, reg, value); + return 0; +} + +static struct adm1021_data *adm1021_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1021_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting adm1021 update\n"); + + data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP); + data->temp_max = adm1021_read_value(client, ADM1021_REG_TOS_R); + data->temp_hyst = adm1021_read_value(client, ADM1021_REG_THYST_R); + data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP); + data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); + data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); + data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c; + if (data->type == adm1023) { + data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); + data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); + data->remote_temp_hyst_prec = adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC); + data->remote_temp_offset = adm1021_read_value(client, ADM1021_REG_REM_OFFSET); + data->remote_temp_offset_prec = adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC); + } + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_adm1021_init(void) +{ + return i2c_add_driver(&adm1021_driver); +} + +static void __exit sensors_adm1021_exit(void) +{ + i2c_del_driver(&adm1021_driver); +} + +MODULE_AUTHOR ("Frodo Looijaard and " + "Philip Edelbrock "); +MODULE_DESCRIPTION("adm1021 driver"); +MODULE_LICENSE("GPL"); + +module_param(read_only, bool, 0); +MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); + +module_init(sensors_adm1021_init) +module_exit(sensors_adm1021_exit) diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c new file mode 100644 index 00000000000..e452d0daf90 --- /dev/null +++ b/drivers/hwmon/adm1025.c @@ -0,0 +1,577 @@ +/* + * adm1025.c + * + * Copyright (C) 2000 Chen-Yuan Wu + * Copyright (C) 2003-2004 Jean Delvare + * + * The ADM1025 is a sensor chip made by Analog Devices. It reports up to 6 + * voltages (including its own power source) and up to two temperatures + * (its own plus up to one external one). Voltages are scaled internally + * (which is not the common way) with ratios such that the nominal value + * of each voltage correspond to a register value of 192 (which means a + * resolution of about 0.5% of the nominal value). Temperature values are + * reported with a 1 deg resolution and a 3 deg accuracy. Complete + * datasheet can be obtained from Analog's website at: + * http://www.analog.com/Analog_Root/productPage/productHome/0,2121,ADM1025,00.html + * + * This driver also supports the ADM1025A, which differs from the ADM1025 + * only in that it has "open-drain VID inputs while the ADM1025 has + * on-chip 100k pull-ups on the VID inputs". It doesn't make any + * difference for us. + * + * This driver also supports the NE1619, a sensor chip made by Philips. + * That chip is similar to the ADM1025A, with a few differences. The only + * difference that matters to us is that the NE1619 has only two possible + * addresses while the ADM1025A has a third one. Complete datasheet can be + * obtained from Philips's website at: + * http://www.semiconductors.philips.com/pip/NE1619DS.html + * + * Since the ADM1025 was the first chipset supported by this driver, most + * comments will refer to this chipset, but are actually general and + * concern all supported chipsets, unless mentioned otherwise. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan + * ADM1025 and ADM1025A have three possible addresses: 0x2c, 0x2d and 0x2e. + * NE1619 has two possible addresses: 0x2c and 0x2d. + */ + +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_2(adm1025, ne1619); + +/* + * The ADM1025 registers + */ + +#define ADM1025_REG_MAN_ID 0x3E +#define ADM1025_REG_CHIP_ID 0x3F +#define ADM1025_REG_CONFIG 0x40 +#define ADM1025_REG_STATUS1 0x41 +#define ADM1025_REG_STATUS2 0x42 +#define ADM1025_REG_IN(nr) (0x20 + (nr)) +#define ADM1025_REG_IN_MAX(nr) (0x2B + (nr) * 2) +#define ADM1025_REG_IN_MIN(nr) (0x2C + (nr) * 2) +#define ADM1025_REG_TEMP(nr) (0x26 + (nr)) +#define ADM1025_REG_TEMP_HIGH(nr) (0x37 + (nr) * 2) +#define ADM1025_REG_TEMP_LOW(nr) (0x38 + (nr) * 2) +#define ADM1025_REG_VID 0x47 +#define ADM1025_REG_VID4 0x49 + +/* + * Conversions and various macros + * The ADM1025 uses signed 8-bit values for temperatures. + */ + +static int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 }; + +#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) +#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ + (val) * 192 >= (scale) * 255 ? 255 : \ + ((val) * 192 + (scale)/2) / (scale)) + +#define TEMP_FROM_REG(reg) ((reg) * 1000) +#define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \ + (val) >= 126500 ? 127 : \ + (((val) < 0 ? (val)-500 : (val)+500) / 1000)) + +/* + * Functions declaration + */ + +static int adm1025_attach_adapter(struct i2c_adapter *adapter); +static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind); +static void adm1025_init_client(struct i2c_client *client); +static int adm1025_detach_client(struct i2c_client *client); +static struct adm1025_data *adm1025_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver adm1025_driver = { + .owner = THIS_MODULE, + .name = "adm1025", + .id = I2C_DRIVERID_ADM1025, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm1025_attach_adapter, + .detach_client = adm1025_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct adm1025_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + u8 in[6]; /* register value */ + u8 in_max[6]; /* register value */ + u8 in_min[6]; /* register value */ + s8 temp[2]; /* register value */ + s8 temp_min[2]; /* register value */ + s8 temp_max[2]; /* register value */ + u16 alarms; /* register values, combined */ + u8 vid; /* register values, combined */ + u8 vrm; +}; + +/* + * Sysfs stuff + */ + +#define show_in(offset) \ +static ssize_t show_in##offset(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ + in_scale[offset])); \ +} \ +static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ + in_scale[offset])); \ +} \ +static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ + in_scale[offset])); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); +show_in(0); +show_in(1); +show_in(2); +show_in(3); +show_in(4); +show_in(5); + +#define show_temp(offset) \ +static ssize_t show_temp##offset(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ +} \ +static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ +} \ +static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct adm1025_data *data = adm1025_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ +}\ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp##offset, NULL); +show_temp(1); +show_temp(2); + +#define set_in(offset) \ +static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_min[offset] = IN_TO_REG(val, in_scale[offset]); \ + i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \ + data->in_min[offset]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_max[offset] = IN_TO_REG(val, in_scale[offset]); \ + i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \ + data->in_max[offset]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ + show_in##offset##_max, set_in##offset##_max); +set_in(0); +set_in(1); +set_in(2); +set_in(3); +set_in(4); +set_in(5); + +#define set_temp(offset) \ +static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp_min[offset-1] = TEMP_TO_REG(val); \ + i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \ + data->temp_min[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1025_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp_max[offset-1] = TEMP_TO_REG(val); \ + i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \ + data->temp_max[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ + show_temp##offset##_min, set_temp##offset##_min); \ +static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ + show_temp##offset##_max, set_temp##offset##_max); +set_temp(1); +set_temp(2); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); +} +/* in1_ref is deprecated in favour of cpu0_vid, remove after 2005-11-11 */ +static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", data->vrm); +} +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + data->vrm = simple_strtoul(buf, NULL, 10); + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); + +/* + * Real code + */ + +static int adm1025_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, adm1025_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct adm1025_data *data; + int err = 0; + const char *name = ""; + u8 config; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct adm1025_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct adm1025_data)); + + /* The common I2C client data is placed right before the + ADM1025-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm1025_driver; + new_client->flags = 0; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip. A zero kind means that + * the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + config = i2c_smbus_read_byte_data(new_client, ADM1025_REG_CONFIG); + if (kind < 0) { /* detection */ + if ((config & 0x80) != 0x00 + || (i2c_smbus_read_byte_data(new_client, + ADM1025_REG_STATUS1) & 0xC0) != 0x00 + || (i2c_smbus_read_byte_data(new_client, + ADM1025_REG_STATUS2) & 0xBC) != 0x00) { + dev_dbg(&adapter->dev, + "ADM1025 detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + u8 man_id, chip_id; + + man_id = i2c_smbus_read_byte_data(new_client, + ADM1025_REG_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + ADM1025_REG_CHIP_ID); + + if (man_id == 0x41) { /* Analog Devices */ + if ((chip_id & 0xF0) == 0x20) { /* ADM1025/ADM1025A */ + kind = adm1025; + } + } else + if (man_id == 0xA1) { /* Philips */ + if (address != 0x2E + && (chip_id & 0xF0) == 0x20) { /* NE1619 */ + kind = ne1619; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%02X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + } + + if (kind == adm1025) { + name = "adm1025"; + } else if (kind == ne1619) { + name = "ne1619"; + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the ADM1025 chip */ + adm1025_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_alarms); + /* in1_ref is deprecated, remove after 2005-11-11 */ + device_create_file(&new_client->dev, &dev_attr_in1_ref); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + device_create_file(&new_client->dev, &dev_attr_vrm); + + /* Pin 11 is either in4 (+12V) or VID4 */ + if (!(config & 0x20)) { + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + } + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static void adm1025_init_client(struct i2c_client *client) +{ + u8 reg; + struct adm1025_data *data = i2c_get_clientdata(client); + int i; + + data->vrm = i2c_which_vrm(); + + /* + * Set high limits + * Usually we avoid setting limits on driver init, but it happens + * that the ADM1025 comes with stupid default limits (all registers + * set to 0). In case the chip has not gone through any limit + * setting yet, we better set the high limits to the max so that + * no alarm triggers. + */ + for (i=0; i<6; i++) { + reg = i2c_smbus_read_byte_data(client, + ADM1025_REG_IN_MAX(i)); + if (reg == 0) + i2c_smbus_write_byte_data(client, + ADM1025_REG_IN_MAX(i), + 0xFF); + } + for (i=0; i<2; i++) { + reg = i2c_smbus_read_byte_data(client, + ADM1025_REG_TEMP_HIGH(i)); + if (reg == 0) + i2c_smbus_write_byte_data(client, + ADM1025_REG_TEMP_HIGH(i), + 0x7F); + } + + /* + * Start the conversions + */ + reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); + if (!(reg & 0x01)) + i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG, + (reg&0x7E)|0x01); +} + +static int adm1025_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static struct adm1025_data *adm1025_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + int i; + + dev_dbg(&client->dev, "Updating data.\n"); + for (i=0; i<6; i++) { + data->in[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_IN(i)); + data->in_min[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_IN_MIN(i)); + data->in_max[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_IN_MAX(i)); + } + for (i=0; i<2; i++) { + data->temp[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_TEMP(i)); + data->temp_min[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_TEMP_LOW(i)); + data->temp_max[i] = i2c_smbus_read_byte_data(client, + ADM1025_REG_TEMP_HIGH(i)); + } + data->alarms = i2c_smbus_read_byte_data(client, + ADM1025_REG_STATUS1) + | (i2c_smbus_read_byte_data(client, + ADM1025_REG_STATUS2) << 8); + data->vid = (i2c_smbus_read_byte_data(client, + ADM1025_REG_VID) & 0x0f) + | ((i2c_smbus_read_byte_data(client, + ADM1025_REG_VID4) & 0x01) << 4); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_adm1025_init(void) +{ + return i2c_add_driver(&adm1025_driver); +} + +static void __exit sensors_adm1025_exit(void) +{ + i2c_del_driver(&adm1025_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("ADM1025 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_adm1025_init); +module_exit(sensors_adm1025_exit); diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c new file mode 100644 index 00000000000..3c85fe150cd --- /dev/null +++ b/drivers/hwmon/adm1026.c @@ -0,0 +1,1714 @@ +/* + adm1026.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (C) 2002, 2003 Philip Pokorny + Copyright (C) 2004 Justin Thiessen + + Chip details at: + + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(adm1026); + +static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; +module_param_array(gpio_input,int,NULL,0); +MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs"); +module_param_array(gpio_output,int,NULL,0); +MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as " + "outputs"); +module_param_array(gpio_inverted,int,NULL,0); +MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as " + "inverted"); +module_param_array(gpio_normal,int,NULL,0); +MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as " + "normal/non-inverted"); +module_param_array(gpio_fan,int,NULL,0); +MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs"); + +/* Many ADM1026 constants specified below */ + +/* The ADM1026 registers */ +#define ADM1026_REG_CONFIG1 0x00 +#define CFG1_MONITOR 0x01 +#define CFG1_INT_ENABLE 0x02 +#define CFG1_INT_CLEAR 0x04 +#define CFG1_AIN8_9 0x08 +#define CFG1_THERM_HOT 0x10 +#define CFG1_DAC_AFC 0x20 +#define CFG1_PWM_AFC 0x40 +#define CFG1_RESET 0x80 +#define ADM1026_REG_CONFIG2 0x01 +/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */ +#define ADM1026_REG_CONFIG3 0x07 +#define CFG3_GPIO16_ENABLE 0x01 +#define CFG3_CI_CLEAR 0x02 +#define CFG3_VREF_250 0x04 +#define CFG3_GPIO16_DIR 0x40 +#define CFG3_GPIO16_POL 0x80 +#define ADM1026_REG_E2CONFIG 0x13 +#define E2CFG_READ 0x01 +#define E2CFG_WRITE 0x02 +#define E2CFG_ERASE 0x04 +#define E2CFG_ROM 0x08 +#define E2CFG_CLK_EXT 0x80 + +/* There are 10 general analog inputs and 7 dedicated inputs + * They are: + * 0 - 9 = AIN0 - AIN9 + * 10 = Vbat + * 11 = 3.3V Standby + * 12 = 3.3V Main + * 13 = +5V + * 14 = Vccp (CPU core voltage) + * 15 = +12V + * 16 = -12V + */ +static u16 ADM1026_REG_IN[] = { + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x27, 0x29, 0x26, 0x2a, + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f + }; +static u16 ADM1026_REG_IN_MIN[] = { + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, + 0x5e, 0x5f, 0x6d, 0x49, 0x6b, 0x4a, + 0x4b, 0x4c, 0x4d, 0x4e, 0x4f + }; +static u16 ADM1026_REG_IN_MAX[] = { + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x6c, 0x41, 0x6a, 0x42, + 0x43, 0x44, 0x45, 0x46, 0x47 + }; + +/* Temperatures are: + * 0 - Internal + * 1 - External 1 + * 2 - External 2 + */ +static u16 ADM1026_REG_TEMP[] = { 0x1f, 0x28, 0x29 }; +static u16 ADM1026_REG_TEMP_MIN[] = { 0x69, 0x48, 0x49 }; +static u16 ADM1026_REG_TEMP_MAX[] = { 0x68, 0x40, 0x41 }; +static u16 ADM1026_REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 }; +static u16 ADM1026_REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f }; +static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f }; + +#define ADM1026_REG_FAN(nr) (0x38 + (nr)) +#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr)) +#define ADM1026_REG_FAN_DIV_0_3 0x02 +#define ADM1026_REG_FAN_DIV_4_7 0x03 + +#define ADM1026_REG_DAC 0x04 +#define ADM1026_REG_PWM 0x05 + +#define ADM1026_REG_GPIO_CFG_0_3 0x08 +#define ADM1026_REG_GPIO_CFG_4_7 0x09 +#define ADM1026_REG_GPIO_CFG_8_11 0x0a +#define ADM1026_REG_GPIO_CFG_12_15 0x0b +/* CFG_16 in REG_CFG3 */ +#define ADM1026_REG_GPIO_STATUS_0_7 0x24 +#define ADM1026_REG_GPIO_STATUS_8_15 0x25 +/* STATUS_16 in REG_STATUS4 */ +#define ADM1026_REG_GPIO_MASK_0_7 0x1c +#define ADM1026_REG_GPIO_MASK_8_15 0x1d +/* MASK_16 in REG_MASK4 */ + +#define ADM1026_REG_COMPANY 0x16 +#define ADM1026_REG_VERSTEP 0x17 +/* These are the recognized values for the above regs */ +#define ADM1026_COMPANY_ANALOG_DEV 0x41 +#define ADM1026_VERSTEP_GENERIC 0x40 +#define ADM1026_VERSTEP_ADM1026 0x44 + +#define ADM1026_REG_MASK1 0x18 +#define ADM1026_REG_MASK2 0x19 +#define ADM1026_REG_MASK3 0x1a +#define ADM1026_REG_MASK4 0x1b + +#define ADM1026_REG_STATUS1 0x20 +#define ADM1026_REG_STATUS2 0x21 +#define ADM1026_REG_STATUS3 0x22 +#define ADM1026_REG_STATUS4 0x23 + +#define ADM1026_FAN_ACTIVATION_TEMP_HYST -6 +#define ADM1026_FAN_CONTROL_TEMP_RANGE 20 +#define ADM1026_PWM_MAX 255 + +/* Conversions. Rounding and limit checking is only done on the TO_REG + * variants. Note that you should be a bit careful with which arguments + * these macros are called: arguments may be evaluated more than once. + */ + +/* IN are scaled acording to built-in resistors. These are the + * voltages corresponding to 3/4 of full scale (192 or 0xc0) + * NOTE: The -12V input needs an additional factor to account + * for the Vref pullup resistor. + * NEG12_OFFSET = SCALE * Vref / V-192 - Vref + * = 13875 * 2.50 / 1.875 - 2500 + * = 16000 + * + * The values in this table are based on Table II, page 15 of the + * datasheet. + */ +static int adm1026_scaling[] = { /* .001 Volts */ + 2250, 2250, 2250, 2250, 2250, 2250, + 1875, 1875, 1875, 1875, 3000, 3330, + 3330, 4995, 2250, 12000, 13875 + }; +#define NEG12_OFFSET 16000 +#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) +#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),\ + 0,255)) +#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n])) + +/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses + * and we assume a 2 pulse-per-rev fan tach signal + * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000 + */ +#define FAN_TO_REG(val,div) ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*\ + (div)),1,254)) +#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*\ + (div))) +#define DIV_FROM_REG(val) (1<<(val)) +#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0) + +/* Temperature is reported in 1 degC increments */ +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ + -127,127)) +#define TEMP_FROM_REG(val) ((val) * 1000) +#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ + -127,127)) +#define OFFSET_FROM_REG(val) ((val) * 1000) + +#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) +#define PWM_FROM_REG(val) (val) + +#define PWM_MIN_TO_REG(val) ((val) & 0xf0) +#define PWM_MIN_FROM_REG(val) (((val) & 0xf0) + ((val) >> 4)) + +/* Analog output is a voltage, and scaled to millivolts. The datasheet + * indicates that the DAC could be used to drive the fans, but in our + * example board (Arima HDAMA) it isn't connected to the fans at all. + */ +#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val)*255)+500)/2500),0,255)) +#define DAC_FROM_REG(val) (((val)*2500)/255) + +/* Typically used with systems using a v9.1 VRM spec ? */ +#define ADM1026_INIT_VRM 91 + +/* Chip sampling rates + * + * Some sensors are not updated more frequently than once per second + * so it doesn't make sense to read them more often than that. + * We cache the results and return the saved data if the driver + * is called again before a second has elapsed. + * + * Also, there is significant configuration data for this chip + * So, we keep the config data up to date in the cache + * when it is written and only sample it once every 5 *minutes* + */ +#define ADM1026_DATA_INTERVAL (1 * HZ) +#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ) + +/* We allow for multiple chips in a single system. + * + * For each registered ADM1026, we need to keep state information + * at client->data. The adm1026_data structure is dynamically + * allocated, when a new client structure is allocated. */ + +struct pwm_data { + u8 pwm; + u8 enable; + u8 auto_pwm_min; +}; + +struct adm1026_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + int valid; /* !=0 if following fields are valid */ + unsigned long last_reading; /* In jiffies */ + unsigned long last_config; /* In jiffies */ + + u8 in[17]; /* Register value */ + u8 in_max[17]; /* Register value */ + u8 in_min[17]; /* Register value */ + s8 temp[3]; /* Register value */ + s8 temp_min[3]; /* Register value */ + s8 temp_max[3]; /* Register value */ + s8 temp_tmin[3]; /* Register value */ + s8 temp_crit[3]; /* Register value */ + s8 temp_offset[3]; /* Register value */ + u8 fan[8]; /* Register value */ + u8 fan_min[8]; /* Register value */ + u8 fan_div[8]; /* Decoded value */ + struct pwm_data pwm1; /* Pwm control values */ + int vid; /* Decoded value */ + u8 vrm; /* VRM version */ + u8 analog_out; /* Register value (DAC) */ + long alarms; /* Register encoding, combined */ + long alarm_mask; /* Register encoding, combined */ + long gpio; /* Register encoding, combined */ + long gpio_mask; /* Register encoding, combined */ + u8 gpio_config[17]; /* Decoded value */ + u8 config1; /* Register value */ + u8 config2; /* Register value */ + u8 config3; /* Register value */ +}; + +static int adm1026_attach_adapter(struct i2c_adapter *adapter); +static int adm1026_detect(struct i2c_adapter *adapter, int address, + int kind); +static int adm1026_detach_client(struct i2c_client *client); +static int adm1026_read_value(struct i2c_client *client, u8 register); +static int adm1026_write_value(struct i2c_client *client, u8 register, + int value); +static void adm1026_print_gpio(struct i2c_client *client); +static void adm1026_fixup_gpio(struct i2c_client *client); +static struct adm1026_data *adm1026_update_device(struct device *dev); +static void adm1026_init_client(struct i2c_client *client); + + +static struct i2c_driver adm1026_driver = { + .owner = THIS_MODULE, + .name = "adm1026", + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm1026_attach_adapter, + .detach_client = adm1026_detach_client, +}; + +int adm1026_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) { + return 0; + } + return i2c_detect(adapter, &addr_data, adm1026_detect); +} + +int adm1026_detach_client(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(client); + return 0; +} + +int adm1026_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + if (reg < 0x80) { + /* "RAM" locations */ + res = i2c_smbus_read_byte_data(client, reg) & 0xff; + } else { + /* EEPROM, do nothing */ + res = 0; + } + return res; +} + +int adm1026_write_value(struct i2c_client *client, u8 reg, int value) +{ + int res; + + if (reg < 0x80) { + /* "RAM" locations */ + res = i2c_smbus_write_byte_data(client, reg, value); + } else { + /* EEPROM, do nothing */ + res = 0; + } + return res; +} + +void adm1026_init_client(struct i2c_client *client) +{ + int value, i; + struct adm1026_data *data = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "Initializing device\n"); + /* Read chip config */ + data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1); + data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2); + data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3); + + /* Inform user of chip config */ + dev_dbg(&client->dev, "ADM1026_REG_CONFIG1 is: 0x%02x\n", + data->config1); + if ((data->config1 & CFG1_MONITOR) == 0) { + dev_dbg(&client->dev, "Monitoring not currently " + "enabled.\n"); + } + if (data->config1 & CFG1_INT_ENABLE) { + dev_dbg(&client->dev, "SMBALERT interrupts are " + "enabled.\n"); + } + if (data->config1 & CFG1_AIN8_9) { + dev_dbg(&client->dev, "in8 and in9 enabled. " + "temp3 disabled.\n"); + } else { + dev_dbg(&client->dev, "temp3 enabled. in8 and " + "in9 disabled.\n"); + } + if (data->config1 & CFG1_THERM_HOT) { + dev_dbg(&client->dev, "Automatic THERM, PWM, " + "and temp limits enabled.\n"); + } + + value = data->config3; + if (data->config3 & CFG3_GPIO16_ENABLE) { + dev_dbg(&client->dev, "GPIO16 enabled. THERM" + "pin disabled.\n"); + } else { + dev_dbg(&client->dev, "THERM pin enabled. " + "GPIO16 disabled.\n"); + } + if (data->config3 & CFG3_VREF_250) { + dev_dbg(&client->dev, "Vref is 2.50 Volts.\n"); + } else { + dev_dbg(&client->dev, "Vref is 1.82 Volts.\n"); + } + /* Read and pick apart the existing GPIO configuration */ + value = 0; + for (i = 0;i <= 15;++i) { + if ((i & 0x03) == 0) { + value = adm1026_read_value(client, + ADM1026_REG_GPIO_CFG_0_3 + i/4); + } + data->gpio_config[i] = value & 0x03; + value >>= 2; + } + data->gpio_config[16] = (data->config3 >> 6) & 0x03; + + /* ... and then print it */ + adm1026_print_gpio(client); + + /* If the user asks us to reprogram the GPIO config, then + * do it now. + */ + if (gpio_input[0] != -1 || gpio_output[0] != -1 + || gpio_inverted[0] != -1 || gpio_normal[0] != -1 + || gpio_fan[0] != -1) { + adm1026_fixup_gpio(client); + } + + /* WE INTENTIONALLY make no changes to the limits, + * offsets, pwms, fans and zones. If they were + * configured, we don't want to mess with them. + * If they weren't, the default is 100% PWM, no + * control and will suffice until 'sensors -s' + * can be run by the user. We DO set the default + * value for pwm1.auto_pwm_min to its maximum + * so that enabling automatic pwm fan control + * without first setting a value for pwm1.auto_pwm_min + * will not result in potentially dangerous fan speed decrease. + */ + data->pwm1.auto_pwm_min=255; + /* Start monitoring */ + value = adm1026_read_value(client, ADM1026_REG_CONFIG1); + /* Set MONITOR, clear interrupt acknowledge and s/w reset */ + value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET); + dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value); + data->config1 = value; + adm1026_write_value(client, ADM1026_REG_CONFIG1, value); + + /* initialize fan_div[] to hardware defaults */ + value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) | + (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8); + for (i = 0;i <= 7;++i) { + data->fan_div[i] = DIV_FROM_REG(value & 0x03); + value >>= 2; + } +} + +void adm1026_print_gpio(struct i2c_client *client) +{ + struct adm1026_data *data = i2c_get_clientdata(client); + int i; + + dev_dbg(&client->dev, "GPIO config is:"); + for (i = 0;i <= 7;++i) { + if (data->config2 & (1 << i)) { + dev_dbg(&client->dev, "\t%sGP%s%d\n", + data->gpio_config[i] & 0x02 ? "" : "!", + data->gpio_config[i] & 0x01 ? "OUT" : "IN", + i); + } else { + dev_dbg(&client->dev, "\tFAN%d\n", i); + } + } + for (i = 8;i <= 15;++i) { + dev_dbg(&client->dev, "\t%sGP%s%d\n", + data->gpio_config[i] & 0x02 ? "" : "!", + data->gpio_config[i] & 0x01 ? "OUT" : "IN", + i); + } + if (data->config3 & CFG3_GPIO16_ENABLE) { + dev_dbg(&client->dev, "\t%sGP%s16\n", + data->gpio_config[16] & 0x02 ? "" : "!", + data->gpio_config[16] & 0x01 ? "OUT" : "IN"); + } else { + /* GPIO16 is THERM */ + dev_dbg(&client->dev, "\tTHERM\n"); + } +} + +void adm1026_fixup_gpio(struct i2c_client *client) +{ + struct adm1026_data *data = i2c_get_clientdata(client); + int i; + int value; + + /* Make the changes requested. */ + /* We may need to unlock/stop monitoring or soft-reset the + * chip before we can make changes. This hasn't been + * tested much. FIXME + */ + + /* Make outputs */ + for (i = 0;i <= 16;++i) { + if (gpio_output[i] >= 0 && gpio_output[i] <= 16) { + data->gpio_config[gpio_output[i]] |= 0x01; + } + /* if GPIO0-7 is output, it isn't a FAN tach */ + if (gpio_output[i] >= 0 && gpio_output[i] <= 7) { + data->config2 |= 1 << gpio_output[i]; + } + } + + /* Input overrides output */ + for (i = 0;i <= 16;++i) { + if (gpio_input[i] >= 0 && gpio_input[i] <= 16) { + data->gpio_config[gpio_input[i]] &= ~ 0x01; + } + /* if GPIO0-7 is input, it isn't a FAN tach */ + if (gpio_input[i] >= 0 && gpio_input[i] <= 7) { + data->config2 |= 1 << gpio_input[i]; + } + } + + /* Inverted */ + for (i = 0;i <= 16;++i) { + if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16) { + data->gpio_config[gpio_inverted[i]] &= ~ 0x02; + } + } + + /* Normal overrides inverted */ + for (i = 0;i <= 16;++i) { + if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16) { + data->gpio_config[gpio_normal[i]] |= 0x02; + } + } + + /* Fan overrides input and output */ + for (i = 0;i <= 7;++i) { + if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7) { + data->config2 &= ~(1 << gpio_fan[i]); + } + } + + /* Write new configs to registers */ + adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2); + data->config3 = (data->config3 & 0x3f) + | ((data->gpio_config[16] & 0x03) << 6); + adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3); + for (i = 15, value = 0;i >= 0;--i) { + value <<= 2; + value |= data->gpio_config[i] & 0x03; + if ((i & 0x03) == 0) { + adm1026_write_value(client, + ADM1026_REG_GPIO_CFG_0_3 + i/4, + value); + value = 0; + } + } + + /* Print the new config */ + adm1026_print_gpio(client); +} + + +static struct adm1026_data *adm1026_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int i; + long value, alarms, gpio; + + down(&data->update_lock); + if (!data->valid + || time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) { + /* Things that change quickly */ + dev_dbg(&client->dev,"Reading sensor values\n"); + for (i = 0;i <= 16;++i) { + data->in[i] = + adm1026_read_value(client, ADM1026_REG_IN[i]); + } + + for (i = 0;i <= 7;++i) { + data->fan[i] = + adm1026_read_value(client, ADM1026_REG_FAN(i)); + } + + for (i = 0;i <= 2;++i) { + /* NOTE: temp[] is s8 and we assume 2's complement + * "conversion" in the assignment */ + data->temp[i] = + adm1026_read_value(client, ADM1026_REG_TEMP[i]); + } + + data->pwm1.pwm = adm1026_read_value(client, + ADM1026_REG_PWM); + data->analog_out = adm1026_read_value(client, + ADM1026_REG_DAC); + /* GPIO16 is MSbit of alarms, move it to gpio */ + alarms = adm1026_read_value(client, ADM1026_REG_STATUS4); + gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ + alarms &= 0x7f; + alarms <<= 8; + alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3); + alarms <<= 8; + alarms |= adm1026_read_value(client, ADM1026_REG_STATUS2); + alarms <<= 8; + alarms |= adm1026_read_value(client, ADM1026_REG_STATUS1); + data->alarms = alarms; + + /* Read the GPIO values */ + gpio |= adm1026_read_value(client, + ADM1026_REG_GPIO_STATUS_8_15); + gpio <<= 8; + gpio |= adm1026_read_value(client, + ADM1026_REG_GPIO_STATUS_0_7); + data->gpio = gpio; + + data->last_reading = jiffies; + }; /* last_reading */ + + if (!data->valid || + time_after(jiffies, data->last_config + ADM1026_CONFIG_INTERVAL)) { + /* Things that don't change often */ + dev_dbg(&client->dev, "Reading config values\n"); + for (i = 0;i <= 16;++i) { + data->in_min[i] = adm1026_read_value(client, + ADM1026_REG_IN_MIN[i]); + data->in_max[i] = adm1026_read_value(client, + ADM1026_REG_IN_MAX[i]); + } + + value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) + | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) + << 8); + for (i = 0;i <= 7;++i) { + data->fan_min[i] = adm1026_read_value(client, + ADM1026_REG_FAN_MIN(i)); + data->fan_div[i] = DIV_FROM_REG(value & 0x03); + value >>= 2; + } + + for (i = 0; i <= 2; ++i) { + /* NOTE: temp_xxx[] are s8 and we assume 2's + * complement "conversion" in the assignment + */ + data->temp_min[i] = adm1026_read_value(client, + ADM1026_REG_TEMP_MIN[i]); + data->temp_max[i] = adm1026_read_value(client, + ADM1026_REG_TEMP_MAX[i]); + data->temp_tmin[i] = adm1026_read_value(client, + ADM1026_REG_TEMP_TMIN[i]); + data->temp_crit[i] = adm1026_read_value(client, + ADM1026_REG_TEMP_THERM[i]); + data->temp_offset[i] = adm1026_read_value(client, + ADM1026_REG_TEMP_OFFSET[i]); + } + + /* Read the STATUS/alarm masks */ + alarms = adm1026_read_value(client, ADM1026_REG_MASK4); + gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ + alarms = (alarms & 0x7f) << 8; + alarms |= adm1026_read_value(client, ADM1026_REG_MASK3); + alarms <<= 8; + alarms |= adm1026_read_value(client, ADM1026_REG_MASK2); + alarms <<= 8; + alarms |= adm1026_read_value(client, ADM1026_REG_MASK1); + data->alarm_mask = alarms; + + /* Read the GPIO values */ + gpio |= adm1026_read_value(client, + ADM1026_REG_GPIO_MASK_8_15); + gpio <<= 8; + gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7); + data->gpio_mask = gpio; + + /* Read various values from CONFIG1 */ + data->config1 = adm1026_read_value(client, + ADM1026_REG_CONFIG1); + if (data->config1 & CFG1_PWM_AFC) { + data->pwm1.enable = 2; + data->pwm1.auto_pwm_min = + PWM_MIN_FROM_REG(data->pwm1.pwm); + } + /* Read the GPIO config */ + data->config2 = adm1026_read_value(client, + ADM1026_REG_CONFIG2); + data->config3 = adm1026_read_value(client, + ADM1026_REG_CONFIG3); + data->gpio_config[16] = (data->config3 >> 6) & 0x03; + + value = 0; + for (i = 0;i <= 15;++i) { + if ((i & 0x03) == 0) { + value = adm1026_read_value(client, + ADM1026_REG_GPIO_CFG_0_3 + i/4); + } + data->gpio_config[i] = value & 0x03; + value >>= 2; + } + + data->last_config = jiffies; + }; /* last_config */ + + dev_dbg(&client->dev, "Setting VID from GPIO11-15.\n"); + data->vid = (data->gpio >> 11) & 0x1f; + data->valid = 1; + up(&data->update_lock); + return data; +} + +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr])); +} +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr])); +} +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = INS_TO_REG(nr, val); + adm1026_write_value(client, ADM1026_REG_IN_MIN[nr], data->in_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr])); +} +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = INS_TO_REG(nr, val); + adm1026_write_value(client, ADM1026_REG_IN_MAX[nr], data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define in_reg(offset) \ +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in, \ + NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset); + + +in_reg(0); +in_reg(1); +in_reg(2); +in_reg(3); +in_reg(4); +in_reg(5); +in_reg(6); +in_reg(7); +in_reg(8); +in_reg(9); +in_reg(10); +in_reg(11); +in_reg(12); +in_reg(13); +in_reg(14); +in_reg(15); + +static ssize_t show_in16(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in[16]) - + NEG12_OFFSET); +} +static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_min[16]) + - NEG12_OFFSET); +} +static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET); + adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]); + up(&data->update_lock); + return count; +} +static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_max[16]) + - NEG12_OFFSET); +} +static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET); + adm1026_write_value(client, ADM1026_REG_IN_MAX[16], data->in_max[16]); + up(&data->update_lock); + return count; +} + +static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in16, NULL, 16); +static SENSOR_DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min, set_in16_min, 16); +static SENSOR_DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max, set_in16_max, 16); + + + + +/* Now add fan read/write functions */ + +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], + data->fan_div[nr])); +} +static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], + data->fan_div[nr])); +} +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, data->fan_div[nr]); + adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr), + data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +#define fan_offset(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \ + offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1); + +fan_offset(1); +fan_offset(2); +fan_offset(3); +fan_offset(4); +fan_offset(5); +fan_offset(6); +fan_offset(7); +fan_offset(8); + +/* Adjust fan_min to account for new fan divisor */ +static void fixup_fan_min(struct device *dev, int fan, int old_div) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int new_min; + int new_div = data->fan_div[fan]; + + /* 0 and 0xff are special. Don't adjust them */ + if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff) { + return; + } + + new_min = data->fan_min[fan] * old_div / new_div; + new_min = SENSORS_LIMIT(new_min, 1, 254); + data->fan_min[fan] = new_min; + adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min); +} + +/* Now add fan_div read/write functions */ +static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", data->fan_div[nr]); +} +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val,orig_div,new_div,shift; + + val = simple_strtol(buf, NULL, 10); + new_div = DIV_TO_REG(val); + if (new_div == 0) { + return -EINVAL; + } + down(&data->update_lock); + orig_div = data->fan_div[nr]; + data->fan_div[nr] = DIV_FROM_REG(new_div); + + if (nr < 4) { /* 0 <= nr < 4 */ + shift = 2 * nr; + adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3, + ((DIV_TO_REG(orig_div) & (~(0x03 << shift))) | + (new_div << shift))); + } else { /* 3 < nr < 8 */ + shift = 2 * (nr - 4); + adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7, + ((DIV_TO_REG(orig_div) & (~(0x03 << (2 * shift)))) | + (new_div << shift))); + } + + if (data->fan_div[nr] != orig_div) { + fixup_fan_min(dev,nr,orig_div); + } + up(&data->update_lock); + return count; +} + +#define fan_offset_div(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_div, set_fan_div, offset - 1); + +fan_offset_div(1); +fan_offset_div(2); +fan_offset_div(3); +fan_offset_div(4); +fan_offset_div(5); +fan_offset_div(6); +fan_offset_div(7); +fan_offset_div(8); + +/* Temps */ +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr])); +} +static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr])); +} +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_min[nr] = TEMP_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_TEMP_MIN[nr], + data->temp_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr])); +} +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max[nr] = TEMP_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_TEMP_MAX[nr], + data->temp_max[nr]); + up(&data->update_lock); + return count; +} + +#define temp_reg(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ + NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_min, set_temp_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, set_temp_max, offset - 1); + + +temp_reg(1); +temp_reg(2); +temp_reg(3); + +static ssize_t show_temp_offset(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_offset[nr])); +} +static ssize_t set_temp_offset(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_offset[nr] = TEMP_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET[nr], + data->temp_offset[nr]); + up(&data->update_lock); + return count; +} + +#define temp_offset_reg(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR, \ + show_temp_offset, set_temp_offset, offset - 1); + +temp_offset_reg(1); +temp_offset_reg(2); +temp_offset_reg(3); + +static ssize_t show_temp_auto_point1_temp_hyst(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG( + ADM1026_FAN_ACTIVATION_TEMP_HYST + data->temp_tmin[nr])); +} +static ssize_t show_temp_auto_point2_temp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr] + + ADM1026_FAN_CONTROL_TEMP_RANGE)); +} +static ssize_t show_temp_auto_point1_temp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr])); +} +static ssize_t set_temp_auto_point1_temp(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_tmin[nr] = TEMP_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_TEMP_TMIN[nr], + data->temp_tmin[nr]); + up(&data->update_lock); + return count; +} + +#define temp_auto_point(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp, S_IRUGO | S_IWUSR, \ + show_temp_auto_point1_temp, set_temp_auto_point1_temp, \ + offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO, \ + show_temp_auto_point1_temp_hyst, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO, \ + show_temp_auto_point2_temp, NULL, offset - 1); + +temp_auto_point(1); +temp_auto_point(2); +temp_auto_point(3); + +static ssize_t show_temp_crit_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", (data->config1 & CFG1_THERM_HOT) >> 4); +} +static ssize_t set_temp_crit_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + if ((val == 1) || (val==0)) { + down(&data->update_lock); + data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4); + adm1026_write_value(client, ADM1026_REG_CONFIG1, + data->config1); + up(&data->update_lock); + } + return count; +} + +#define temp_crit_enable(offset) \ +static DEVICE_ATTR(temp##offset##_crit_enable, S_IRUGO | S_IWUSR, \ + show_temp_crit_enable, set_temp_crit_enable); + +temp_crit_enable(1); +temp_crit_enable(2); +temp_crit_enable(3); + +static ssize_t show_temp_crit(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_crit[nr])); +} +static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_crit[nr] = TEMP_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_TEMP_THERM[nr], + data->temp_crit[nr]); + up(&data->update_lock); + return count; +} + +#define temp_crit_reg(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ + show_temp_crit, set_temp_crit, offset - 1); + +temp_crit_reg(1); +temp_crit_reg(2); +temp_crit_reg(3); + +static ssize_t show_analog_out_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", DAC_FROM_REG(data->analog_out)); +} +static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->analog_out = DAC_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_DAC, data->analog_out); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg, + set_analog_out_reg); + +static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm)); +} +/* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ +static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); + +static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", data->vrm); +} +static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + + data->vrm = simple_strtol(buf, NULL, 10); + return count; +} + +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); + +static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf, "%ld\n", (long) (data->alarms)); +} + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); + +static ssize_t show_alarm_mask(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%ld\n", data->alarm_mask); +} +static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + unsigned long mask; + + down(&data->update_lock); + data->alarm_mask = val & 0x7fffffff; + mask = data->alarm_mask + | (data->gpio_mask & 0x10000 ? 0x80000000 : 0); + adm1026_write_value(client, ADM1026_REG_MASK1, + mask & 0xff); + mask >>= 8; + adm1026_write_value(client, ADM1026_REG_MASK2, + mask & 0xff); + mask >>= 8; + adm1026_write_value(client, ADM1026_REG_MASK3, + mask & 0xff); + mask >>= 8; + adm1026_write_value(client, ADM1026_REG_MASK4, + mask & 0xff); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask, + set_alarm_mask); + + +static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%ld\n", data->gpio); +} +static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + long gpio; + + down(&data->update_lock); + data->gpio = val & 0x1ffff; + gpio = data->gpio; + adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7,gpio & 0xff); + gpio >>= 8; + adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_8_15,gpio & 0xff); + gpio = ((gpio >> 1) & 0x80) | (data->alarms >> 24 & 0x7f); + adm1026_write_value(client, ADM1026_REG_STATUS4,gpio & 0xff); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio); + + +static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%ld\n", data->gpio_mask); +} +static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + long mask; + + down(&data->update_lock); + data->gpio_mask = val & 0x1ffff; + mask = data->gpio_mask; + adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7,mask & 0xff); + mask >>= 8; + adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15,mask & 0xff); + mask = ((mask >> 1) & 0x80) | (data->alarm_mask >> 24 & 0x7f); + adm1026_write_value(client, ADM1026_REG_MASK1,mask & 0xff); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask); + +static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm1.pwm)); +} +static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + + if (data->pwm1.enable == 1) { + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->pwm1.pwm = PWM_TO_REG(val); + adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); + up(&data->update_lock); + } + return count; +} +static ssize_t show_auto_pwm_min(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", data->pwm1.auto_pwm_min); +} +static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->pwm1.auto_pwm_min = SENSORS_LIMIT(val,0,255); + if (data->pwm1.enable == 2) { /* apply immediately */ + data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | + PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); + adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); + } + up(&data->update_lock); + return count; +} +static ssize_t show_auto_pwm_max(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%d\n", ADM1026_PWM_MAX); +} +static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1026_data *data = adm1026_update_device(dev); + return sprintf(buf,"%d\n", data->pwm1.enable); +} +static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1026_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + int old_enable; + + if ((val >= 0) && (val < 3)) { + down(&data->update_lock); + old_enable = data->pwm1.enable; + data->pwm1.enable = val; + data->config1 = (data->config1 & ~CFG1_PWM_AFC) + | ((val == 2) ? CFG1_PWM_AFC : 0); + adm1026_write_value(client, ADM1026_REG_CONFIG1, + data->config1); + if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */ + data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | + PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); + adm1026_write_value(client, ADM1026_REG_PWM, + data->pwm1.pwm); + } else if (!((old_enable == 1) && (val == 1))) { + /* set pwm to safe value */ + data->pwm1.pwm = 255; + adm1026_write_value(client, ADM1026_REG_PWM, + data->pwm1.pwm); + } + up(&data->update_lock); + } + return count; +} + +/* enable PWM fan control */ +static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); +static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); +static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); +static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + set_pwm_enable); +static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + set_pwm_enable); +static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + set_pwm_enable); +static DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm_min, set_auto_pwm_min); +static DEVICE_ATTR(temp2_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm_min, set_auto_pwm_min); +static DEVICE_ATTR(temp3_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm_min, set_auto_pwm_min); + +static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); +static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); +static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); + +int adm1026_detect(struct i2c_adapter *adapter, int address, + int kind) +{ + int company, verstep; + struct i2c_client *new_client; + struct adm1026_data *data; + int err = 0; + const char *type_name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + /* We need to be able to do byte I/O */ + goto exit; + }; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access adm1026_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct adm1026_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + memset(data, 0, sizeof(struct adm1026_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm1026_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + company = adm1026_read_value(new_client, ADM1026_REG_COMPANY); + verstep = adm1026_read_value(new_client, ADM1026_REG_VERSTEP); + + dev_dbg(&new_client->dev, "Detecting device at %d,0x%02x with" + " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", + i2c_adapter_id(new_client->adapter), new_client->addr, + company, verstep); + + /* If auto-detecting, Determine the chip type. */ + if (kind <= 0) { + dev_dbg(&new_client->dev, "Autodetecting device at %d,0x%02x " + "...\n", i2c_adapter_id(adapter), address); + if (company == ADM1026_COMPANY_ANALOG_DEV + && verstep == ADM1026_VERSTEP_ADM1026) { + kind = adm1026; + } else if (company == ADM1026_COMPANY_ANALOG_DEV + && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) { + dev_err(&adapter->dev, ": Unrecognized stepping " + "0x%02x. Defaulting to ADM1026.\n", verstep); + kind = adm1026; + } else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) { + dev_err(&adapter->dev, ": Found version/stepping " + "0x%02x. Assuming generic ADM1026.\n", + verstep); + kind = any_chip; + } else { + dev_dbg(&new_client->dev, ": Autodetection " + "failed\n"); + /* Not an ADM1026 ... */ + if (kind == 0) { /* User used force=x,y */ + dev_err(&adapter->dev, "Generic ADM1026 not " + "found at %d,0x%02x. Try " + "force_adm1026.\n", + i2c_adapter_id(adapter), address); + } + err = 0; + goto exitfree; + } + } + + /* Fill in the chip specific driver values */ + switch (kind) { + case any_chip : + type_name = "adm1026"; + break; + case adm1026 : + type_name = "adm1026"; + break; + default : + dev_err(&adapter->dev, ": Internal error, invalid " + "kind (%d)!", kind); + err = -EFAULT; + goto exitfree; + } + strlcpy(new_client->name, type_name, I2C_NAME_SIZE); + + /* Fill in the remaining client fields */ + data->type = kind; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exitfree; + + /* Set the VRM version */ + data->vrm = i2c_which_vrm(); + + /* Initialize the ADM1026 chip */ + adm1026_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in11_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in11_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in11_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in12_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in12_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in12_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in13_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in13_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in13_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in14_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in14_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in14_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in15_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in15_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in15_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in16_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in16_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in16_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan4_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan4_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan4_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan5_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan5_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan5_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan6_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan6_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan6_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan7_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan7_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan7_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan8_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan8_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan8_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_offset.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_offset.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_offset.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_auto_point1_temp.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_auto_point1_temp.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_auto_point1_temp.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_auto_point2_temp.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_auto_point2_temp.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_auto_point2_temp.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr); + device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable); + device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable); + device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable); + /* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ + device_create_file(&new_client->dev, &dev_attr_vid); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + device_create_file(&new_client->dev, &dev_attr_vrm); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_alarm_mask); + device_create_file(&new_client->dev, &dev_attr_gpio); + device_create_file(&new_client->dev, &dev_attr_gpio_mask); + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_pwm2); + device_create_file(&new_client->dev, &dev_attr_pwm3); + device_create_file(&new_client->dev, &dev_attr_pwm1_enable); + device_create_file(&new_client->dev, &dev_attr_pwm2_enable); + device_create_file(&new_client->dev, &dev_attr_pwm3_enable); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_point1_pwm); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_point1_pwm); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_point1_pwm); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_point2_pwm); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_point2_pwm); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_point2_pwm); + device_create_file(&new_client->dev, &dev_attr_analog_out); + return 0; + + /* Error out and cleanup code */ +exitfree: + kfree(new_client); +exit: + return err; +} +static int __init sm_adm1026_init(void) +{ + return i2c_add_driver(&adm1026_driver); +} + +static void __exit sm_adm1026_exit(void) +{ + i2c_del_driver(&adm1026_driver); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Philip Pokorny , " + "Justin Thiessen "); +MODULE_DESCRIPTION("ADM1026 driver"); + +module_init(sm_adm1026_init); +module_exit(sm_adm1026_exit); diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c new file mode 100644 index 00000000000..9168e983ca1 --- /dev/null +++ b/drivers/hwmon/adm1031.c @@ -0,0 +1,977 @@ +/* + adm1031.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Based on lm75.c and lm85.c + Supports adm1030 / adm1031 + Copyright (C) 2004 Alexandre d'Alton + Reworked by Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +/* Following macros takes channel parameter starting from 0 to 2 */ +#define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) +#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) +#define ADM1031_REG_PWM (0x22) +#define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr)) + +#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4*(nr)) +#define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4*(nr)) +#define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4*(nr)) + +#define ADM1031_REG_TEMP(nr) (0xa + (nr)) +#define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr)) + +#define ADM1031_REG_STATUS(nr) (0x2 + (nr)) + +#define ADM1031_REG_CONF1 0x0 +#define ADM1031_REG_CONF2 0x1 +#define ADM1031_REG_EXT_TEMP 0x6 + +#define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */ +#define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert */ +#define ADM1031_CONF1_AUTO_MODE 0x80 /* Auto FAN */ + +#define ADM1031_CONF2_PWM1_ENABLE 0x01 +#define ADM1031_CONF2_PWM2_ENABLE 0x02 +#define ADM1031_CONF2_TACH1_ENABLE 0x04 +#define ADM1031_CONF2_TACH2_ENABLE 0x08 +#define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan)) + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_2(adm1030, adm1031); + +typedef u8 auto_chan_table_t[8][2]; + +/* Each client has this additional data */ +struct adm1031_data { + struct i2c_client client; + struct semaphore update_lock; + int chip_type; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + /* The chan_select_table contains the possible configurations for + * auto fan control. + */ + auto_chan_table_t *chan_select_table; + u16 alarm; + u8 conf1; + u8 conf2; + u8 fan[2]; + u8 fan_div[2]; + u8 fan_min[2]; + u8 pwm[2]; + u8 old_pwm[2]; + s8 temp[3]; + u8 ext_temp[3]; + u8 auto_temp[3]; + u8 auto_temp_min[3]; + u8 auto_temp_off[3]; + u8 auto_temp_max[3]; + s8 temp_min[3]; + s8 temp_max[3]; + s8 temp_crit[3]; +}; + +static int adm1031_attach_adapter(struct i2c_adapter *adapter); +static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind); +static void adm1031_init_client(struct i2c_client *client); +static int adm1031_detach_client(struct i2c_client *client); +static struct adm1031_data *adm1031_update_device(struct device *dev); + +/* This is the driver that will be inserted */ +static struct i2c_driver adm1031_driver = { + .owner = THIS_MODULE, + .name = "adm1031", + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm1031_attach_adapter, + .detach_client = adm1031_detach_client, +}; + +static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static inline int +adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + + +#define TEMP_TO_REG(val) (((val) < 0 ? ((val - 500) / 1000) : \ + ((val + 500) / 1000))) + +#define TEMP_FROM_REG(val) ((val) * 1000) + +#define TEMP_FROM_REG_EXT(val, ext) (TEMP_FROM_REG(val) + (ext) * 125) + +#define FAN_FROM_REG(reg, div) ((reg) ? (11250 * 60) / ((reg) * (div)) : 0) + +static int FAN_TO_REG(int reg, int div) +{ + int tmp; + tmp = FAN_FROM_REG(SENSORS_LIMIT(reg, 0, 65535), div); + return tmp > 255 ? 255 : tmp; +} + +#define FAN_DIV_FROM_REG(reg) (1<<(((reg)&0xc0)>>6)) + +#define PWM_TO_REG(val) (SENSORS_LIMIT((val), 0, 255) >> 4) +#define PWM_FROM_REG(val) ((val) << 4) + +#define FAN_CHAN_FROM_REG(reg) (((reg) >> 5) & 7) +#define FAN_CHAN_TO_REG(val, reg) \ + (((reg) & 0x1F) | (((val) << 5) & 0xe0)) + +#define AUTO_TEMP_MIN_TO_REG(val, reg) \ + ((((val)/500) & 0xf8)|((reg) & 0x7)) +#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1<< ((reg)&0x7))) +#define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2)) + +#define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2) + +#define AUTO_TEMP_OFF_FROM_REG(reg) \ + (AUTO_TEMP_MIN_FROM_REG(reg) - 5000) + +#define AUTO_TEMP_MAX_FROM_REG(reg) \ + (AUTO_TEMP_RANGE_FROM_REG(reg) + \ + AUTO_TEMP_MIN_FROM_REG(reg)) + +static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm) +{ + int ret; + int range = val - AUTO_TEMP_MIN_FROM_REG(reg); + + range = ((val - AUTO_TEMP_MIN_FROM_REG(reg))*10)/(16 - pwm); + ret = ((reg & 0xf8) | + (range < 10000 ? 0 : + range < 20000 ? 1 : + range < 40000 ? 2 : range < 80000 ? 3 : 4)); + return ret; +} + +/* FAN auto control */ +#define GET_FAN_AUTO_BITFIELD(data, idx) \ + (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2] + +/* The tables below contains the possible values for the auto fan + * control bitfields. the index in the table is the register value. + * MSb is the auto fan control enable bit, so the four first entries + * in the table disables auto fan control when both bitfields are zero. + */ +static auto_chan_table_t auto_channel_select_table_adm1031 = { + {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {2 /*0b010 */ , 4 /*0b100 */ }, + {2 /*0b010 */ , 2 /*0b010 */ }, + {4 /*0b100 */ , 4 /*0b100 */ }, + {7 /*0b111 */ , 7 /*0b111 */ }, +}; + +static auto_chan_table_t auto_channel_select_table_adm1030 = { + {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {2 /*0b10 */ , 0}, + {0xff /*invalid */ , 0}, + {0xff /*invalid */ , 0}, + {3 /*0b11 */ , 0}, +}; + +/* That function checks if a bitfield is valid and returns the other bitfield + * nearest match if no exact match where found. + */ +static int +get_fan_auto_nearest(struct adm1031_data *data, + int chan, u8 val, u8 reg, u8 * new_reg) +{ + int i; + int first_match = -1, exact_match = -1; + u8 other_reg_val = + (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1]; + + if (val == 0) { + *new_reg = 0; + return 0; + } + + for (i = 0; i < 8; i++) { + if ((val == (*data->chan_select_table)[i][chan]) && + ((*data->chan_select_table)[i][chan ? 0 : 1] == + other_reg_val)) { + /* We found an exact match */ + exact_match = i; + break; + } else if (val == (*data->chan_select_table)[i][chan] && + first_match == -1) { + /* Save the first match in case of an exact match has not been + * found + */ + first_match = i; + } + } + + if (exact_match >= 0) { + *new_reg = exact_match; + } else if (first_match >= 0) { + *new_reg = first_match; + } else { + return -EINVAL; + } + return 0; +} + +static ssize_t show_fan_auto_channel(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr)); +} + +static ssize_t +set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + u8 reg; + int ret; + u8 old_fan_mode; + + old_fan_mode = data->conf1; + + down(&data->update_lock); + + if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®))) { + up(&data->update_lock); + return ret; + } + if (((data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1)) & ADM1031_CONF1_AUTO_MODE) ^ + (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { + if (data->conf1 & ADM1031_CONF1_AUTO_MODE){ + /* Switch to Auto Fan Mode + * Save PWM registers + * Set PWM registers to 33% Both */ + data->old_pwm[0] = data->pwm[0]; + data->old_pwm[1] = data->pwm[1]; + adm1031_write_value(client, ADM1031_REG_PWM, 0x55); + } else { + /* Switch to Manual Mode */ + data->pwm[0] = data->old_pwm[0]; + data->pwm[1] = data->old_pwm[1]; + /* Restore PWM registers */ + adm1031_write_value(client, ADM1031_REG_PWM, + data->pwm[0] | (data->pwm[1] << 4)); + } + } + data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); + adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1); + up(&data->update_lock); + return count; +} + +#define fan_auto_channel_offset(offset) \ +static ssize_t show_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_auto_channel(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_auto_channel(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(auto_fan##offset##_channel, S_IRUGO | S_IWUSR, \ + show_fan_auto_channel_##offset, \ + set_fan_auto_channel_##offset) + +fan_auto_channel_offset(1); +fan_auto_channel_offset(2); + +/* Auto Temps */ +static ssize_t show_auto_temp_off(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", + AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr])); +} +static ssize_t show_auto_temp_min(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", + AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr])); +} +static ssize_t +set_auto_temp_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]); + adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), + data->auto_temp[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_auto_temp_max(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", + AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr])); +} +static ssize_t +set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]); + adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), + data->temp_max[nr]); + up(&data->update_lock); + return count; +} + +#define auto_temp_reg(offset) \ +static ssize_t show_auto_temp_##offset##_off (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_auto_temp_off(dev, buf, offset - 1); \ +} \ +static ssize_t show_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_auto_temp_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_auto_temp_max(dev, buf, offset - 1); \ +} \ +static ssize_t set_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_auto_temp_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_auto_temp_max(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO, \ + show_auto_temp_##offset##_off, NULL); \ +static DEVICE_ATTR(auto_temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_auto_temp_##offset##_min, set_auto_temp_##offset##_min);\ +static DEVICE_ATTR(auto_temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_auto_temp_##offset##_max, set_auto_temp_##offset##_max) + +auto_temp_reg(1); +auto_temp_reg(2); +auto_temp_reg(3); + +/* pwm */ +static ssize_t show_pwm(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); +} +static ssize_t +set_pwm(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + int reg; + + down(&data->update_lock); + if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && + (((val>>4) & 0xf) != 5)) { + /* In automatic mode, the only PWM accepted is 33% */ + up(&data->update_lock); + return -EINVAL; + } + data->pwm[nr] = PWM_TO_REG(val); + reg = adm1031_read_value(client, ADM1031_REG_PWM); + adm1031_write_value(client, ADM1031_REG_PWM, + nr ? ((data->pwm[nr] << 4) & 0xf0) | (reg & 0xf) + : (data->pwm[nr] & 0xf) | (reg & 0xf0)); + up(&data->update_lock); + return count; +} + +#define pwm_reg(offset) \ +static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwm(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_pwm_##offset, set_pwm_##offset) + +pwm_reg(1); +pwm_reg(2); + +/* Fans */ + +/* + * That function checks the cases where the fan reading is not + * relevant. It is used to provide 0 as fan reading when the fan is + * not supposed to run + */ +static int trust_fan_readings(struct adm1031_data *data, int chan) +{ + int res = 0; + + if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { + switch (data->conf1 & 0x60) { + case 0x00: /* remote temp1 controls fan1 remote temp2 controls fan2 */ + res = data->temp[chan+1] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); + break; + case 0x20: /* remote temp1 controls both fans */ + res = + data->temp[1] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]); + break; + case 0x40: /* remote temp2 controls both fans */ + res = + data->temp[2] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]); + break; + case 0x60: /* max controls both fans */ + res = + data->temp[0] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0]) + || data->temp[1] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]) + || (data->chip_type == adm1031 + && data->temp[2] >= + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2])); + break; + } + } else { + res = data->pwm[chan] > 0; + } + return res; +} + + +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + int value; + + value = trust_fan_readings(data, nr) ? FAN_FROM_REG(data->fan[nr], + FAN_DIV_FROM_REG(data->fan_div[nr])) : 0; + return sprintf(buf, "%d\n", value); +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr])); +} +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", + FAN_FROM_REG(data->fan_min[nr], + FAN_DIV_FROM_REG(data->fan_div[nr]))); +} +static ssize_t +set_fan_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + if (val) { + data->fan_min[nr] = + FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr])); + } else { + data->fan_min[nr] = 0xff; + } + adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t +set_fan_div(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + u8 tmp; + int old_div; + int new_min; + + tmp = val == 8 ? 0xc0 : + val == 4 ? 0x80 : + val == 2 ? 0x40 : + val == 1 ? 0x00 : + 0xff; + if (tmp == 0xff) + return -EINVAL; + + down(&data->update_lock); + old_div = FAN_DIV_FROM_REG(data->fan_div[nr]); + data->fan_div[nr] = (tmp & 0xC0) | (0x3f & data->fan_div[nr]); + new_min = data->fan_min[nr] * old_div / + FAN_DIV_FROM_REG(data->fan_div[nr]); + data->fan_min[nr] = new_min > 0xff ? 0xff : new_min; + data->fan[nr] = data->fan[nr] * old_div / + FAN_DIV_FROM_REG(data->fan_div[nr]); + + adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr), + data->fan_div[nr]); + adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), + data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +#define fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_div(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ + NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_div, set_fan_##offset##_div); \ +static DEVICE_ATTR(auto_fan##offset##_min_pwm, S_IRUGO | S_IWUSR, \ + show_pwm_##offset, set_pwm_##offset) + +fan_offset(1); +fan_offset(2); + + +/* Temps */ +static ssize_t show_temp(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + int ext; + ext = nr == 0 ? + ((data->ext_temp[nr] >> 6) & 0x3) * 2 : + (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7)); + return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext)); +} +static ssize_t show_temp_min(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr])); +} +static ssize_t show_temp_max(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr])); +} +static ssize_t show_temp_crit(struct device *dev, char *buf, int nr) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr])); +} +static ssize_t +set_temp_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val; + + val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); + down(&data->update_lock); + data->temp_min[nr] = TEMP_TO_REG(val); + adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr), + data->temp_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t +set_temp_max(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val; + + val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); + down(&data->update_lock); + data->temp_max[nr] = TEMP_TO_REG(val); + adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr), + data->temp_max[nr]); + up(&data->update_lock); + return count; +} +static ssize_t +set_temp_crit(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int val; + + val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); + down(&data->update_lock); + data->temp_crit[nr] = TEMP_TO_REG(val); + adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr), + data->temp_crit[nr]); + up(&data->update_lock); + return count; +} + +#define temp_reg(offset) \ +static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, offset - 1); \ +} \ +static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_max(dev, buf, offset - 1); \ +} \ +static ssize_t show_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_crit(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_max(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_crit(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ + NULL); \ +static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_min, set_temp_##offset##_min); \ +static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_max, set_temp_##offset##_max); \ +static DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_crit, set_temp_##offset##_crit) + +temp_reg(1); +temp_reg(2); +temp_reg(3); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm1031_data *data = adm1031_update_device(dev); + return sprintf(buf, "%d\n", data->alarm); +} + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + + +static int adm1031_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, adm1031_detect); +} + +/* This function is called by i2c_detect */ +static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct adm1031_data *data; + int err = 0; + const char *name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct adm1031_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm1031_driver; + new_client->flags = 0; + + if (kind < 0) { + int id, co; + id = i2c_smbus_read_byte_data(new_client, 0x3d); + co = i2c_smbus_read_byte_data(new_client, 0x3e); + + if (!((id == 0x31 || id == 0x30) && co == 0x41)) + goto exit_free; + kind = (id == 0x30) ? adm1030 : adm1031; + } + + if (kind <= 0) + kind = adm1031; + + /* Given the detected chip type, set the chip name and the + * auto fan control helper table. */ + if (kind == adm1030) { + name = "adm1030"; + data->chan_select_table = &auto_channel_select_table_adm1030; + } else if (kind == adm1031) { + name = "adm1031"; + data->chan_select_table = &auto_channel_select_table_adm1031; + } + data->chip_type = kind; + + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the ADM1031 chip */ + adm1031_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp2_crit); + + device_create_file(&new_client->dev, &dev_attr_auto_temp1_off); + device_create_file(&new_client->dev, &dev_attr_auto_temp1_min); + device_create_file(&new_client->dev, &dev_attr_auto_temp1_max); + + device_create_file(&new_client->dev, &dev_attr_auto_temp2_off); + device_create_file(&new_client->dev, &dev_attr_auto_temp2_min); + device_create_file(&new_client->dev, &dev_attr_auto_temp2_max); + + device_create_file(&new_client->dev, &dev_attr_auto_fan1_min_pwm); + + device_create_file(&new_client->dev, &dev_attr_alarms); + + if (kind == adm1031) { + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_pwm2); + device_create_file(&new_client->dev, + &dev_attr_auto_fan2_channel); + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp3_min); + device_create_file(&new_client->dev, &dev_attr_temp3_max); + device_create_file(&new_client->dev, &dev_attr_temp3_crit); + device_create_file(&new_client->dev, &dev_attr_auto_temp3_off); + device_create_file(&new_client->dev, &dev_attr_auto_temp3_min); + device_create_file(&new_client->dev, &dev_attr_auto_temp3_max); + device_create_file(&new_client->dev, &dev_attr_auto_fan2_min_pwm); + } + + return 0; + +exit_free: + kfree(new_client); +exit: + return err; +} + +static int adm1031_detach_client(struct i2c_client *client) +{ + int ret; + if ((ret = i2c_detach_client(client)) != 0) { + return ret; + } + kfree(client); + return 0; +} + +static void adm1031_init_client(struct i2c_client *client) +{ + unsigned int read_val; + unsigned int mask; + struct adm1031_data *data = i2c_get_clientdata(client); + + mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE); + if (data->chip_type == adm1031) { + mask |= (ADM1031_CONF2_PWM2_ENABLE | + ADM1031_CONF2_TACH2_ENABLE); + } + /* Initialize the ADM1031 chip (enables fan speed reading ) */ + read_val = adm1031_read_value(client, ADM1031_REG_CONF2); + if ((read_val | mask) != read_val) { + adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); + } + + read_val = adm1031_read_value(client, ADM1031_REG_CONF1); + if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { + adm1031_write_value(client, ADM1031_REG_CONF1, read_val | + ADM1031_CONF1_MONITOR_ENABLE); + } + +} + +static struct adm1031_data *adm1031_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm1031_data *data = i2c_get_clientdata(client); + int chan; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + dev_dbg(&client->dev, "Starting adm1031 update\n"); + for (chan = 0; + chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) { + u8 oldh, newh; + + oldh = + adm1031_read_value(client, ADM1031_REG_TEMP(chan)); + data->ext_temp[chan] = + adm1031_read_value(client, ADM1031_REG_EXT_TEMP); + newh = + adm1031_read_value(client, ADM1031_REG_TEMP(chan)); + if (newh != oldh) { + data->ext_temp[chan] = + adm1031_read_value(client, + ADM1031_REG_EXT_TEMP); +#ifdef DEBUG + oldh = + adm1031_read_value(client, + ADM1031_REG_TEMP(chan)); + + /* oldh is actually newer */ + if (newh != oldh) + dev_warn(&client->dev, + "Remote temperature may be " + "wrong.\n"); +#endif + } + data->temp[chan] = newh; + + data->temp_min[chan] = + adm1031_read_value(client, + ADM1031_REG_TEMP_MIN(chan)); + data->temp_max[chan] = + adm1031_read_value(client, + ADM1031_REG_TEMP_MAX(chan)); + data->temp_crit[chan] = + adm1031_read_value(client, + ADM1031_REG_TEMP_CRIT(chan)); + data->auto_temp[chan] = + adm1031_read_value(client, + ADM1031_REG_AUTO_TEMP(chan)); + + } + + data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); + data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); + + data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0)) + | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) + << 8); + if (data->chip_type == adm1030) { + data->alarm &= 0xc0ff; + } + + for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) { + data->fan_div[chan] = + adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan)); + data->fan_min[chan] = + adm1031_read_value(client, ADM1031_REG_FAN_MIN(chan)); + data->fan[chan] = + adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan)); + data->pwm[chan] = + 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >> + (4*chan)); + } + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_adm1031_init(void) +{ + return i2c_add_driver(&adm1031_driver); +} + +static void __exit sensors_adm1031_exit(void) +{ + i2c_del_driver(&adm1031_driver); +} + +MODULE_AUTHOR("Alexandre d'Alton "); +MODULE_DESCRIPTION("ADM1031/ADM1030 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_adm1031_init); +module_exit(sensors_adm1031_exit); diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c new file mode 100644 index 00000000000..5c68e9c311a --- /dev/null +++ b/drivers/hwmon/adm9240.c @@ -0,0 +1,791 @@ +/* + * adm9240.c Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * + * Copyright (C) 1999 Frodo Looijaard + * Philip Edelbrock + * Copyright (C) 2003 Michiel Rook + * Copyright (C) 2005 Grant Coady with valuable + * guidance from Jean Delvare + * + * Driver supports Analog Devices ADM9240 + * Dallas Semiconductor DS1780 + * National Semiconductor LM81 + * + * ADM9240 is the reference, DS1780 and LM81 are register compatibles + * + * Voltage Six inputs are scaled by chip, VID also reported + * Temperature Chip temperature to 0.5'C, maximum and max_hysteris + * Fans 2 fans, low speed alarm, automatic fan clock divider + * Alarms 16-bit map of active alarms + * Analog Out 0..1250 mV output + * + * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear' + * + * Test hardware: Intel SE440BX-2 desktop motherboard --Grant + * + * LM81 extended temp reading not implemented + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, + I2C_CLIENT_END }; + +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_3(adm9240, ds1780, lm81); + +/* ADM9240 registers */ +#define ADM9240_REG_MAN_ID 0x3e +#define ADM9240_REG_DIE_REV 0x3f +#define ADM9240_REG_CONFIG 0x40 + +#define ADM9240_REG_IN(nr) (0x20 + (nr)) /* 0..5 */ +#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define ADM9240_REG_FAN(nr) (0x28 + (nr)) /* 0..1 */ +#define ADM9240_REG_FAN_MIN(nr) (0x3b + (nr)) +#define ADM9240_REG_INT(nr) (0x41 + (nr)) +#define ADM9240_REG_INT_MASK(nr) (0x43 + (nr)) +#define ADM9240_REG_TEMP 0x27 +#define ADM9240_REG_TEMP_HIGH 0x39 +#define ADM9240_REG_TEMP_HYST 0x3a +#define ADM9240_REG_ANALOG_OUT 0x19 +#define ADM9240_REG_CHASSIS_CLEAR 0x46 +#define ADM9240_REG_VID_FAN_DIV 0x47 +#define ADM9240_REG_I2C_ADDR 0x48 +#define ADM9240_REG_VID4 0x49 +#define ADM9240_REG_TEMP_CONF 0x4b + +/* generalised scaling with integer rounding */ +static inline int SCALE(long val, int mul, int div) +{ + if (val < 0) + return (val * mul - div / 2) / div; + else + return (val * mul + div / 2) / div; +} + +/* adm9240 internally scales voltage measurements */ +static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 }; + +static inline unsigned int IN_FROM_REG(u8 reg, int n) +{ + return SCALE(reg, nom_mv[n], 192); +} + +static inline u8 IN_TO_REG(unsigned long val, int n) +{ + return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255); +} + +/* temperature range: -40..125, 127 disables temperature alarm */ +static inline s8 TEMP_TO_REG(long val) +{ + return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127); +} + +/* two fans, each with low fan speed limit */ +static inline unsigned int FAN_FROM_REG(u8 reg, u8 div) +{ + if (!reg) /* error */ + return -1; + + if (reg == 255) + return 0; + + return SCALE(1350000, 1, reg * div); +} + +/* analog out 0..1250mV */ +static inline u8 AOUT_TO_REG(unsigned long val) +{ + return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255); +} + +static inline unsigned int AOUT_FROM_REG(u8 reg) +{ + return SCALE(reg, 1250, 255); +} + +static int adm9240_attach_adapter(struct i2c_adapter *adapter); +static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind); +static void adm9240_init_client(struct i2c_client *client); +static int adm9240_detach_client(struct i2c_client *client); +static struct adm9240_data *adm9240_update_device(struct device *dev); + +/* driver data */ +static struct i2c_driver adm9240_driver = { + .owner = THIS_MODULE, + .name = "adm9240", + .id = I2C_DRIVERID_ADM9240, + .flags = I2C_DF_NOTIFY, + .attach_adapter = adm9240_attach_adapter, + .detach_client = adm9240_detach_client, +}; + +/* per client data */ +struct adm9240_data { + enum chips type; + struct i2c_client client; + struct semaphore update_lock; + char valid; + unsigned long last_updated_measure; + unsigned long last_updated_config; + + u8 in[6]; /* ro in0_input */ + u8 in_max[6]; /* rw in0_max */ + u8 in_min[6]; /* rw in0_min */ + u8 fan[2]; /* ro fan1_input */ + u8 fan_min[2]; /* rw fan1_min */ + u8 fan_div[2]; /* rw fan1_div, read-only accessor */ + s16 temp; /* ro temp1_input, 9-bit sign-extended */ + s8 temp_high; /* rw temp1_max */ + s8 temp_hyst; /* rw temp1_max_hyst */ + u16 alarms; /* ro alarms */ + u8 aout; /* rw aout_output */ + u8 vid; /* ro vid */ + u8 vrm; /* -- vrm set on startup, no accessor */ +}; + +/* i2c byte read/write interface */ +static int adm9240_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/*** sysfs accessors ***/ + +/* temperature */ +#define show_temp(value, scale) \ +static ssize_t show_##value(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct adm9240_data *data = adm9240_update_device(dev); \ + return sprintf(buf, "%d\n", data->value * scale); \ +} +show_temp(temp_high, 1000); +show_temp(temp_hyst, 1000); +show_temp(temp, 500); /* 0.5'C per bit */ + +#define set_temp(value, reg) \ +static ssize_t set_##value(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm9240_data *data = adm9240_update_device(dev); \ + long temp = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_TO_REG(temp); \ + adm9240_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} + +set_temp(temp_high, ADM9240_REG_TEMP_HIGH); +set_temp(temp_hyst, ADM9240_REG_TEMP_HYST); + +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + show_temp_high, set_temp_high); +static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, + show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); + +/* voltage */ +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr)); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr)); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr)); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val, nr); + adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val, nr); + adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define show_in_offset(offset) \ +static ssize_t show_in##offset(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \ +static ssize_t show_in##offset##_min(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t show_in##offset##_max(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t \ +set_in##offset##_min(struct device *dev, \ + struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t \ +set_in##offset##_max(struct device *dev, \ + struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); +show_in_offset(5); + +/* fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + 1 << data->fan_div[nr])); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + 1 << data->fan_div[nr])); +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", 1 << data->fan_div[nr]); +} + +/* write new fan div, callers must hold data->update_lock */ +static void adm9240_write_fan_div(struct i2c_client *client, int nr, + u8 fan_div) +{ + u8 reg, old, shift = (nr + 2) * 2; + + reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + old = (reg >> shift) & 3; + reg &= ~(3 << shift); + reg |= (fan_div << shift); + adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg); + dev_dbg(&client->dev, "fan%d clock divider changed from %u " + "to %u\n", nr + 1, 1 << old, 1 << fan_div); +} + +/* + * set fan speed low limit: + * + * - value is zero: disable fan speed low limit alarm + * + * - value is below fan speed measurement range: enable fan speed low + * limit alarm to be asserted while fan speed too slow to measure + * + * - otherwise: select fan clock divider to suit fan speed low limit, + * measurement code may adjust registers to ensure fan speed reading + */ +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + u8 new_div; + + down(&data->update_lock); + + if (!val) { + data->fan_min[nr] = 255; + new_div = data->fan_div[nr]; + + dev_dbg(&client->dev, "fan%u low limit set disabled\n", + nr + 1); + + } else if (val < 1350000 / (8 * 254)) { + new_div = 3; + data->fan_min[nr] = 254; + + dev_dbg(&client->dev, "fan%u low limit set minimum %u\n", + nr + 1, FAN_FROM_REG(254, 1 << new_div)); + + } else { + unsigned int new_min = 1350000 / val; + + new_div = 0; + while (new_min > 192 && new_div < 3) { + new_div++; + new_min /= 2; + } + if (!new_min) /* keep > 0 */ + new_min++; + + data->fan_min[nr] = new_min; + + dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n", + nr + 1, FAN_FROM_REG(new_min, 1 << new_div)); + } + + if (new_div != data->fan_div[nr]) { + data->fan_div[nr] = new_div; + adm9240_write_fan_div(client, nr, new_div); + } + adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr), + data->fan_min[nr]); + + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ +return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ +return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ +return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ +return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan_##offset, NULL); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ + show_fan_##offset##_div, NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); + +show_fan_offset(1); +show_fan_offset(2); + +/* alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* vid */ +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +/* analog output */ +static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adm9240_data *data = adm9240_update_device(dev); + return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); +} + +static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->aout = AOUT_TO_REG(val); + adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout); + up(&data->update_lock); + return count; +} +static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); + +/* chassis_clear */ +static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned long val = simple_strtol(buf, NULL, 10); + + if (val == 1) { + adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); + dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); + } + return count; +} +static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear); + + +/*** sensor chip detect and driver install ***/ + +static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct adm9240_data *data; + int err = 0; + const char *name = ""; + u8 man_id, die_rev; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct adm9240_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &adm9240_driver; + new_client->flags = 0; + + if (kind == 0) { + kind = adm9240; + } + + if (kind < 0) { + + /* verify chip: reg address should match i2c address */ + if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR) + != address) { + dev_err(&adapter->dev, "detect fail: address match, " + "0x%02x\n", address); + goto exit_free; + } + + /* check known chip manufacturer */ + man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID); + + if (man_id == 0x23) { + kind = adm9240; + } else if (man_id == 0xda) { + kind = ds1780; + } else if (man_id == 0x01) { + kind = lm81; + } else { + dev_err(&adapter->dev, "detect fail: unknown manuf, " + "0x%02x\n", man_id); + goto exit_free; + } + + /* successful detect, print chip info */ + die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV); + dev_info(&adapter->dev, "found %s revision %u\n", + man_id == 0x23 ? "ADM9240" : + man_id == 0xda ? "DS1780" : "LM81", die_rev); + } + + /* either forced or detected chip kind */ + if (kind == adm9240) { + name = "adm9240"; + } else if (kind == ds1780) { + name = "ds1780"; + } else if (kind == lm81) { + name = "lm81"; + } + + /* fill in the remaining client fields and attach */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->type = kind; + init_MUTEX(&data->update_lock); + + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + adm9240_init_client(new_client); + + /* populate sysfs filesystem */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_aout_output); + device_create_file(&new_client->dev, &dev_attr_chassis_clear); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + + return 0; +exit_free: + kfree(new_client); +exit: + return err; +} + +static int adm9240_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, adm9240_detect); +} + +static int adm9240_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static void adm9240_init_client(struct i2c_client *client) +{ + struct adm9240_data *data = i2c_get_clientdata(client); + u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG); + u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3; + + data->vrm = i2c_which_vrm(); /* need this to report vid as mV */ + + dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10, + data->vrm % 10); + + if (conf & 1) { /* measurement cycle running: report state */ + + dev_info(&client->dev, "status: config 0x%02x mode %u\n", + conf, mode); + + } else { /* cold start: open limits before starting chip */ + int i; + + for (i = 0; i < 6; i++) + { + adm9240_write_value(client, + ADM9240_REG_IN_MIN(i), 0); + adm9240_write_value(client, + ADM9240_REG_IN_MAX(i), 255); + } + adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255); + adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255); + adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127); + adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127); + + /* start measurement cycle */ + adm9240_write_value(client, ADM9240_REG_CONFIG, 1); + + dev_info(&client->dev, "cold start: config was 0x%02x " + "mode %u\n", conf, mode); + } +} + +static struct adm9240_data *adm9240_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + /* minimum measurement cycle: 1.75 seconds */ + if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) + || !data->valid) { + + for (i = 0; i < 6; i++) /* read voltages */ + { + data->in[i] = adm9240_read_value(client, + ADM9240_REG_IN(i)); + } + data->alarms = adm9240_read_value(client, + ADM9240_REG_INT(0)) | + adm9240_read_value(client, + ADM9240_REG_INT(1)) << 8; + + /* read temperature: assume temperature changes less than + * 0.5'C per two measurement cycles thus ignore possible + * but unlikely aliasing error on lsb reading. --Grant */ + data->temp = ((adm9240_read_value(client, + ADM9240_REG_TEMP) << 8) | + adm9240_read_value(client, + ADM9240_REG_TEMP_CONF)) / 128; + + for (i = 0; i < 2; i++) /* read fans */ + { + data->fan[i] = adm9240_read_value(client, + ADM9240_REG_FAN(i)); + + /* adjust fan clock divider on overflow */ + if (data->valid && data->fan[i] == 255 && + data->fan_div[i] < 3) { + + adm9240_write_fan_div(client, i, + ++data->fan_div[i]); + + /* adjust fan_min if active, but not to 0 */ + if (data->fan_min[i] < 255 && + data->fan_min[i] >= 2) + data->fan_min[i] /= 2; + } + } + data->last_updated_measure = jiffies; + } + + /* minimum config reading cycle: 300 seconds */ + if (time_after(jiffies, data->last_updated_config + (HZ * 300)) + || !data->valid) { + + for (i = 0; i < 6; i++) + { + data->in_min[i] = adm9240_read_value(client, + ADM9240_REG_IN_MIN(i)); + data->in_max[i] = adm9240_read_value(client, + ADM9240_REG_IN_MAX(i)); + } + for (i = 0; i < 2; i++) + { + data->fan_min[i] = adm9240_read_value(client, + ADM9240_REG_FAN_MIN(i)); + } + data->temp_high = adm9240_read_value(client, + ADM9240_REG_TEMP_HIGH); + data->temp_hyst = adm9240_read_value(client, + ADM9240_REG_TEMP_HYST); + + /* read fan divs and 5-bit VID */ + i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); + data->fan_div[0] = (i >> 4) & 3; + data->fan_div[1] = (i >> 6) & 3; + data->vid = i & 0x0f; + data->vid |= (adm9240_read_value(client, + ADM9240_REG_VID4) & 1) << 4; + /* read analog out */ + data->aout = adm9240_read_value(client, + ADM9240_REG_ANALOG_OUT); + + data->last_updated_config = jiffies; + data->valid = 1; + } + up(&data->update_lock); + return data; +} + +static int __init sensors_adm9240_init(void) +{ + return i2c_add_driver(&adm9240_driver); +} + +static void __exit sensors_adm9240_exit(void) +{ + i2c_del_driver(&adm9240_driver); +} + +MODULE_AUTHOR("Michiel Rook , " + "Grant Coady and others"); +MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_adm9240_init); +module_exit(sensors_adm9240_exit); + diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c new file mode 100644 index 00000000000..70d996d6fe0 --- /dev/null +++ b/drivers/hwmon/asb100.c @@ -0,0 +1,1065 @@ +/* + asb100.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + + Copyright (C) 2004 Mark M. Hoffman + + (derived from w83781d.c) + + Copyright (C) 1998 - 2003 Frodo Looijaard , + Philip Edelbrock , and + Mark Studebaker + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + This driver supports the hardware sensor chips: Asus ASB100 and + ASB100-A "BACH". + + ASB100-A supports pwm1, while plain ASB100 does not. There is no known + way for the driver to tell which one is there. + + Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + asb100 7 3 1 4 0x31 0x0694 yes no +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "lm75.h" + +/* + HISTORY: + 2003-12-29 1.0.0 Ported from lm_sensors project for kernel 2.6 +*/ +#define ASB100_VERSION "1.0.0" + +/* I2C addresses to scan */ +static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END }; + +/* ISA addresses to scan (none) */ +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(asb100); +I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " + "{bus, clientaddr, subclientaddr1, subclientaddr2}"); + +/* Voltage IN registers 0-6 */ +#define ASB100_REG_IN(nr) (0x20 + (nr)) +#define ASB100_REG_IN_MAX(nr) (0x2b + (nr * 2)) +#define ASB100_REG_IN_MIN(nr) (0x2c + (nr * 2)) + +/* FAN IN registers 1-3 */ +#define ASB100_REG_FAN(nr) (0x28 + (nr)) +#define ASB100_REG_FAN_MIN(nr) (0x3b + (nr)) + +/* TEMPERATURE registers 1-4 */ +static const u16 asb100_reg_temp[] = {0, 0x27, 0x150, 0x250, 0x17}; +static const u16 asb100_reg_temp_max[] = {0, 0x39, 0x155, 0x255, 0x18}; +static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19}; + +#define ASB100_REG_TEMP(nr) (asb100_reg_temp[nr]) +#define ASB100_REG_TEMP_MAX(nr) (asb100_reg_temp_max[nr]) +#define ASB100_REG_TEMP_HYST(nr) (asb100_reg_temp_hyst[nr]) + +#define ASB100_REG_TEMP2_CONFIG 0x0152 +#define ASB100_REG_TEMP3_CONFIG 0x0252 + + +#define ASB100_REG_CONFIG 0x40 +#define ASB100_REG_ALARM1 0x41 +#define ASB100_REG_ALARM2 0x42 +#define ASB100_REG_SMIM1 0x43 +#define ASB100_REG_SMIM2 0x44 +#define ASB100_REG_VID_FANDIV 0x47 +#define ASB100_REG_I2C_ADDR 0x48 +#define ASB100_REG_CHIPID 0x49 +#define ASB100_REG_I2C_SUBADDR 0x4a +#define ASB100_REG_PIN 0x4b +#define ASB100_REG_IRQ 0x4c +#define ASB100_REG_BANK 0x4e +#define ASB100_REG_CHIPMAN 0x4f + +#define ASB100_REG_WCHIPID 0x58 + +/* bit 7 -> enable, bits 0-3 -> duty cycle */ +#define ASB100_REG_PWM1 0x59 + +/* CONVERSIONS + Rounding and limit checking is only done on the TO_REG variants. */ + +/* These constants are a guess, consistent w/ w83781d */ +#define ASB100_IN_MIN ( 0) +#define ASB100_IN_MAX (4080) + +/* IN: 1/1000 V (0V to 4.08V) + REG: 16mV/bit */ +static u8 IN_TO_REG(unsigned val) +{ + unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX); + return (nval + 8) / 16; +} + +static unsigned IN_FROM_REG(u8 reg) +{ + return reg * 16; +} + +static u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == -1) + return 0; + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +static int FAN_FROM_REG(u8 val, int div) +{ + return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); +} + +/* These constants are a guess, consistent w/ w83781d */ +#define ASB100_TEMP_MIN (-128000) +#define ASB100_TEMP_MAX ( 127000) + +/* TEMP: 0.001C/bit (-128C to +127C) + REG: 1C/bit, two's complement */ +static u8 TEMP_TO_REG(int temp) +{ + int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX); + ntemp += (ntemp<0 ? -500 : 500); + return (u8)(ntemp / 1000); +} + +static int TEMP_FROM_REG(u8 reg) +{ + return (s8)reg * 1000; +} + +/* PWM: 0 - 255 per sensors documentation + REG: (6.25% duty cycle per bit) */ +static u8 ASB100_PWM_TO_REG(int pwm) +{ + pwm = SENSORS_LIMIT(pwm, 0, 255); + return (u8)(pwm / 16); +} + +static int ASB100_PWM_FROM_REG(u8 reg) +{ + return reg * 16; +} + +#define DIV_FROM_REG(val) (1 << (val)) + +/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) + REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ +static u8 DIV_TO_REG(long val) +{ + return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; +} + +/* For each registered client, we need to keep some data in memory. That + data is pointed to by client->data. The structure itself is + dynamically allocated, at the same time the client itself is allocated. */ +struct asb100_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + unsigned long last_updated; /* In jiffies */ + + /* array of 2 pointers to subclients */ + struct i2c_client *lm75[2]; + + char valid; /* !=0 if following fields are valid */ + u8 in[7]; /* Register value */ + u8 in_max[7]; /* Register value */ + u8 in_min[7]; /* Register value */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u16 temp[4]; /* Register value (0 and 3 are u8 only) */ + u16 temp_max[4]; /* Register value (0 and 3 are u8 only) */ + u16 temp_hyst[4]; /* Register value (0 and 3 are u8 only) */ + u8 fan_div[3]; /* Register encoding, right justified */ + u8 pwm; /* Register encoding */ + u8 vid; /* Register encoding, combined */ + u32 alarms; /* Register encoding, combined */ + u8 vrm; +}; + +static int asb100_read_value(struct i2c_client *client, u16 reg); +static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val); + +static int asb100_attach_adapter(struct i2c_adapter *adapter); +static int asb100_detect(struct i2c_adapter *adapter, int address, int kind); +static int asb100_detach_client(struct i2c_client *client); +static struct asb100_data *asb100_update_device(struct device *dev); +static void asb100_init_client(struct i2c_client *client); + +static struct i2c_driver asb100_driver = { + .owner = THIS_MODULE, + .name = "asb100", + .id = I2C_DRIVERID_ASB100, + .flags = I2C_DF_NOTIFY, + .attach_adapter = asb100_attach_adapter, + .detach_client = asb100_detach_client, +}; + +/* 7 Voltages */ +#define show_in_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct asb100_data *data = asb100_update_device(dev); \ + return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \ +} + +show_in_reg(in) +show_in_reg(in_min) +show_in_reg(in_max) + +#define set_in_reg(REG, reg) \ +static ssize_t set_in_##reg(struct device *dev, const char *buf, \ + size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct asb100_data *data = i2c_get_clientdata(client); \ + unsigned long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_##reg[nr] = IN_TO_REG(val); \ + asb100_write_value(client, ASB100_REG_IN_##REG(nr), \ + data->in_##reg[nr]); \ + up(&data->update_lock); \ + return count; \ +} + +set_in_reg(MIN, min) +set_in_reg(MAX, max) + +#define sysfs_in(offset) \ +static ssize_t \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in##offset, NULL); \ +static ssize_t \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +sysfs_in(0); +sysfs_in(1); +sysfs_in(2); +sysfs_in(3); +sysfs_in(4); +sysfs_in(5); +sysfs_in(6); + +#define device_create_file_in(client, offset) do { \ + device_create_file(&client->dev, &dev_attr_in##offset##_input); \ + device_create_file(&client->dev, &dev_attr_in##offset##_min); \ + device_create_file(&client->dev, &dev_attr_in##offset##_max); \ +} while (0) + +/* 3 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr]))); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr]))); +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + u32 val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + unsigned long min; + unsigned long val = simple_strtoul(buf, NULL, 10); + int reg; + + down(&data->update_lock); + + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + data->fan_div[nr] = DIV_TO_REG(val); + + switch(nr) { + case 0: /* fan 1 */ + reg = asb100_read_value(client, ASB100_REG_VID_FANDIV); + reg = (reg & 0xcf) | (data->fan_div[0] << 4); + asb100_write_value(client, ASB100_REG_VID_FANDIV, reg); + break; + + case 1: /* fan 2 */ + reg = asb100_read_value(client, ASB100_REG_VID_FANDIV); + reg = (reg & 0x3f) | (data->fan_div[1] << 6); + asb100_write_value(client, ASB100_REG_VID_FANDIV, reg); + break; + + case 2: /* fan 3 */ + reg = asb100_read_value(client, ASB100_REG_PIN); + reg = (reg & 0x3f) | (data->fan_div[2] << 6); + asb100_write_value(client, ASB100_REG_PIN, reg); + break; + } + + data->fan_min[nr] = + FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]); + + up(&data->update_lock); + + return count; +} + +#define sysfs_fan(offset) \ +static ssize_t show_fan##offset(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_fan_div(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan##offset, NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan##offset##_min, set_fan##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan##offset##_div, set_fan##offset##_div); + +sysfs_fan(1); +sysfs_fan(2); +sysfs_fan(3); + +#define device_create_file_fan(client, offset) do { \ + device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ + device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ + device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ +} while (0) + +/* 4 Temp. Sensors */ +static int sprintf_temp_from_reg(u16 reg, char *buf, int nr) +{ + int ret = 0; + + switch (nr) { + case 1: case 2: + ret = sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(reg)); + break; + case 0: case 3: default: + ret = sprintf(buf, "%d\n", TEMP_FROM_REG(reg)); + break; + } + return ret; +} + +#define show_temp_reg(reg) \ +static ssize_t show_##reg(struct device *dev, char *buf, int nr) \ +{ \ + struct asb100_data *data = asb100_update_device(dev); \ + return sprintf_temp_from_reg(data->reg[nr], buf, nr); \ +} + +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_hyst); + +#define set_temp_reg(REG, reg) \ +static ssize_t set_##reg(struct device *dev, const char *buf, \ + size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct asb100_data *data = i2c_get_clientdata(client); \ + unsigned long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + switch (nr) { \ + case 1: case 2: \ + data->reg[nr] = LM75_TEMP_TO_REG(val); \ + break; \ + case 0: case 3: default: \ + data->reg[nr] = TEMP_TO_REG(val); \ + break; \ + } \ + asb100_write_value(client, ASB100_REG_TEMP_##REG(nr+1), \ + data->reg[nr]); \ + up(&data->update_lock); \ + return count; \ +} + +set_temp_reg(MAX, temp_max); +set_temp_reg(HYST, temp_hyst); + +#define sysfs_temp(num) \ +static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, num-1); \ +} \ +static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL); \ +static ssize_t show_temp_max##num(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_max(dev, buf, num-1); \ +} \ +static ssize_t set_temp_max##num(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_temp_max(dev, buf, count, num-1); \ +} \ +static DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \ + show_temp_max##num, set_temp_max##num); \ +static ssize_t show_temp_hyst##num(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_hyst(dev, buf, num-1); \ +} \ +static ssize_t set_temp_hyst##num(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_temp_hyst(dev, buf, count, num-1); \ +} \ +static DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \ + show_temp_hyst##num, set_temp_hyst##num); + +sysfs_temp(1); +sysfs_temp(2); +sysfs_temp(3); +sysfs_temp(4); + +/* VID */ +#define device_create_file_temp(client, num) do { \ + device_create_file(&client->dev, &dev_attr_temp##num##_input); \ + device_create_file(&client->dev, &dev_attr_temp##num##_max); \ + device_create_file(&client->dev, &dev_attr_temp##num##_max_hyst); \ +} while (0) + +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); +} + +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +#define device_create_file_vid(client) \ +device_create_file(&client->dev, &dev_attr_cpu0_vid) + +/* VRM */ +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", data->vrm); +} + +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + return count; +} + +/* Alarms */ +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); +#define device_create_file_vrm(client) \ +device_create_file(&client->dev, &dev_attr_vrm); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +#define device_create_file_alarms(client) \ +device_create_file(&client->dev, &dev_attr_alarms) + +/* 1 PWM */ +static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", ASB100_PWM_FROM_REG(data->pwm & 0x0f)); +} + +static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->pwm &= 0x80; /* keep the enable bit */ + data->pwm |= (0x0f & ASB100_PWM_TO_REG(val)); + asb100_write_value(client, ASB100_REG_PWM1, data->pwm); + up(&data->update_lock); + return count; +} + +static ssize_t show_pwm_enable1(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct asb100_data *data = asb100_update_device(dev); + return sprintf(buf, "%d\n", (data->pwm & 0x80) ? 1 : 0); +} + +static ssize_t set_pwm_enable1(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->pwm &= 0x0f; /* keep the duty cycle bits */ + data->pwm |= (val ? 0x80 : 0x00); + asb100_write_value(client, ASB100_REG_PWM1, data->pwm); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1); +static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, + show_pwm_enable1, set_pwm_enable1); +#define device_create_file_pwm1(client) do { \ + device_create_file(&new_client->dev, &dev_attr_pwm1); \ + device_create_file(&new_client->dev, &dev_attr_pwm1_enable); \ +} while (0) + +/* This function is called when: + asb100_driver is inserted (when this module is loaded), for each + available adapter + when a new adapter is inserted (and asb100_driver is still present) + */ +static int asb100_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, asb100_detect); +} + +static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, + int kind, struct i2c_client *new_client) +{ + int i, id, err; + struct asb100_data *data = i2c_get_clientdata(new_client); + + data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[0])) { + err = -ENOMEM; + goto ERROR_SC_0; + } + memset(data->lm75[0], 0x00, sizeof(struct i2c_client)); + + data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[1])) { + err = -ENOMEM; + goto ERROR_SC_1; + } + memset(data->lm75[1], 0x00, sizeof(struct i2c_client)); + + id = i2c_adapter_id(adapter); + + if (force_subclients[0] == id && force_subclients[1] == address) { + for (i = 2; i <= 3; i++) { + if (force_subclients[i] < 0x48 || + force_subclients[i] > 0x4f) { + dev_err(&new_client->dev, "invalid subclient " + "address %d; must be 0x48-0x4f\n", + force_subclients[i]); + err = -ENODEV; + goto ERROR_SC_2; + } + } + asb100_write_value(new_client, ASB100_REG_I2C_SUBADDR, + (force_subclients[2] & 0x07) | + ((force_subclients[3] & 0x07) <<4)); + data->lm75[0]->addr = force_subclients[2]; + data->lm75[1]->addr = force_subclients[3]; + } else { + int val = asb100_read_value(new_client, ASB100_REG_I2C_SUBADDR); + data->lm75[0]->addr = 0x48 + (val & 0x07); + data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07); + } + + if(data->lm75[0]->addr == data->lm75[1]->addr) { + dev_err(&new_client->dev, "duplicate addresses 0x%x " + "for subclients\n", data->lm75[0]->addr); + err = -ENODEV; + goto ERROR_SC_2; + } + + for (i = 0; i <= 1; i++) { + i2c_set_clientdata(data->lm75[i], NULL); + data->lm75[i]->adapter = adapter; + data->lm75[i]->driver = &asb100_driver; + data->lm75[i]->flags = 0; + strlcpy(data->lm75[i]->name, "asb100 subclient", I2C_NAME_SIZE); + } + + if ((err = i2c_attach_client(data->lm75[0]))) { + dev_err(&new_client->dev, "subclient %d registration " + "at address 0x%x failed.\n", i, data->lm75[0]->addr); + goto ERROR_SC_2; + } + + if ((err = i2c_attach_client(data->lm75[1]))) { + dev_err(&new_client->dev, "subclient %d registration " + "at address 0x%x failed.\n", i, data->lm75[1]->addr); + goto ERROR_SC_3; + } + + return 0; + +/* Undo inits in case of errors */ +ERROR_SC_3: + i2c_detach_client(data->lm75[0]); +ERROR_SC_2: + kfree(data->lm75[1]); +ERROR_SC_1: + kfree(data->lm75[0]); +ERROR_SC_0: + return err; +} + +static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int err; + struct i2c_client *new_client; + struct asb100_data *data; + + /* asb100 is SMBus only */ + if (i2c_is_isa_adapter(adapter)) { + pr_debug("asb100.o: detect failed, " + "cannot attach to legacy adapter!\n"); + err = -ENODEV; + goto ERROR0; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + pr_debug("asb100.o: detect failed, " + "smbus byte data not supported!\n"); + err = -ENODEV; + goto ERROR0; + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access asb100_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct asb100_data), GFP_KERNEL))) { + pr_debug("asb100.o: detect failed, kmalloc failed!\n"); + err = -ENOMEM; + goto ERROR0; + } + memset(data, 0, sizeof(struct asb100_data)); + + new_client = &data->client; + init_MUTEX(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &asb100_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + /* The chip may be stuck in some other bank than bank 0. This may + make reading other information impossible. Specify a force=... or + force_*=... parameter, and the chip will be reset to the right + bank. */ + if (kind < 0) { + + int val1 = asb100_read_value(new_client, ASB100_REG_BANK); + int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); + + /* If we're in bank 0 */ + if ( (!(val1 & 0x07)) && + /* Check for ASB100 ID (low byte) */ + ( ((!(val1 & 0x80)) && (val2 != 0x94)) || + /* Check for ASB100 ID (high byte ) */ + ((val1 & 0x80) && (val2 != 0x06)) ) ) { + pr_debug("asb100.o: detect failed, " + "bad chip id 0x%02x!\n", val2); + err = -ENODEV; + goto ERROR1; + } + + } /* kind < 0 */ + + /* We have either had a force parameter, or we have already detected + Winbond. Put it now into bank 0 and Vendor ID High Byte */ + asb100_write_value(new_client, ASB100_REG_BANK, + (asb100_read_value(new_client, ASB100_REG_BANK) & 0x78) | 0x80); + + /* Determine the chip type. */ + if (kind <= 0) { + int val1 = asb100_read_value(new_client, ASB100_REG_WCHIPID); + int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); + + if ((val1 == 0x31) && (val2 == 0x06)) + kind = asb100; + else { + if (kind == 0) + dev_warn(&new_client->dev, "ignoring " + "'force' parameter for unknown chip " + "at adapter %d, address 0x%02x.\n", + i2c_adapter_id(adapter), address); + err = -ENODEV; + goto ERROR1; + } + } + + /* Fill in remaining client fields and put it into the global list */ + strlcpy(new_client->name, "asb100", I2C_NAME_SIZE); + data->type = kind; + + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR1; + + /* Attach secondary lm75 clients */ + if ((err = asb100_detect_subclients(adapter, address, kind, + new_client))) + goto ERROR2; + + /* Initialize the chip */ + asb100_init_client(new_client); + + /* A few vars need to be filled upon startup */ + data->fan_min[0] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(0)); + data->fan_min[1] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(1)); + data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2)); + + /* Register sysfs hooks */ + device_create_file_in(new_client, 0); + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + device_create_file_in(new_client, 3); + device_create_file_in(new_client, 4); + device_create_file_in(new_client, 5); + device_create_file_in(new_client, 6); + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + device_create_file_fan(new_client, 3); + + device_create_file_temp(new_client, 1); + device_create_file_temp(new_client, 2); + device_create_file_temp(new_client, 3); + device_create_file_temp(new_client, 4); + + device_create_file_vid(new_client); + device_create_file_vrm(new_client); + + device_create_file_alarms(new_client); + + device_create_file_pwm1(new_client); + + return 0; + +ERROR2: + i2c_detach_client(new_client); +ERROR1: + kfree(data); +ERROR0: + return err; +} + +static int asb100_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "client deregistration failed; " + "client not detached.\n"); + return err; + } + + if (i2c_get_clientdata(client)==NULL) { + /* subclients */ + kfree(client); + } else { + /* main client */ + kfree(i2c_get_clientdata(client)); + } + + return 0; +} + +/* The SMBus locks itself, usually, but nothing may access the chip between + bank switches. */ +static int asb100_read_value(struct i2c_client *client, u16 reg) +{ + struct asb100_data *data = i2c_get_clientdata(client); + struct i2c_client *cl; + int res, bank; + + down(&data->lock); + + bank = (reg >> 8) & 0x0f; + if (bank > 2) + /* switch banks */ + i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); + + if (bank == 0 || bank > 2) { + res = i2c_smbus_read_byte_data(client, reg & 0xff); + } else { + /* switch to subclient */ + cl = data->lm75[bank - 1]; + + /* convert from ISA to LM75 I2C addresses */ + switch (reg & 0xff) { + case 0x50: /* TEMP */ + res = swab16(i2c_smbus_read_word_data (cl, 0)); + break; + case 0x52: /* CONFIG */ + res = i2c_smbus_read_byte_data(cl, 1); + break; + case 0x53: /* HYST */ + res = swab16(i2c_smbus_read_word_data (cl, 2)); + break; + case 0x55: /* MAX */ + default: + res = swab16(i2c_smbus_read_word_data (cl, 3)); + break; + } + } + + if (bank > 2) + i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); + + up(&data->lock); + + return res; +} + +static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value) +{ + struct asb100_data *data = i2c_get_clientdata(client); + struct i2c_client *cl; + int bank; + + down(&data->lock); + + bank = (reg >> 8) & 0x0f; + if (bank > 2) + /* switch banks */ + i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); + + if (bank == 0 || bank > 2) { + i2c_smbus_write_byte_data(client, reg & 0xff, value & 0xff); + } else { + /* switch to subclient */ + cl = data->lm75[bank - 1]; + + /* convert from ISA to LM75 I2C addresses */ + switch (reg & 0xff) { + case 0x52: /* CONFIG */ + i2c_smbus_write_byte_data(cl, 1, value & 0xff); + break; + case 0x53: /* HYST */ + i2c_smbus_write_word_data(cl, 2, swab16(value)); + break; + case 0x55: /* MAX */ + i2c_smbus_write_word_data(cl, 3, swab16(value)); + break; + } + } + + if (bank > 2) + i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); + + up(&data->lock); +} + +static void asb100_init_client(struct i2c_client *client) +{ + struct asb100_data *data = i2c_get_clientdata(client); + int vid = 0; + + vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f; + vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4; + data->vrm = i2c_which_vrm(); + vid = vid_from_reg(vid, data->vrm); + + /* Start monitoring */ + asb100_write_value(client, ASB100_REG_CONFIG, + (asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01); +} + +static struct asb100_data *asb100_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct asb100_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + dev_dbg(&client->dev, "starting device update...\n"); + + /* 7 voltage inputs */ + for (i = 0; i < 7; i++) { + data->in[i] = asb100_read_value(client, + ASB100_REG_IN(i)); + data->in_min[i] = asb100_read_value(client, + ASB100_REG_IN_MIN(i)); + data->in_max[i] = asb100_read_value(client, + ASB100_REG_IN_MAX(i)); + } + + /* 3 fan inputs */ + for (i = 0; i < 3; i++) { + data->fan[i] = asb100_read_value(client, + ASB100_REG_FAN(i)); + data->fan_min[i] = asb100_read_value(client, + ASB100_REG_FAN_MIN(i)); + } + + /* 4 temperature inputs */ + for (i = 1; i <= 4; i++) { + data->temp[i-1] = asb100_read_value(client, + ASB100_REG_TEMP(i)); + data->temp_max[i-1] = asb100_read_value(client, + ASB100_REG_TEMP_MAX(i)); + data->temp_hyst[i-1] = asb100_read_value(client, + ASB100_REG_TEMP_HYST(i)); + } + + /* VID and fan divisors */ + i = asb100_read_value(client, ASB100_REG_VID_FANDIV); + data->vid = i & 0x0f; + data->vid |= (asb100_read_value(client, + ASB100_REG_CHIPID) & 0x01) << 4; + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + data->fan_div[2] = (asb100_read_value(client, + ASB100_REG_PIN) >> 6) & 0x03; + + /* PWM */ + data->pwm = asb100_read_value(client, ASB100_REG_PWM1); + + /* alarms */ + data->alarms = asb100_read_value(client, ASB100_REG_ALARM1) + + (asb100_read_value(client, ASB100_REG_ALARM2) << 8); + + data->last_updated = jiffies; + data->valid = 1; + + dev_dbg(&client->dev, "... device update complete\n"); + } + + up(&data->update_lock); + + return data; +} + +static int __init asb100_init(void) +{ + return i2c_add_driver(&asb100_driver); +} + +static void __exit asb100_exit(void) +{ + i2c_del_driver(&asb100_driver); +} + +MODULE_AUTHOR("Mark M. Hoffman "); +MODULE_DESCRIPTION("ASB100 Bach driver"); +MODULE_LICENSE("GPL"); + +module_init(asb100_init); +module_exit(asb100_exit); + diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c new file mode 100644 index 00000000000..0bcf82b4c07 --- /dev/null +++ b/drivers/hwmon/atxp1.c @@ -0,0 +1,361 @@ +/* + atxp1.c - kernel module for setting CPU VID and general purpose + I/Os using the Attansic ATXP1 chip. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); +MODULE_VERSION("0.6.2"); +MODULE_AUTHOR("Sebastian Witt "); + +#define ATXP1_VID 0x00 +#define ATXP1_CVID 0x01 +#define ATXP1_GPIO1 0x06 +#define ATXP1_GPIO2 0x0a +#define ATXP1_VIDENA 0x20 +#define ATXP1_VIDMASK 0x1f +#define ATXP1_GPIO1MASK 0x0f + +static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +SENSORS_INSMOD_1(atxp1); + +static int atxp1_attach_adapter(struct i2c_adapter * adapter); +static int atxp1_detach_client(struct i2c_client * client); +static struct atxp1_data * atxp1_update_device(struct device *dev); +static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind); + +static struct i2c_driver atxp1_driver = { + .owner = THIS_MODULE, + .name = "atxp1", + .flags = I2C_DF_NOTIFY, + .attach_adapter = atxp1_attach_adapter, + .detach_client = atxp1_detach_client, +}; + +struct atxp1_data { + struct i2c_client client; + struct semaphore update_lock; + unsigned long last_updated; + u8 valid; + struct { + u8 vid; /* VID output register */ + u8 cpu_vid; /* VID input from CPU */ + u8 gpio1; /* General purpose I/O register 1 */ + u8 gpio2; /* General purpose I/O register 2 */ + } reg; + u8 vrm; /* Detected CPU VRM */ +}; + +static struct atxp1_data * atxp1_update_device(struct device *dev) +{ + struct i2c_client *client; + struct atxp1_data *data; + + client = to_i2c_client(dev); + data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ) || + (jiffies < data->last_updated) || + !data->valid) { + + /* Update local register data */ + data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID); + data->reg.cpu_vid = i2c_smbus_read_byte_data(client, ATXP1_CVID); + data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1); + data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2); + + data->valid = 1; + } + + up(&data->update_lock); + + return(data); +} + +/* sys file functions for cpu0_vid */ +static ssize_t atxp1_showvcore(struct device *dev, struct device_attribute *attr, char *buf) +{ + int size; + struct atxp1_data *data; + + data = atxp1_update_device(dev); + + size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, data->vrm)); + + return size; +} + +static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct atxp1_data *data; + struct i2c_client *client; + char vid; + char cvid; + unsigned int vcore; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + vcore = simple_strtoul(buf, NULL, 10); + vcore /= 25; + vcore *= 25; + + /* Calculate VID */ + vid = vid_to_reg(vcore, data->vrm); + + if (vid < 0) { + dev_err(dev, "VID calculation failed.\n"); + return -1; + } + + /* If output enabled, use control register value. Otherwise original CPU VID */ + if (data->reg.vid & ATXP1_VIDENA) + cvid = data->reg.vid & ATXP1_VIDMASK; + else + cvid = data->reg.cpu_vid; + + /* Nothing changed, aborting */ + if (vid == cvid) + return count; + + dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid); + + /* Write every 25 mV step to increase stability */ + if (cvid > vid) { + for (; cvid >= vid; cvid--) { + i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); + } + } + else { + for (; cvid <= vid; cvid++) { + i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); + } + } + + data->valid = 0; + + return count; +} + +/* CPU core reference voltage + unit: millivolt +*/ +static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore); + +/* sys file functions for GPIO1 */ +static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr, char *buf) +{ + int size; + struct atxp1_data *data; + + data = atxp1_update_device(dev); + + size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK); + + return size; +} + +static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *attr, const char*buf, size_t count) +{ + struct atxp1_data *data; + struct i2c_client *client; + unsigned int value; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + value = simple_strtoul(buf, NULL, 16); + + value &= ATXP1_GPIO1MASK; + + if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) { + dev_info(dev, "Writing 0x%x to GPIO1.\n", value); + + i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value); + + data->valid = 0; + } + + return count; +} + +/* GPIO1 data register + unit: Four bit as hex (e.g. 0x0f) +*/ +static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); + +/* sys file functions for GPIO2 */ +static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr, char *buf) +{ + int size; + struct atxp1_data *data; + + data = atxp1_update_device(dev); + + size = sprintf(buf, "0x%02x\n", data->reg.gpio2); + + return size; +} + +static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct atxp1_data *data; + struct i2c_client *client; + unsigned int value; + + client = to_i2c_client(dev); + data = atxp1_update_device(dev); + + value = simple_strtoul(buf, NULL, 16) & 0xff; + + if (value != data->reg.gpio2) { + dev_info(dev, "Writing 0x%x to GPIO1.\n", value); + + i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value); + + data->valid = 0; + } + + return count; +} + +/* GPIO2 data register + unit: Eight bit as hex (e.g. 0xff) +*/ +static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); + + +static int atxp1_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, &atxp1_detect); +}; + +static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client * new_client; + struct atxp1_data * data; + int err = 0; + u8 temp; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + memset(data, 0, sizeof(struct atxp1_data)); + new_client = &data->client; + i2c_set_clientdata(new_client, data); + + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &atxp1_driver; + new_client->flags = 0; + + /* Detect ATXP1, checking if vendor ID registers are all zero */ + if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) && + (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) && + (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) && + (i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) { + + /* No vendor ID, now checking if registers 0x10,0x11 (non-existent) + * showing the same as register 0x00 */ + temp = i2c_smbus_read_byte_data(new_client, 0x00); + + if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) && + (i2c_smbus_read_byte_data(new_client, 0x11) == temp) )) + goto exit_free; + } + + /* Get VRM */ + data->vrm = i2c_which_vrm(); + + if ((data->vrm != 90) && (data->vrm != 91)) { + dev_err(&new_client->dev, "Not supporting VRM %d.%d\n", + data->vrm / 10, data->vrm % 10); + goto exit_free; + } + + strncpy(new_client->name, "atxp1", I2C_NAME_SIZE); + + data->valid = 0; + + init_MUTEX(&data->update_lock); + + err = i2c_attach_client(new_client); + + if (err) + { + dev_err(&new_client->dev, "Attach client error.\n"); + goto exit_free; + } + + device_create_file(&new_client->dev, &dev_attr_gpio1); + device_create_file(&new_client->dev, &dev_attr_gpio2); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + + dev_info(&new_client->dev, "Using VRM: %d.%d\n", + data->vrm / 10, data->vrm % 10); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +}; + +static int atxp1_detach_client(struct i2c_client * client) +{ + int err; + + err = i2c_detach_client(client); + + if (err) + dev_err(&client->dev, "Failed to detach client.\n"); + else + kfree(i2c_get_clientdata(client)); + + return err; +}; + +static int __init atxp1_init(void) +{ + return i2c_add_driver(&atxp1_driver); +}; + +static void __exit atxp1_exit(void) +{ + i2c_del_driver(&atxp1_driver); +}; + +module_init(atxp1_init); +module_exit(atxp1_exit); diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c new file mode 100644 index 00000000000..5360d58804f --- /dev/null +++ b/drivers/hwmon/ds1621.c @@ -0,0 +1,341 @@ +/* + ds1621.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Christian W. Zuckschwerdt 2000-11-23 + based on lm75.c by Frodo Looijaard + Ported to Linux 2.6 by Aurelien Jarno with + the help of Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include "lm75.h" + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(ds1621); +static int polarity = -1; +module_param(polarity, int, 0); +MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low"); + +/* Many DS1621 constants specified below */ +/* Config register used for detection */ +/* 7 6 5 4 3 2 1 0 */ +/* |Done|THF |TLF |NVB | X | X |POL |1SHOT| */ +#define DS1621_REG_CONFIG_NVB 0x10 +#define DS1621_REG_CONFIG_POLARITY 0x02 +#define DS1621_REG_CONFIG_1SHOT 0x01 +#define DS1621_REG_CONFIG_DONE 0x80 + +/* The DS1621 registers */ +#define DS1621_REG_TEMP 0xAA /* word, RO */ +#define DS1621_REG_TEMP_MIN 0xA1 /* word, RW */ +#define DS1621_REG_TEMP_MAX 0xA2 /* word, RW */ +#define DS1621_REG_CONF 0xAC /* byte, RW */ +#define DS1621_COM_START 0xEE /* no data */ +#define DS1621_COM_STOP 0x22 /* no data */ + +/* The DS1621 configuration register */ +#define DS1621_ALARM_TEMP_HIGH 0x40 +#define DS1621_ALARM_TEMP_LOW 0x20 + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +#define ALARMS_FROM_REG(val) ((val) & \ + (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) + +/* Each client has this additional data */ +struct ds1621_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u16 temp, temp_min, temp_max; /* Register values, word */ + u8 conf; /* Register encoding, combined */ +}; + +static int ds1621_attach_adapter(struct i2c_adapter *adapter); +static int ds1621_detect(struct i2c_adapter *adapter, int address, + int kind); +static void ds1621_init_client(struct i2c_client *client); +static int ds1621_detach_client(struct i2c_client *client); +static struct ds1621_data *ds1621_update_client(struct device *dev); + +/* This is the driver that will be inserted */ +static struct i2c_driver ds1621_driver = { + .owner = THIS_MODULE, + .name = "ds1621", + .id = I2C_DRIVERID_DS1621, + .flags = I2C_DF_NOTIFY, + .attach_adapter = ds1621_attach_adapter, + .detach_client = ds1621_detach_client, +}; + +/* All registers are word-sized, except for the configuration register. + DS1621 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +static int ds1621_read_value(struct i2c_client *client, u8 reg) +{ + if (reg == DS1621_REG_CONF) + return i2c_smbus_read_byte_data(client, reg); + else + return swab16(i2c_smbus_read_word_data(client, reg)); +} + +/* All registers are word-sized, except for the configuration register. + DS1621 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (reg == DS1621_REG_CONF) + return i2c_smbus_write_byte_data(client, reg, value); + else + return i2c_smbus_write_word_data(client, reg, swab16(value)); +} + +static void ds1621_init_client(struct i2c_client *client) +{ + int reg = ds1621_read_value(client, DS1621_REG_CONF); + /* switch to continuous conversion mode */ + reg &= ~ DS1621_REG_CONFIG_1SHOT; + + /* setup output polarity */ + if (polarity == 0) + reg &= ~DS1621_REG_CONFIG_POLARITY; + else if (polarity == 1) + reg |= DS1621_REG_CONFIG_POLARITY; + + ds1621_write_value(client, DS1621_REG_CONF, reg); + + /* start conversion */ + i2c_smbus_write_byte(client, DS1621_COM_START); +} + +#define show(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct ds1621_data *data = ds1621_update_client(dev); \ + return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ +} + +show(temp); +show(temp_min); +show(temp_max); + +#define set_temp(suffix, value, reg) \ +static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct ds1621_data *data = ds1621_update_client(dev); \ + u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \ + \ + down(&data->update_lock); \ + data->value = val; \ + ds1621_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} + +set_temp(min, temp_min, DS1621_REG_TEMP_MIN); +set_temp(max, temp_max, DS1621_REG_TEMP_MAX); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct ds1621_data *data = ds1621_update_client(dev); + return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf)); +} + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL); +static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min); +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); + + +static int ds1621_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, ds1621_detect); +} + +/* This function is called by i2c_detect */ +int ds1621_detect(struct i2c_adapter *adapter, int address, + int kind) +{ + int conf, temp; + struct i2c_client *new_client; + struct ds1621_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_WORD_DATA + | I2C_FUNC_SMBUS_WRITE_BYTE)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access ds1621_{read,write}_value. */ + if (!(data = kmalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct ds1621_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &ds1621_driver; + new_client->flags = 0; + + + /* Now, we do the remaining detection. It is lousy. */ + if (kind < 0) { + /* The NVB bit should be low if no EEPROM write has been + requested during the latest 10ms, which is highly + improbable in our case. */ + conf = ds1621_read_value(new_client, DS1621_REG_CONF); + if (conf & DS1621_REG_CONFIG_NVB) + goto exit_free; + /* The 7 lowest bits of a temperature should always be 0. */ + temp = ds1621_read_value(new_client, DS1621_REG_TEMP); + if (temp & 0x007f) + goto exit_free; + temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MIN); + if (temp & 0x007f) + goto exit_free; + temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MAX); + if (temp & 0x007f) + goto exit_free; + } + + /* Determine the chip type - only one kind supported! */ + if (kind <= 0) + kind = ds1621; + + /* Fill in remaining client fields and put it into the global list */ + strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the DS1621 chip */ + ds1621_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + + return 0; + +/* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + exit_free: + kfree(data); + exit: + return err; +} + +static int ds1621_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + + return 0; +} + + +static struct ds1621_data *ds1621_update_client(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ds1621_data *data = i2c_get_clientdata(client); + u8 new_conf; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + dev_dbg(&client->dev, "Starting ds1621 update\n"); + + data->conf = ds1621_read_value(client, DS1621_REG_CONF); + + data->temp = ds1621_read_value(client, DS1621_REG_TEMP); + + data->temp_min = ds1621_read_value(client, + DS1621_REG_TEMP_MIN); + data->temp_max = ds1621_read_value(client, + DS1621_REG_TEMP_MAX); + + /* reset alarms if necessary */ + new_conf = data->conf; + if (data->temp < data->temp_min) + new_conf &= ~DS1621_ALARM_TEMP_LOW; + if (data->temp > data->temp_max) + new_conf &= ~DS1621_ALARM_TEMP_HIGH; + if (data->conf != new_conf) + ds1621_write_value(client, DS1621_REG_CONF, + new_conf); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init ds1621_init(void) +{ + return i2c_add_driver(&ds1621_driver); +} + +static void __exit ds1621_exit(void) +{ + i2c_del_driver(&ds1621_driver); +} + + +MODULE_AUTHOR("Christian W. Zuckschwerdt "); +MODULE_DESCRIPTION("DS1621 driver"); +MODULE_LICENSE("GPL"); + +module_init(ds1621_init); +module_exit(ds1621_exit); diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c new file mode 100644 index 00000000000..da411741c2c --- /dev/null +++ b/drivers/hwmon/fscher.c @@ -0,0 +1,691 @@ +/* + * fscher.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2003, 2004 Reinhard Nissl + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * fujitsu siemens hermes chip, + * module based on fscpos.c + * Copyright (C) 2000 Hermann Jung + * Copyright (C) 1998, 1999 Frodo Looijaard + * and Philip Edelbrock + */ + +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan + */ + +static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(fscher); + +/* + * The FSCHER registers + */ + +/* chip identification */ +#define FSCHER_REG_IDENT_0 0x00 +#define FSCHER_REG_IDENT_1 0x01 +#define FSCHER_REG_IDENT_2 0x02 +#define FSCHER_REG_REVISION 0x03 + +/* global control and status */ +#define FSCHER_REG_EVENT_STATE 0x04 +#define FSCHER_REG_CONTROL 0x05 + +/* watchdog */ +#define FSCHER_REG_WDOG_PRESET 0x28 +#define FSCHER_REG_WDOG_STATE 0x23 +#define FSCHER_REG_WDOG_CONTROL 0x21 + +/* fan 0 */ +#define FSCHER_REG_FAN0_MIN 0x55 +#define FSCHER_REG_FAN0_ACT 0x0e +#define FSCHER_REG_FAN0_STATE 0x0d +#define FSCHER_REG_FAN0_RIPPLE 0x0f + +/* fan 1 */ +#define FSCHER_REG_FAN1_MIN 0x65 +#define FSCHER_REG_FAN1_ACT 0x6b +#define FSCHER_REG_FAN1_STATE 0x62 +#define FSCHER_REG_FAN1_RIPPLE 0x6f + +/* fan 2 */ +#define FSCHER_REG_FAN2_MIN 0xb5 +#define FSCHER_REG_FAN2_ACT 0xbb +#define FSCHER_REG_FAN2_STATE 0xb2 +#define FSCHER_REG_FAN2_RIPPLE 0xbf + +/* voltage supervision */ +#define FSCHER_REG_VOLT_12 0x45 +#define FSCHER_REG_VOLT_5 0x42 +#define FSCHER_REG_VOLT_BATT 0x48 + +/* temperature 0 */ +#define FSCHER_REG_TEMP0_ACT 0x64 +#define FSCHER_REG_TEMP0_STATE 0x71 + +/* temperature 1 */ +#define FSCHER_REG_TEMP1_ACT 0x32 +#define FSCHER_REG_TEMP1_STATE 0x81 + +/* temperature 2 */ +#define FSCHER_REG_TEMP2_ACT 0x35 +#define FSCHER_REG_TEMP2_STATE 0x91 + +/* + * Functions declaration + */ + +static int fscher_attach_adapter(struct i2c_adapter *adapter); +static int fscher_detect(struct i2c_adapter *adapter, int address, int kind); +static int fscher_detach_client(struct i2c_client *client); +static struct fscher_data *fscher_update_device(struct device *dev); +static void fscher_init_client(struct i2c_client *client); + +static int fscher_read_value(struct i2c_client *client, u8 reg); +static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver fscher_driver = { + .owner = THIS_MODULE, + .name = "fscher", + .id = I2C_DRIVERID_FSCHER, + .flags = I2C_DF_NOTIFY, + .attach_adapter = fscher_attach_adapter, + .detach_client = fscher_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct fscher_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* register values */ + u8 revision; /* revision of chip */ + u8 global_event; /* global event status */ + u8 global_control; /* global control register */ + u8 watchdog[3]; /* watchdog */ + u8 volt[3]; /* 12, 5, battery voltage */ + u8 temp_act[3]; /* temperature */ + u8 temp_status[3]; /* status of sensor */ + u8 fan_act[3]; /* fans revolutions per second */ + u8 fan_status[3]; /* fan status */ + u8 fan_min[3]; /* fan min value for rps */ + u8 fan_ripple[3]; /* divider for rps */ +}; + +/* + * Sysfs stuff + */ + +#define sysfs_r(kind, sub, offset, reg) \ +static ssize_t show_##kind##sub (struct fscher_data *, char *, int); \ +static ssize_t show_##kind##offset##sub (struct device *, struct device_attribute *attr, char *); \ +static ssize_t show_##kind##offset##sub (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct fscher_data *data = fscher_update_device(dev); \ + return show_##kind##sub(data, buf, (offset)); \ +} + +#define sysfs_w(kind, sub, offset, reg) \ +static ssize_t set_##kind##sub (struct i2c_client *, struct fscher_data *, const char *, size_t, int, int); \ +static ssize_t set_##kind##offset##sub (struct device *, struct device_attribute *attr, const char *, size_t); \ +static ssize_t set_##kind##offset##sub (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct fscher_data *data = i2c_get_clientdata(client); \ + return set_##kind##sub(client, data, buf, count, (offset), reg); \ +} + +#define sysfs_rw_n(kind, sub, offset, reg) \ +sysfs_r(kind, sub, offset, reg) \ +sysfs_w(kind, sub, offset, reg) \ +static DEVICE_ATTR(kind##offset##sub, S_IRUGO | S_IWUSR, show_##kind##offset##sub, set_##kind##offset##sub); + +#define sysfs_rw(kind, sub, reg) \ +sysfs_r(kind, sub, 0, reg) \ +sysfs_w(kind, sub, 0, reg) \ +static DEVICE_ATTR(kind##sub, S_IRUGO | S_IWUSR, show_##kind##0##sub, set_##kind##0##sub); + +#define sysfs_ro_n(kind, sub, offset, reg) \ +sysfs_r(kind, sub, offset, reg) \ +static DEVICE_ATTR(kind##offset##sub, S_IRUGO, show_##kind##offset##sub, NULL); + +#define sysfs_ro(kind, sub, reg) \ +sysfs_r(kind, sub, 0, reg) \ +static DEVICE_ATTR(kind, S_IRUGO, show_##kind##0##sub, NULL); + +#define sysfs_fan(offset, reg_status, reg_min, reg_ripple, reg_act) \ +sysfs_rw_n(pwm, , offset, reg_min) \ +sysfs_rw_n(fan, _status, offset, reg_status) \ +sysfs_rw_n(fan, _div , offset, reg_ripple) \ +sysfs_ro_n(fan, _input , offset, reg_act) + +#define sysfs_temp(offset, reg_status, reg_act) \ +sysfs_rw_n(temp, _status, offset, reg_status) \ +sysfs_ro_n(temp, _input , offset, reg_act) + +#define sysfs_in(offset, reg_act) \ +sysfs_ro_n(in, _input, offset, reg_act) + +#define sysfs_revision(reg_revision) \ +sysfs_ro(revision, , reg_revision) + +#define sysfs_alarms(reg_events) \ +sysfs_ro(alarms, , reg_events) + +#define sysfs_control(reg_control) \ +sysfs_rw(control, , reg_control) + +#define sysfs_watchdog(reg_control, reg_status, reg_preset) \ +sysfs_rw(watchdog, _control, reg_control) \ +sysfs_rw(watchdog, _status , reg_status) \ +sysfs_rw(watchdog, _preset , reg_preset) + +sysfs_fan(1, FSCHER_REG_FAN0_STATE, FSCHER_REG_FAN0_MIN, + FSCHER_REG_FAN0_RIPPLE, FSCHER_REG_FAN0_ACT) +sysfs_fan(2, FSCHER_REG_FAN1_STATE, FSCHER_REG_FAN1_MIN, + FSCHER_REG_FAN1_RIPPLE, FSCHER_REG_FAN1_ACT) +sysfs_fan(3, FSCHER_REG_FAN2_STATE, FSCHER_REG_FAN2_MIN, + FSCHER_REG_FAN2_RIPPLE, FSCHER_REG_FAN2_ACT) + +sysfs_temp(1, FSCHER_REG_TEMP0_STATE, FSCHER_REG_TEMP0_ACT) +sysfs_temp(2, FSCHER_REG_TEMP1_STATE, FSCHER_REG_TEMP1_ACT) +sysfs_temp(3, FSCHER_REG_TEMP2_STATE, FSCHER_REG_TEMP2_ACT) + +sysfs_in(0, FSCHER_REG_VOLT_12) +sysfs_in(1, FSCHER_REG_VOLT_5) +sysfs_in(2, FSCHER_REG_VOLT_BATT) + +sysfs_revision(FSCHER_REG_REVISION) +sysfs_alarms(FSCHER_REG_EVENTS) +sysfs_control(FSCHER_REG_CONTROL) +sysfs_watchdog(FSCHER_REG_WDOG_CONTROL, FSCHER_REG_WDOG_STATE, FSCHER_REG_WDOG_PRESET) + +#define device_create_file_fan(client, offset) \ +do { \ + device_create_file(&client->dev, &dev_attr_fan##offset##_status); \ + device_create_file(&client->dev, &dev_attr_pwm##offset); \ + device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ + device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ +} while (0) + +#define device_create_file_temp(client, offset) \ +do { \ + device_create_file(&client->dev, &dev_attr_temp##offset##_status); \ + device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ +} while (0) + +#define device_create_file_in(client, offset) \ +do { \ + device_create_file(&client->dev, &dev_attr_in##offset##_input); \ +} while (0) + +#define device_create_file_revision(client) \ +do { \ + device_create_file(&client->dev, &dev_attr_revision); \ +} while (0) + +#define device_create_file_alarms(client) \ +do { \ + device_create_file(&client->dev, &dev_attr_alarms); \ +} while (0) + +#define device_create_file_control(client) \ +do { \ + device_create_file(&client->dev, &dev_attr_control); \ +} while (0) + +#define device_create_file_watchdog(client) \ +do { \ + device_create_file(&client->dev, &dev_attr_watchdog_status); \ + device_create_file(&client->dev, &dev_attr_watchdog_control); \ + device_create_file(&client->dev, &dev_attr_watchdog_preset); \ +} while (0) + +/* + * Real code + */ + +static int fscher_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, fscher_detect); +} + +static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct fscher_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + * client structure, even though we cannot fill it completely yet. + * But it allows us to access i2c_smbus_read_byte_data. */ + if (!(data = kmalloc(sizeof(struct fscher_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct fscher_data)); + + /* The common I2C client data is placed right before the + * Hermes-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &fscher_driver; + new_client->flags = 0; + + /* Do the remaining detection unless force or force_fscher parameter */ + if (kind < 0) { + if ((i2c_smbus_read_byte_data(new_client, + FSCHER_REG_IDENT_0) != 0x48) /* 'H' */ + || (i2c_smbus_read_byte_data(new_client, + FSCHER_REG_IDENT_1) != 0x45) /* 'E' */ + || (i2c_smbus_read_byte_data(new_client, + FSCHER_REG_IDENT_2) != 0x52)) /* 'R' */ + goto exit_free; + } + + /* Fill in the remaining client fields and put it into the + * global list */ + strlcpy(new_client->name, "fscher", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + fscher_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file_revision(new_client); + device_create_file_alarms(new_client); + device_create_file_control(new_client); + device_create_file_watchdog(new_client); + + device_create_file_in(new_client, 0); + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + device_create_file_fan(new_client, 3); + + device_create_file_temp(new_client, 1); + device_create_file_temp(new_client, 2); + device_create_file_temp(new_client, 3); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int fscher_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static int fscher_read_value(struct i2c_client *client, u8 reg) +{ + dev_dbg(&client->dev, "read reg 0x%02x\n", reg); + + return i2c_smbus_read_byte_data(client, reg); +} + +static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + dev_dbg(&client->dev, "write reg 0x%02x, val 0x%02x\n", + reg, value); + + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* Called when we have found a new FSC Hermes. */ +static void fscher_init_client(struct i2c_client *client) +{ + struct fscher_data *data = i2c_get_clientdata(client); + + /* Read revision from chip */ + data->revision = fscher_read_value(client, FSCHER_REG_REVISION); +} + +static struct fscher_data *fscher_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fscher_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + + dev_dbg(&client->dev, "Starting fscher update\n"); + + data->temp_act[0] = fscher_read_value(client, FSCHER_REG_TEMP0_ACT); + data->temp_act[1] = fscher_read_value(client, FSCHER_REG_TEMP1_ACT); + data->temp_act[2] = fscher_read_value(client, FSCHER_REG_TEMP2_ACT); + data->temp_status[0] = fscher_read_value(client, FSCHER_REG_TEMP0_STATE); + data->temp_status[1] = fscher_read_value(client, FSCHER_REG_TEMP1_STATE); + data->temp_status[2] = fscher_read_value(client, FSCHER_REG_TEMP2_STATE); + + data->volt[0] = fscher_read_value(client, FSCHER_REG_VOLT_12); + data->volt[1] = fscher_read_value(client, FSCHER_REG_VOLT_5); + data->volt[2] = fscher_read_value(client, FSCHER_REG_VOLT_BATT); + + data->fan_act[0] = fscher_read_value(client, FSCHER_REG_FAN0_ACT); + data->fan_act[1] = fscher_read_value(client, FSCHER_REG_FAN1_ACT); + data->fan_act[2] = fscher_read_value(client, FSCHER_REG_FAN2_ACT); + data->fan_status[0] = fscher_read_value(client, FSCHER_REG_FAN0_STATE); + data->fan_status[1] = fscher_read_value(client, FSCHER_REG_FAN1_STATE); + data->fan_status[2] = fscher_read_value(client, FSCHER_REG_FAN2_STATE); + data->fan_min[0] = fscher_read_value(client, FSCHER_REG_FAN0_MIN); + data->fan_min[1] = fscher_read_value(client, FSCHER_REG_FAN1_MIN); + data->fan_min[2] = fscher_read_value(client, FSCHER_REG_FAN2_MIN); + data->fan_ripple[0] = fscher_read_value(client, FSCHER_REG_FAN0_RIPPLE); + data->fan_ripple[1] = fscher_read_value(client, FSCHER_REG_FAN1_RIPPLE); + data->fan_ripple[2] = fscher_read_value(client, FSCHER_REG_FAN2_RIPPLE); + + data->watchdog[0] = fscher_read_value(client, FSCHER_REG_WDOG_PRESET); + data->watchdog[1] = fscher_read_value(client, FSCHER_REG_WDOG_STATE); + data->watchdog[2] = fscher_read_value(client, FSCHER_REG_WDOG_CONTROL); + + data->global_event = fscher_read_value(client, FSCHER_REG_EVENT_STATE); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + + + +#define FAN_INDEX_FROM_NUM(nr) ((nr) - 1) + +static ssize_t set_fan_status(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + /* bits 0..1, 3..7 reserved => mask with 0x04 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x04; + + down(&data->update_lock); + data->fan_status[FAN_INDEX_FROM_NUM(nr)] &= ~v; + fscher_write_value(client, reg, v); + up(&data->update_lock); + return count; +} + +static ssize_t show_fan_status(struct fscher_data *data, char *buf, int nr) +{ + /* bits 0..1, 3..7 reserved => mask with 0x04 */ + return sprintf(buf, "%u\n", data->fan_status[FAN_INDEX_FROM_NUM(nr)] & 0x04); +} + +static ssize_t set_pwm(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[FAN_INDEX_FROM_NUM(nr)] = v > 0xff ? 0xff : v; + fscher_write_value(client, reg, data->fan_min[FAN_INDEX_FROM_NUM(nr)]); + up(&data->update_lock); + return count; +} + +static ssize_t show_pwm(struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", data->fan_min[FAN_INDEX_FROM_NUM(nr)]); +} + +static ssize_t set_fan_div(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + /* supported values: 2, 4, 8 */ + unsigned long v = simple_strtoul(buf, NULL, 10); + + switch (v) { + case 2: v = 1; break; + case 4: v = 2; break; + case 8: v = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not " + "supported. Choose one of 2, 4 or 8!\n", v); + return -EINVAL; + } + + down(&data->update_lock); + + /* bits 2..7 reserved => mask with 0x03 */ + data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] &= ~0x03; + data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] |= v; + + fscher_write_value(client, reg, data->fan_ripple[FAN_INDEX_FROM_NUM(nr)]); + up(&data->update_lock); + return count; +} + +static ssize_t show_fan_div(struct fscher_data *data, char *buf, int nr) +{ + /* bits 2..7 reserved => mask with 0x03 */ + return sprintf(buf, "%u\n", 1 << (data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] & 0x03)); +} + +#define RPM_FROM_REG(val) (val*60) + +static ssize_t show_fan_input (struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[FAN_INDEX_FROM_NUM(nr)])); +} + + + +#define TEMP_INDEX_FROM_NUM(nr) ((nr) - 1) + +static ssize_t set_temp_status(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + /* bits 2..7 reserved, 0 read only => mask with 0x02 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; + + down(&data->update_lock); + data->temp_status[TEMP_INDEX_FROM_NUM(nr)] &= ~v; + fscher_write_value(client, reg, v); + up(&data->update_lock); + return count; +} + +static ssize_t show_temp_status(struct fscher_data *data, char *buf, int nr) +{ + /* bits 2..7 reserved => mask with 0x03 */ + return sprintf(buf, "%u\n", data->temp_status[TEMP_INDEX_FROM_NUM(nr)] & 0x03); +} + +#define TEMP_FROM_REG(val) (((val) - 128) * 1000) + +static ssize_t show_temp_input(struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[TEMP_INDEX_FROM_NUM(nr)])); +} + +/* + * The final conversion is specified in sensors.conf, as it depends on + * mainboard specific values. We export the registers contents as + * pseudo-hundredths-of-Volts (range 0V - 2.55V). Not that it makes much + * sense per se, but it minimizes the conversions count and keeps the + * values within a usual range. + */ +#define VOLT_FROM_REG(val) ((val) * 10) + +static ssize_t show_in_input(struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[nr])); +} + + + +static ssize_t show_revision(struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", data->revision); +} + + + +static ssize_t show_alarms(struct fscher_data *data, char *buf, int nr) +{ + /* bits 2, 5..6 reserved => mask with 0x9b */ + return sprintf(buf, "%u\n", data->global_event & 0x9b); +} + + + +static ssize_t set_control(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + /* bits 1..7 reserved => mask with 0x01 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x01; + + down(&data->update_lock); + data->global_control &= ~v; + fscher_write_value(client, reg, v); + up(&data->update_lock); + return count; +} + +static ssize_t show_control(struct fscher_data *data, char *buf, int nr) +{ + /* bits 1..7 reserved => mask with 0x01 */ + return sprintf(buf, "%u\n", data->global_control & 0x01); +} + + + +static ssize_t set_watchdog_control(struct i2c_client *client, struct + fscher_data *data, const char *buf, size_t count, + int nr, int reg) +{ + /* bits 0..3 reserved => mask with 0xf0 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0; + + down(&data->update_lock); + data->watchdog[2] &= ~0xf0; + data->watchdog[2] |= v; + fscher_write_value(client, reg, data->watchdog[2]); + up(&data->update_lock); + return count; +} + +static ssize_t show_watchdog_control(struct fscher_data *data, char *buf, int nr) +{ + /* bits 0..3 reserved, bit 5 write only => mask with 0xd0 */ + return sprintf(buf, "%u\n", data->watchdog[2] & 0xd0); +} + +static ssize_t set_watchdog_status(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + /* bits 0, 2..7 reserved => mask with 0x02 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; + + down(&data->update_lock); + data->watchdog[1] &= ~v; + fscher_write_value(client, reg, v); + up(&data->update_lock); + return count; +} + +static ssize_t show_watchdog_status(struct fscher_data *data, char *buf, int nr) +{ + /* bits 0, 2..7 reserved => mask with 0x02 */ + return sprintf(buf, "%u\n", data->watchdog[1] & 0x02); +} + +static ssize_t set_watchdog_preset(struct i2c_client *client, struct fscher_data *data, + const char *buf, size_t count, int nr, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff; + + down(&data->update_lock); + data->watchdog[0] = v; + fscher_write_value(client, reg, data->watchdog[0]); + up(&data->update_lock); + return count; +} + +static ssize_t show_watchdog_preset(struct fscher_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", data->watchdog[0]); +} + +static int __init sensors_fscher_init(void) +{ + return i2c_add_driver(&fscher_driver); +} + +static void __exit sensors_fscher_exit(void) +{ + i2c_del_driver(&fscher_driver); +} + +MODULE_AUTHOR("Reinhard Nissl "); +MODULE_DESCRIPTION("FSC Hermes driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_fscher_init); +module_exit(sensors_fscher_exit); diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c new file mode 100644 index 00000000000..3beaa6191ef --- /dev/null +++ b/drivers/hwmon/fscpos.c @@ -0,0 +1,641 @@ +/* + fscpos.c - Kernel module for hardware monitoring with FSC Poseidon chips + Copyright (C) 2004, 2005 Stefan Ott + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + fujitsu siemens poseidon chip, + module based on the old fscpos module by Hermann Jung and + the fscher module by Reinhard Nissl + + original module based on lm80.c + Copyright (C) 1998, 1999 Frodo Looijaard + and Philip Edelbrock + + Thanks to Jean Delvare for reviewing my code and suggesting a lot of + improvements. +*/ + +#include +#include +#include +#include +#include + +/* + * Addresses to scan + */ +static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ +SENSORS_INSMOD_1(fscpos); + +/* + * The FSCPOS registers + */ + +/* chip identification */ +#define FSCPOS_REG_IDENT_0 0x00 +#define FSCPOS_REG_IDENT_1 0x01 +#define FSCPOS_REG_IDENT_2 0x02 +#define FSCPOS_REG_REVISION 0x03 + +/* global control and status */ +#define FSCPOS_REG_EVENT_STATE 0x04 +#define FSCPOS_REG_CONTROL 0x05 + +/* watchdog */ +#define FSCPOS_REG_WDOG_PRESET 0x28 +#define FSCPOS_REG_WDOG_STATE 0x23 +#define FSCPOS_REG_WDOG_CONTROL 0x21 + +/* voltages */ +#define FSCPOS_REG_VOLT_12 0x45 +#define FSCPOS_REG_VOLT_5 0x42 +#define FSCPOS_REG_VOLT_BATT 0x48 + +/* fans - the chip does not support minimum speed for fan2 */ +static u8 FSCPOS_REG_PWM[] = { 0x55, 0x65 }; +static u8 FSCPOS_REG_FAN_ACT[] = { 0x0e, 0x6b, 0xab }; +static u8 FSCPOS_REG_FAN_STATE[] = { 0x0d, 0x62, 0xa2 }; +static u8 FSCPOS_REG_FAN_RIPPLE[] = { 0x0f, 0x6f, 0xaf }; + +/* temperatures */ +static u8 FSCPOS_REG_TEMP_ACT[] = { 0x64, 0x32, 0x35 }; +static u8 FSCPOS_REG_TEMP_STATE[] = { 0x71, 0x81, 0x91 }; + +/* + * Functions declaration + */ +static int fscpos_attach_adapter(struct i2c_adapter *adapter); +static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind); +static int fscpos_detach_client(struct i2c_client *client); + +static int fscpos_read_value(struct i2c_client *client, u8 register); +static int fscpos_write_value(struct i2c_client *client, u8 register, u8 value); +static struct fscpos_data *fscpos_update_device(struct device *dev); +static void fscpos_init_client(struct i2c_client *client); + +static void reset_fan_alarm(struct i2c_client *client, int nr); + +/* + * Driver data (common to all clients) + */ +static struct i2c_driver fscpos_driver = { + .owner = THIS_MODULE, + .name = "fscpos", + .id = I2C_DRIVERID_FSCPOS, + .flags = I2C_DF_NOTIFY, + .attach_adapter = fscpos_attach_adapter, + .detach_client = fscpos_detach_client, +}; + +/* + * Client data (each client gets its own) + */ +struct fscpos_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* 0 until following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + /* register values */ + u8 revision; /* revision of chip */ + u8 global_event; /* global event status */ + u8 global_control; /* global control register */ + u8 wdog_control; /* watchdog control */ + u8 wdog_state; /* watchdog status */ + u8 wdog_preset; /* watchdog preset */ + u8 volt[3]; /* 12, 5, battery current */ + u8 temp_act[3]; /* temperature */ + u8 temp_status[3]; /* status of sensor */ + u8 fan_act[3]; /* fans revolutions per second */ + u8 fan_status[3]; /* fan status */ + u8 pwm[2]; /* fan min value for rps */ + u8 fan_ripple[3]; /* divider for rps */ +}; + +/* Temperature */ +#define TEMP_FROM_REG(val) (((val) - 128) * 1000) + +static ssize_t show_temp_input(struct fscpos_data *data, char *buf, int nr) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[nr - 1])); +} + +static ssize_t show_temp_status(struct fscpos_data *data, char *buf, int nr) +{ + /* bits 2..7 reserved => mask with 0x03 */ + return sprintf(buf, "%u\n", data->temp_status[nr - 1] & 0x03); +} + +static ssize_t show_temp_reset(struct fscpos_data *data, char *buf, int nr) +{ + return sprintf(buf, "1\n"); +} + +static ssize_t set_temp_reset(struct i2c_client *client, struct fscpos_data + *data, const char *buf, size_t count, int nr, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + if (v != 1) { + dev_err(&client->dev, "temp_reset value %ld not supported. " + "Use 1 to reset the alarm!\n", v); + return -EINVAL; + } + + dev_info(&client->dev, "You used the temp_reset feature which has not " + "been proplerly tested. Please report your " + "experience to the module author.\n"); + + /* Supported value: 2 (clears the status) */ + fscpos_write_value(client, FSCPOS_REG_TEMP_STATE[nr], 2); + return count; +} + +/* Fans */ +#define RPM_FROM_REG(val) ((val) * 60) + +static ssize_t show_fan_status(struct fscpos_data *data, char *buf, int nr) +{ + /* bits 0..1, 3..7 reserved => mask with 0x04 */ + return sprintf(buf, "%u\n", data->fan_status[nr - 1] & 0x04); +} + +static ssize_t show_fan_input(struct fscpos_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[nr - 1])); +} + +static ssize_t show_fan_ripple(struct fscpos_data *data, char *buf, int nr) +{ + /* bits 2..7 reserved => mask with 0x03 */ + return sprintf(buf, "%u\n", data->fan_ripple[nr - 1] & 0x03); +} + +static ssize_t set_fan_ripple(struct i2c_client *client, struct fscpos_data + *data, const char *buf, size_t count, int nr, int reg) +{ + /* supported values: 2, 4, 8 */ + unsigned long v = simple_strtoul(buf, NULL, 10); + + switch (v) { + case 2: v = 1; break; + case 4: v = 2; break; + case 8: v = 3; break; + default: + dev_err(&client->dev, "fan_ripple value %ld not supported. " + "Must be one of 2, 4 or 8!\n", v); + return -EINVAL; + } + + down(&data->update_lock); + /* bits 2..7 reserved => mask with 0x03 */ + data->fan_ripple[nr - 1] &= ~0x03; + data->fan_ripple[nr - 1] |= v; + + fscpos_write_value(client, reg, data->fan_ripple[nr - 1]); + up(&data->update_lock); + return count; +} + +static ssize_t show_pwm(struct fscpos_data *data, char *buf, int nr) +{ + return sprintf(buf, "%u\n", data->pwm[nr - 1]); +} + +static ssize_t set_pwm(struct i2c_client *client, struct fscpos_data *data, + const char *buf, size_t count, int nr, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + + /* Range: 0..255 */ + if (v < 0) v = 0; + if (v > 255) v = 255; + + down(&data->update_lock); + data->pwm[nr - 1] = v; + fscpos_write_value(client, reg, data->pwm[nr - 1]); + up(&data->update_lock); + return count; +} + +static void reset_fan_alarm(struct i2c_client *client, int nr) +{ + fscpos_write_value(client, FSCPOS_REG_FAN_STATE[nr], 4); +} + +/* Volts */ +#define VOLT_FROM_REG(val, mult) ((val) * (mult) / 255) + +static ssize_t show_volt_12(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fscpos_data *data = fscpos_update_device(dev); + return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[0], 14200)); +} + +static ssize_t show_volt_5(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fscpos_data *data = fscpos_update_device(dev); + return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[1], 6600)); +} + +static ssize_t show_volt_batt(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fscpos_data *data = fscpos_update_device(dev); + return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[2], 3300)); +} + +/* Watchdog */ +static ssize_t show_wdog_control(struct fscpos_data *data, char *buf) +{ + /* bits 0..3 reserved, bit 6 write only => mask with 0xb0 */ + return sprintf(buf, "%u\n", data->wdog_control & 0xb0); +} + +static ssize_t set_wdog_control(struct i2c_client *client, struct fscpos_data + *data, const char *buf, size_t count, int reg) +{ + /* bits 0..3 reserved => mask with 0xf0 */ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0; + + down(&data->update_lock); + data->wdog_control &= ~0xf0; + data->wdog_control |= v; + fscpos_write_value(client, reg, data->wdog_control); + up(&data->update_lock); + return count; +} + +static ssize_t show_wdog_state(struct fscpos_data *data, char *buf) +{ + /* bits 0, 2..7 reserved => mask with 0x02 */ + return sprintf(buf, "%u\n", data->wdog_state & 0x02); +} + +static ssize_t set_wdog_state(struct i2c_client *client, struct fscpos_data + *data, const char *buf, size_t count, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; + + /* Valid values: 2 (clear) */ + if (v != 2) { + dev_err(&client->dev, "wdog_state value %ld not supported. " + "Must be 2 to clear the state!\n", v); + return -EINVAL; + } + + down(&data->update_lock); + data->wdog_state &= ~v; + fscpos_write_value(client, reg, v); + up(&data->update_lock); + return count; +} + +static ssize_t show_wdog_preset(struct fscpos_data *data, char *buf) +{ + return sprintf(buf, "%u\n", data->wdog_preset); +} + +static ssize_t set_wdog_preset(struct i2c_client *client, struct fscpos_data + *data, const char *buf, size_t count, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff; + + down(&data->update_lock); + data->wdog_preset = v; + fscpos_write_value(client, reg, data->wdog_preset); + up(&data->update_lock); + return count; +} + +/* Event */ +static ssize_t show_event(struct device *dev, struct device_attribute *attr, char *buf) +{ + /* bits 5..7 reserved => mask with 0x1f */ + struct fscpos_data *data = fscpos_update_device(dev); + return sprintf(buf, "%u\n", data->global_event & 0x9b); +} + +/* + * Sysfs stuff + */ +#define create_getter(kind, sub) \ + static ssize_t sysfs_show_##kind##sub(struct device *dev, struct device_attribute *attr, char *buf) \ + { \ + struct fscpos_data *data = fscpos_update_device(dev); \ + return show_##kind##sub(data, buf); \ + } + +#define create_getter_n(kind, offset, sub) \ + static ssize_t sysfs_show_##kind##offset##sub(struct device *dev, struct device_attribute *attr, char\ + *buf) \ + { \ + struct fscpos_data *data = fscpos_update_device(dev); \ + return show_##kind##sub(data, buf, offset); \ + } + +#define create_setter(kind, sub, reg) \ + static ssize_t sysfs_set_##kind##sub (struct device *dev, struct device_attribute *attr, const char \ + *buf, size_t count) \ + { \ + struct i2c_client *client = to_i2c_client(dev); \ + struct fscpos_data *data = i2c_get_clientdata(client); \ + return set_##kind##sub(client, data, buf, count, reg); \ + } + +#define create_setter_n(kind, offset, sub, reg) \ + static ssize_t sysfs_set_##kind##offset##sub (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ + { \ + struct i2c_client *client = to_i2c_client(dev); \ + struct fscpos_data *data = i2c_get_clientdata(client); \ + return set_##kind##sub(client, data, buf, count, offset, reg);\ + } + +#define create_sysfs_device_ro(kind, sub, offset) \ + static DEVICE_ATTR(kind##offset##sub, S_IRUGO, \ + sysfs_show_##kind##offset##sub, NULL); + +#define create_sysfs_device_rw(kind, sub, offset) \ + static DEVICE_ATTR(kind##offset##sub, S_IRUGO | S_IWUSR, \ + sysfs_show_##kind##offset##sub, sysfs_set_##kind##offset##sub); + +#define sysfs_ro_n(kind, sub, offset) \ + create_getter_n(kind, offset, sub); \ + create_sysfs_device_ro(kind, sub, offset); + +#define sysfs_rw_n(kind, sub, offset, reg) \ + create_getter_n(kind, offset, sub); \ + create_setter_n(kind, offset, sub, reg); \ + create_sysfs_device_rw(kind, sub, offset); + +#define sysfs_rw(kind, sub, reg) \ + create_getter(kind, sub); \ + create_setter(kind, sub, reg); \ + create_sysfs_device_rw(kind, sub,); + +#define sysfs_fan_with_min(offset, reg_status, reg_ripple, reg_min) \ + sysfs_fan(offset, reg_status, reg_ripple); \ + sysfs_rw_n(pwm,, offset, reg_min); + +#define sysfs_fan(offset, reg_status, reg_ripple) \ + sysfs_ro_n(fan, _input, offset); \ + sysfs_ro_n(fan, _status, offset); \ + sysfs_rw_n(fan, _ripple, offset, reg_ripple); + +#define sysfs_temp(offset, reg_status) \ + sysfs_ro_n(temp, _input, offset); \ + sysfs_ro_n(temp, _status, offset); \ + sysfs_rw_n(temp, _reset, offset, reg_status); + +#define sysfs_watchdog(reg_wdog_preset, reg_wdog_state, reg_wdog_control) \ + sysfs_rw(wdog, _control, reg_wdog_control); \ + sysfs_rw(wdog, _preset, reg_wdog_preset); \ + sysfs_rw(wdog, _state, reg_wdog_state); + +sysfs_fan_with_min(1, FSCPOS_REG_FAN_STATE[0], FSCPOS_REG_FAN_RIPPLE[0], + FSCPOS_REG_PWM[0]); +sysfs_fan_with_min(2, FSCPOS_REG_FAN_STATE[1], FSCPOS_REG_FAN_RIPPLE[1], + FSCPOS_REG_PWM[1]); +sysfs_fan(3, FSCPOS_REG_FAN_STATE[2], FSCPOS_REG_FAN_RIPPLE[2]); + +sysfs_temp(1, FSCPOS_REG_TEMP_STATE[0]); +sysfs_temp(2, FSCPOS_REG_TEMP_STATE[1]); +sysfs_temp(3, FSCPOS_REG_TEMP_STATE[2]); + +sysfs_watchdog(FSCPOS_REG_WDOG_PRESET, FSCPOS_REG_WDOG_STATE, + FSCPOS_REG_WDOG_CONTROL); + +static DEVICE_ATTR(event, S_IRUGO, show_event, NULL); +static DEVICE_ATTR(in0_input, S_IRUGO, show_volt_12, NULL); +static DEVICE_ATTR(in1_input, S_IRUGO, show_volt_5, NULL); +static DEVICE_ATTR(in2_input, S_IRUGO, show_volt_batt, NULL); + +static int fscpos_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, fscpos_detect); +} + +int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct fscpos_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + /* + * OK. For now, we presume we have a valid client. We now create the + * client structure, even though we cannot fill it completely yet. + * But it allows us to access fscpos_{read,write}_value. + */ + + if (!(data = kmalloc(sizeof(struct fscpos_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct fscpos_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &fscpos_driver; + new_client->flags = 0; + + /* Do the remaining detection unless force or force_fscpos parameter */ + if (kind < 0) { + if ((fscpos_read_value(new_client, FSCPOS_REG_IDENT_0) + != 0x50) /* 'P' */ + || (fscpos_read_value(new_client, FSCPOS_REG_IDENT_1) + != 0x45) /* 'E' */ + || (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2) + != 0x47))/* 'G' */ + { + dev_dbg(&new_client->dev, "fscpos detection failed\n"); + goto exit_free; + } + } + + /* Fill in the remaining client fields and put it in the global list */ + strlcpy(new_client->name, "fscpos", I2C_NAME_SIZE); + + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Inizialize the fscpos chip */ + fscpos_init_client(new_client); + + /* Announce that the chip was found */ + dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_event); + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_wdog_control); + device_create_file(&new_client->dev, &dev_attr_wdog_preset); + device_create_file(&new_client->dev, &dev_attr_wdog_state); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_status); + device_create_file(&new_client->dev, &dev_attr_temp1_reset); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp2_status); + device_create_file(&new_client->dev, &dev_attr_temp2_reset); + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp3_status); + device_create_file(&new_client->dev, &dev_attr_temp3_reset); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_status); + device_create_file(&new_client->dev, &dev_attr_fan1_ripple); + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_status); + device_create_file(&new_client->dev, &dev_attr_fan2_ripple); + device_create_file(&new_client->dev, &dev_attr_pwm2); + device_create_file(&new_client->dev, &dev_attr_fan3_input); + device_create_file(&new_client->dev, &dev_attr_fan3_status); + device_create_file(&new_client->dev, &dev_attr_fan3_ripple); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int fscpos_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, client" + " not detached.\n"); + return err; + } + kfree(i2c_get_clientdata(client)); + return 0; +} + +static int fscpos_read_value(struct i2c_client *client, u8 reg) +{ + dev_dbg(&client->dev, "Read reg 0x%02x\n", reg); + return i2c_smbus_read_byte_data(client, reg); +} + +static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + dev_dbg(&client->dev, "Write reg 0x%02x, val 0x%02x\n", reg, value); + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* Called when we have found a new FSCPOS chip */ +static void fscpos_init_client(struct i2c_client *client) +{ + struct fscpos_data *data = i2c_get_clientdata(client); + + /* read revision from chip */ + data->revision = fscpos_read_value(client, FSCPOS_REG_REVISION); +} + +static struct fscpos_data *fscpos_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fscpos_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if ((jiffies - data->last_updated > 2 * HZ) || + (jiffies < data->last_updated) || !data->valid) { + int i; + + dev_dbg(&client->dev, "Starting fscpos update\n"); + + for (i = 0; i < 3; i++) { + data->temp_act[i] = fscpos_read_value(client, + FSCPOS_REG_TEMP_ACT[i]); + data->temp_status[i] = fscpos_read_value(client, + FSCPOS_REG_TEMP_STATE[i]); + data->fan_act[i] = fscpos_read_value(client, + FSCPOS_REG_FAN_ACT[i]); + data->fan_status[i] = fscpos_read_value(client, + FSCPOS_REG_FAN_STATE[i]); + data->fan_ripple[i] = fscpos_read_value(client, + FSCPOS_REG_FAN_RIPPLE[i]); + if (i < 2) { + /* fan2_min is not supported by the chip */ + data->pwm[i] = fscpos_read_value(client, + FSCPOS_REG_PWM[i]); + } + /* reset fan status if speed is back to > 0 */ + if (data->fan_status[i] != 0 && data->fan_act[i] > 0) { + reset_fan_alarm(client, i); + } + } + + data->volt[0] = fscpos_read_value(client, FSCPOS_REG_VOLT_12); + data->volt[1] = fscpos_read_value(client, FSCPOS_REG_VOLT_5); + data->volt[2] = fscpos_read_value(client, FSCPOS_REG_VOLT_BATT); + + data->wdog_preset = fscpos_read_value(client, + FSCPOS_REG_WDOG_PRESET); + data->wdog_state = fscpos_read_value(client, + FSCPOS_REG_WDOG_STATE); + data->wdog_control = fscpos_read_value(client, + FSCPOS_REG_WDOG_CONTROL); + + data->global_event = fscpos_read_value(client, + FSCPOS_REG_EVENT_STATE); + + data->last_updated = jiffies; + data->valid = 1; + } + up(&data->update_lock); + return data; +} + +static int __init sm_fscpos_init(void) +{ + return i2c_add_driver(&fscpos_driver); +} + +static void __exit sm_fscpos_exit(void) +{ + i2c_del_driver(&fscpos_driver); +} + +MODULE_AUTHOR("Stefan Ott based on work from Hermann Jung " + ", Frodo Looijaard " + " and Philip Edelbrock "); +MODULE_DESCRIPTION("fujitsu siemens poseidon chip driver"); +MODULE_LICENSE("GPL"); + +module_init(sm_fscpos_init); +module_exit(sm_fscpos_exit); diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c new file mode 100644 index 00000000000..6bedf729dcf --- /dev/null +++ b/drivers/hwmon/gl518sm.c @@ -0,0 +1,604 @@ +/* + * gl518sm.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 1998, 1999 Frodo Looijaard and + * Kyosti Malkki + * Copyright (C) 2004 Hong-Gunn Chew and + * Jean Delvare + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Ported to Linux 2.6 by Hong-Gunn Chew with the help of Jean Delvare + * and advice of Greg Kroah-Hartman. + * + * Notes about the port: + * Release 0x00 of the GL518SM chipset doesn't support reading of in0, + * in1 nor in2. The original driver had an ugly workaround to get them + * anyway (changing limits and watching alarms trigger and wear off). + * We did not keep that part of the original driver in the Linux 2.6 + * version, since it was making the driver significantly more complex + * with no real benefit. + * + * History: + * 2004-01-28 Original port. (Hong-Gunn Chew) + * 2004-01-31 Code review and approval. (Jean Delvare) + */ + +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r80); + +/* Many GL518 constants specified below */ + +/* The GL518 registers */ +#define GL518_REG_CHIP_ID 0x00 +#define GL518_REG_REVISION 0x01 +#define GL518_REG_VENDOR_ID 0x02 +#define GL518_REG_CONF 0x03 +#define GL518_REG_TEMP_IN 0x04 +#define GL518_REG_TEMP_MAX 0x05 +#define GL518_REG_TEMP_HYST 0x06 +#define GL518_REG_FAN_COUNT 0x07 +#define GL518_REG_FAN_LIMIT 0x08 +#define GL518_REG_VIN1_LIMIT 0x09 +#define GL518_REG_VIN2_LIMIT 0x0a +#define GL518_REG_VIN3_LIMIT 0x0b +#define GL518_REG_VDD_LIMIT 0x0c +#define GL518_REG_VIN3 0x0d +#define GL518_REG_MISC 0x0f +#define GL518_REG_ALARM 0x10 +#define GL518_REG_MASK 0x11 +#define GL518_REG_INT 0x12 +#define GL518_REG_VIN2 0x13 +#define GL518_REG_VIN1 0x14 +#define GL518_REG_VDD 0x15 + + +/* + * Conversions. Rounding and limit checking is only done on the TO_REG + * variants. Note that you should be a bit careful with which arguments + * these macros are called: arguments may be evaluated more than once. + * Fixing this is just not worth it. + */ + +#define RAW_FROM_REG(val) val + +#define BOOL_FROM_REG(val) ((val)?0:1) +#define BOOL_TO_REG(val) ((val)?0:1) + +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0? \ + (val)-500:(val)+500)/1000)+119),0,255)) +#define TEMP_FROM_REG(val) (((val) - 119) * 1000) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + long rpmdiv; + if (rpm == 0) + return 0; + rpmdiv = SENSORS_LIMIT(rpm, 1, 1920000) * div; + return SENSORS_LIMIT((960000 + rpmdiv / 2) / rpmdiv, 1, 255); +} +#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (960000/((val)*(div)))) + +#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) +#define IN_FROM_REG(val) ((val)*19) + +#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) +#define VDD_FROM_REG(val) (((val)*95+2)/4) + +#define DIV_TO_REG(val) ((val)==4?2:(val)==2?1:(val)==1?0:3) +#define DIV_FROM_REG(val) (1 << (val)) + +#define BEEP_MASK_TO_REG(val) ((val) & 0x7f & data->alarm_mask) +#define BEEP_MASK_FROM_REG(val) ((val) & 0x7f) + +/* Each client has this additional data */ +struct gl518_data { + struct i2c_client client; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 voltage_in[4]; /* Register values; [0] = VDD */ + u8 voltage_min[4]; /* Register values; [0] = VDD */ + u8 voltage_max[4]; /* Register values; [0] = VDD */ + u8 iter_voltage_in[4]; /* Register values; [0] = VDD */ + u8 fan_in[2]; + u8 fan_min[2]; + u8 fan_div[2]; /* Register encoding, shifted right */ + u8 fan_auto1; /* Boolean */ + u8 temp_in; /* Register values */ + u8 temp_max; /* Register values */ + u8 temp_hyst; /* Register values */ + u8 alarms; /* Register value */ + u8 alarm_mask; /* Register value */ + u8 beep_mask; /* Register value */ + u8 beep_enable; /* Boolean */ +}; + +static int gl518_attach_adapter(struct i2c_adapter *adapter); +static int gl518_detect(struct i2c_adapter *adapter, int address, int kind); +static void gl518_init_client(struct i2c_client *client); +static int gl518_detach_client(struct i2c_client *client); +static int gl518_read_value(struct i2c_client *client, u8 reg); +static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); +static struct gl518_data *gl518_update_device(struct device *dev); + +/* This is the driver that will be inserted */ +static struct i2c_driver gl518_driver = { + .owner = THIS_MODULE, + .name = "gl518sm", + .id = I2C_DRIVERID_GL518, + .flags = I2C_DF_NOTIFY, + .attach_adapter = gl518_attach_adapter, + .detach_client = gl518_detach_client, +}; + +/* + * Sysfs stuff + */ + +#define show(type, suffix, value) \ +static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct gl518_data *data = gl518_update_device(dev); \ + return sprintf(buf, "%d\n", type##_FROM_REG(data->value)); \ +} + +#define show_fan(suffix, value, index) \ +static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct gl518_data *data = gl518_update_device(dev); \ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[index], \ + DIV_FROM_REG(data->fan_div[index]))); \ +} + +show(TEMP, temp_input1, temp_in); +show(TEMP, temp_max1, temp_max); +show(TEMP, temp_hyst1, temp_hyst); +show(BOOL, fan_auto1, fan_auto1); +show_fan(fan_input1, fan_in, 0); +show_fan(fan_input2, fan_in, 1); +show_fan(fan_min1, fan_min, 0); +show_fan(fan_min2, fan_min, 1); +show(DIV, fan_div1, fan_div[0]); +show(DIV, fan_div2, fan_div[1]); +show(VDD, in_input0, voltage_in[0]); +show(IN, in_input1, voltage_in[1]); +show(IN, in_input2, voltage_in[2]); +show(IN, in_input3, voltage_in[3]); +show(VDD, in_min0, voltage_min[0]); +show(IN, in_min1, voltage_min[1]); +show(IN, in_min2, voltage_min[2]); +show(IN, in_min3, voltage_min[3]); +show(VDD, in_max0, voltage_max[0]); +show(IN, in_max1, voltage_max[1]); +show(IN, in_max2, voltage_max[2]); +show(IN, in_max3, voltage_max[3]); +show(RAW, alarms, alarms); +show(BOOL, beep_enable, beep_enable); +show(BEEP_MASK, beep_mask, beep_mask); + +#define set(type, suffix, value, reg) \ +static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct gl518_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = type##_TO_REG(val); \ + gl518_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} + +#define set_bits(type, suffix, value, reg, mask, shift) \ +static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct gl518_data *data = i2c_get_clientdata(client); \ + int regvalue; \ + unsigned long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + regvalue = gl518_read_value(client, reg); \ + data->value = type##_TO_REG(val); \ + regvalue = (regvalue & ~mask) | (data->value << shift); \ + gl518_write_value(client, reg, regvalue); \ + up(&data->update_lock); \ + return count; \ +} + +#define set_low(type, suffix, value, reg) \ + set_bits(type, suffix, value, reg, 0x00ff, 0) +#define set_high(type, suffix, value, reg) \ + set_bits(type, suffix, value, reg, 0xff00, 8) + +set(TEMP, temp_max1, temp_max, GL518_REG_TEMP_MAX); +set(TEMP, temp_hyst1, temp_hyst, GL518_REG_TEMP_HYST); +set_bits(BOOL, fan_auto1, fan_auto1, GL518_REG_MISC, 0x08, 3); +set_bits(DIV, fan_div1, fan_div[0], GL518_REG_MISC, 0xc0, 6); +set_bits(DIV, fan_div2, fan_div[1], GL518_REG_MISC, 0x30, 4); +set_low(VDD, in_min0, voltage_min[0], GL518_REG_VDD_LIMIT); +set_low(IN, in_min1, voltage_min[1], GL518_REG_VIN1_LIMIT); +set_low(IN, in_min2, voltage_min[2], GL518_REG_VIN2_LIMIT); +set_low(IN, in_min3, voltage_min[3], GL518_REG_VIN3_LIMIT); +set_high(VDD, in_max0, voltage_max[0], GL518_REG_VDD_LIMIT); +set_high(IN, in_max1, voltage_max[1], GL518_REG_VIN1_LIMIT); +set_high(IN, in_max2, voltage_max[2], GL518_REG_VIN2_LIMIT); +set_high(IN, in_max3, voltage_max[3], GL518_REG_VIN3_LIMIT); +set_bits(BOOL, beep_enable, beep_enable, GL518_REG_CONF, 0x04, 2); +set(BEEP_MASK, beep_mask, beep_mask, GL518_REG_ALARM); + +static ssize_t set_fan_min1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl518_data *data = i2c_get_clientdata(client); + int regvalue; + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); + data->fan_min[0] = FAN_TO_REG(val, + DIV_FROM_REG(data->fan_div[0])); + regvalue = (regvalue & 0x00ff) | (data->fan_min[0] << 8); + gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); + + data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); + if (data->fan_min[0] == 0) + data->alarm_mask &= ~0x20; + else + data->alarm_mask |= 0x20; + data->beep_mask &= data->alarm_mask; + gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); + + up(&data->update_lock); + return count; +} + +static ssize_t set_fan_min2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl518_data *data = i2c_get_clientdata(client); + int regvalue; + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); + data->fan_min[1] = FAN_TO_REG(val, + DIV_FROM_REG(data->fan_div[1])); + regvalue = (regvalue & 0xff00) | data->fan_min[1]; + gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); + + data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); + if (data->fan_min[1] == 0) + data->alarm_mask &= ~0x40; + else + data->alarm_mask |= 0x40; + data->beep_mask &= data->alarm_mask; + gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); + + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); +static DEVICE_ATTR(temp1_max, S_IWUSR|S_IRUGO, show_temp_max1, set_temp_max1); +static DEVICE_ATTR(temp1_max_hyst, S_IWUSR|S_IRUGO, + show_temp_hyst1, set_temp_hyst1); +static DEVICE_ATTR(fan1_auto, S_IWUSR|S_IRUGO, show_fan_auto1, set_fan_auto1); +static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); +static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); +static DEVICE_ATTR(fan1_min, S_IWUSR|S_IRUGO, show_fan_min1, set_fan_min1); +static DEVICE_ATTR(fan2_min, S_IWUSR|S_IRUGO, show_fan_min2, set_fan_min2); +static DEVICE_ATTR(fan1_div, S_IWUSR|S_IRUGO, show_fan_div1, set_fan_div1); +static DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO, show_fan_div2, set_fan_div2); +static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL); +static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL); +static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL); +static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL); +static DEVICE_ATTR(in0_min, S_IWUSR|S_IRUGO, show_in_min0, set_in_min0); +static DEVICE_ATTR(in1_min, S_IWUSR|S_IRUGO, show_in_min1, set_in_min1); +static DEVICE_ATTR(in2_min, S_IWUSR|S_IRUGO, show_in_min2, set_in_min2); +static DEVICE_ATTR(in3_min, S_IWUSR|S_IRUGO, show_in_min3, set_in_min3); +static DEVICE_ATTR(in0_max, S_IWUSR|S_IRUGO, show_in_max0, set_in_max0); +static DEVICE_ATTR(in1_max, S_IWUSR|S_IRUGO, show_in_max1, set_in_max1); +static DEVICE_ATTR(in2_max, S_IWUSR|S_IRUGO, show_in_max2, set_in_max2); +static DEVICE_ATTR(in3_max, S_IWUSR|S_IRUGO, show_in_max3, set_in_max3); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO, + show_beep_enable, set_beep_enable); +static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO, + show_beep_mask, set_beep_mask); + +/* + * Real code + */ + +static int gl518_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, gl518_detect); +} + +static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i; + struct i2c_client *new_client; + struct gl518_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access gl518_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct gl518_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct gl518_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &gl518_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + if (kind < 0) { + if ((gl518_read_value(new_client, GL518_REG_CHIP_ID) != 0x80) + || (gl518_read_value(new_client, GL518_REG_CONF) & 0x80)) + goto exit_free; + } + + /* Determine the chip type. */ + if (kind <= 0) { + i = gl518_read_value(new_client, GL518_REG_REVISION); + if (i == 0x00) { + kind = gl518sm_r00; + } else if (i == 0x80) { + kind = gl518sm_r80; + } else { + if (kind <= 0) + dev_info(&adapter->dev, + "Ignoring 'force' parameter for unknown " + "chip at adapter %d, address 0x%02x\n", + i2c_adapter_id(adapter), address); + goto exit_free; + } + } + + /* Fill in the remaining client fields */ + strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE); + data->type = kind; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the GL518SM chip */ + data->alarm_mask = 0xff; + data->voltage_in[0]=data->voltage_in[1]=data->voltage_in[2]=0; + gl518_init_client((struct i2c_client *) new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_fan1_auto); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_beep_enable); + device_create_file(&new_client->dev, &dev_attr_beep_mask); + + return 0; + +/* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + +exit_free: + kfree(data); +exit: + return err; +} + + +/* Called when we have found a new GL518SM. + Note that we preserve D4:NoFan2 and D2:beep_enable. */ +static void gl518_init_client(struct i2c_client *client) +{ + /* Make sure we leave D7:Reset untouched */ + u8 regvalue = gl518_read_value(client, GL518_REG_CONF) & 0x7f; + + /* Comparator mode (D3=0), standby mode (D6=0) */ + gl518_write_value(client, GL518_REG_CONF, (regvalue &= 0x37)); + + /* Never interrupts */ + gl518_write_value(client, GL518_REG_MASK, 0x00); + + /* Clear status register (D5=1), start (D6=1) */ + gl518_write_value(client, GL518_REG_CONF, 0x20 | regvalue); + gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue); +} + +static int gl518_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + + return 0; +} + +/* Registers 0x07 to 0x0c are word-sized, others are byte-sized + GL518 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +static int gl518_read_value(struct i2c_client *client, u8 reg) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return swab16(i2c_smbus_read_word_data(client, reg)); + else + return i2c_smbus_read_byte_data(client, reg); +} + +/* Registers 0x07 to 0x0c are word-sized, others are byte-sized + GL518 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return i2c_smbus_write_word_data(client, reg, swab16(value)); + else + return i2c_smbus_write_byte_data(client, reg, value); +} + +static struct gl518_data *gl518_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl518_data *data = i2c_get_clientdata(client); + int val; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting gl518 update\n"); + + data->alarms = gl518_read_value(client, GL518_REG_INT); + data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); + + val = gl518_read_value(client, GL518_REG_VDD_LIMIT); + data->voltage_min[0] = val & 0xff; + data->voltage_max[0] = (val >> 8) & 0xff; + val = gl518_read_value(client, GL518_REG_VIN1_LIMIT); + data->voltage_min[1] = val & 0xff; + data->voltage_max[1] = (val >> 8) & 0xff; + val = gl518_read_value(client, GL518_REG_VIN2_LIMIT); + data->voltage_min[2] = val & 0xff; + data->voltage_max[2] = (val >> 8) & 0xff; + val = gl518_read_value(client, GL518_REG_VIN3_LIMIT); + data->voltage_min[3] = val & 0xff; + data->voltage_max[3] = (val >> 8) & 0xff; + + val = gl518_read_value(client, GL518_REG_FAN_COUNT); + data->fan_in[0] = (val >> 8) & 0xff; + data->fan_in[1] = val & 0xff; + + val = gl518_read_value(client, GL518_REG_FAN_LIMIT); + data->fan_min[0] = (val >> 8) & 0xff; + data->fan_min[1] = val & 0xff; + + data->temp_in = gl518_read_value(client, GL518_REG_TEMP_IN); + data->temp_max = + gl518_read_value(client, GL518_REG_TEMP_MAX); + data->temp_hyst = + gl518_read_value(client, GL518_REG_TEMP_HYST); + + val = gl518_read_value(client, GL518_REG_MISC); + data->fan_div[0] = (val >> 6) & 0x03; + data->fan_div[1] = (val >> 4) & 0x03; + data->fan_auto1 = (val >> 3) & 0x01; + + data->alarms &= data->alarm_mask; + + val = gl518_read_value(client, GL518_REG_CONF); + data->beep_enable = (val >> 2) & 1; + + if (data->type != gl518sm_r00) { + data->voltage_in[0] = + gl518_read_value(client, GL518_REG_VDD); + data->voltage_in[1] = + gl518_read_value(client, GL518_REG_VIN1); + data->voltage_in[2] = + gl518_read_value(client, GL518_REG_VIN2); + } + data->voltage_in[3] = + gl518_read_value(client, GL518_REG_VIN3); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_gl518sm_init(void) +{ + return i2c_add_driver(&gl518_driver); +} + +static void __exit sensors_gl518sm_exit(void) +{ + i2c_del_driver(&gl518_driver); +} + +MODULE_AUTHOR("Frodo Looijaard , " + "Kyosti Malkki and " + "Hong-Gunn Chew "); +MODULE_DESCRIPTION("GL518SM driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_gl518sm_init); +module_exit(sensors_gl518sm_exit); diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c new file mode 100644 index 00000000000..a13a504f5bf --- /dev/null +++ b/drivers/hwmon/gl520sm.c @@ -0,0 +1,769 @@ +/* + gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard , + Kyösti Mälkki + Copyright (c) 2005 Maarten Deprez + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +/* Type of the extra sensor */ +static unsigned short extra_sensor_type; +module_param(extra_sensor_type, ushort, 0); +MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=temperature, 2=voltage)"); + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(gl520sm); + +/* Many GL520 constants specified below +One of the inputs can be configured as either temp or voltage. +That's why _TEMP2 and _IN4 access the same register +*/ + +/* The GL520 registers */ +#define GL520_REG_CHIP_ID 0x00 +#define GL520_REG_REVISION 0x01 +#define GL520_REG_CONF 0x03 +#define GL520_REG_MASK 0x11 + +#define GL520_REG_VID_INPUT 0x02 + +#define GL520_REG_IN0_INPUT 0x15 +#define GL520_REG_IN0_LIMIT 0x0c +#define GL520_REG_IN0_MIN GL520_REG_IN0_LIMIT +#define GL520_REG_IN0_MAX GL520_REG_IN0_LIMIT + +#define GL520_REG_IN1_INPUT 0x14 +#define GL520_REG_IN1_LIMIT 0x09 +#define GL520_REG_IN1_MIN GL520_REG_IN1_LIMIT +#define GL520_REG_IN1_MAX GL520_REG_IN1_LIMIT + +#define GL520_REG_IN2_INPUT 0x13 +#define GL520_REG_IN2_LIMIT 0x0a +#define GL520_REG_IN2_MIN GL520_REG_IN2_LIMIT +#define GL520_REG_IN2_MAX GL520_REG_IN2_LIMIT + +#define GL520_REG_IN3_INPUT 0x0d +#define GL520_REG_IN3_LIMIT 0x0b +#define GL520_REG_IN3_MIN GL520_REG_IN3_LIMIT +#define GL520_REG_IN3_MAX GL520_REG_IN3_LIMIT + +#define GL520_REG_IN4_INPUT 0x0e +#define GL520_REG_IN4_MAX 0x17 +#define GL520_REG_IN4_MIN 0x18 + +#define GL520_REG_TEMP1_INPUT 0x04 +#define GL520_REG_TEMP1_MAX 0x05 +#define GL520_REG_TEMP1_MAX_HYST 0x06 + +#define GL520_REG_TEMP2_INPUT 0x0e +#define GL520_REG_TEMP2_MAX 0x17 +#define GL520_REG_TEMP2_MAX_HYST 0x18 + +#define GL520_REG_FAN_INPUT 0x07 +#define GL520_REG_FAN_MIN 0x08 +#define GL520_REG_FAN_DIV 0x0f +#define GL520_REG_FAN_OFF GL520_REG_FAN_DIV + +#define GL520_REG_ALARMS 0x12 +#define GL520_REG_BEEP_MASK 0x10 +#define GL520_REG_BEEP_ENABLE GL520_REG_CONF + +/* + * Function declarations + */ + +static int gl520_attach_adapter(struct i2c_adapter *adapter); +static int gl520_detect(struct i2c_adapter *adapter, int address, int kind); +static void gl520_init_client(struct i2c_client *client); +static int gl520_detach_client(struct i2c_client *client); +static int gl520_read_value(struct i2c_client *client, u8 reg); +static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value); +static struct gl520_data *gl520_update_device(struct device *dev); + +/* Driver data */ +static struct i2c_driver gl520_driver = { + .owner = THIS_MODULE, + .name = "gl520sm", + .id = I2C_DRIVERID_GL520, + .flags = I2C_DF_NOTIFY, + .attach_adapter = gl520_attach_adapter, + .detach_client = gl520_detach_client, +}; + +/* Client data */ +struct gl520_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until the following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + u8 vid; + u8 vrm; + u8 in_input[5]; /* [0] = VVD */ + u8 in_min[5]; /* [0] = VDD */ + u8 in_max[5]; /* [0] = VDD */ + u8 fan_input[2]; + u8 fan_min[2]; + u8 fan_div[2]; + u8 fan_off; + u8 temp_input[2]; + u8 temp_max[2]; + u8 temp_max_hyst[2]; + u8 alarms; + u8 beep_enable; + u8 beep_mask; + u8 alarm_mask; + u8 two_temps; +}; + +/* + * Sysfs stuff + */ + +#define sysfs_r(type, n, item, reg) \ +static ssize_t get_##type##item (struct gl520_data *, char *, int); \ +static ssize_t get_##type##n##item (struct device *, struct device_attribute *attr, char *); \ +static ssize_t get_##type##n##item (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct gl520_data *data = gl520_update_device(dev); \ + return get_##type##item(data, buf, (n)); \ +} + +#define sysfs_w(type, n, item, reg) \ +static ssize_t set_##type##item (struct i2c_client *, struct gl520_data *, const char *, size_t, int, int); \ +static ssize_t set_##type##n##item (struct device *, struct device_attribute *attr, const char *, size_t); \ +static ssize_t set_##type##n##item (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct gl520_data *data = i2c_get_clientdata(client); \ + return set_##type##item(client, data, buf, count, (n), reg); \ +} + +#define sysfs_rw_n(type, n, item, reg) \ +sysfs_r(type, n, item, reg) \ +sysfs_w(type, n, item, reg) \ +static DEVICE_ATTR(type##n##item, S_IRUGO | S_IWUSR, get_##type##n##item, set_##type##n##item); + +#define sysfs_ro_n(type, n, item, reg) \ +sysfs_r(type, n, item, reg) \ +static DEVICE_ATTR(type##n##item, S_IRUGO, get_##type##n##item, NULL); + +#define sysfs_rw(type, item, reg) \ +sysfs_r(type, 0, item, reg) \ +sysfs_w(type, 0, item, reg) \ +static DEVICE_ATTR(type##item, S_IRUGO | S_IWUSR, get_##type##0##item, set_##type##0##item); + +#define sysfs_ro(type, item, reg) \ +sysfs_r(type, 0, item, reg) \ +static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL); + + +#define sysfs_vid(n) \ +sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT) + +#define device_create_file_vid(client, n) \ +device_create_file(&client->dev, &dev_attr_cpu##n##_vid) + +#define sysfs_in(n) \ +sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \ +sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \ +sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \ + +#define device_create_file_in(client, n) \ +({device_create_file(&client->dev, &dev_attr_in##n##_input); \ +device_create_file(&client->dev, &dev_attr_in##n##_min); \ +device_create_file(&client->dev, &dev_attr_in##n##_max);}) + +#define sysfs_fan(n) \ +sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \ +sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \ +sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV) + +#define device_create_file_fan(client, n) \ +({device_create_file(&client->dev, &dev_attr_fan##n##_input); \ +device_create_file(&client->dev, &dev_attr_fan##n##_min); \ +device_create_file(&client->dev, &dev_attr_fan##n##_div);}) + +#define sysfs_fan_off(n) \ +sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \ + +#define device_create_file_fan_off(client, n) \ +device_create_file(&client->dev, &dev_attr_fan##n##_off) + +#define sysfs_temp(n) \ +sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \ +sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \ +sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST) + +#define device_create_file_temp(client, n) \ +({device_create_file(&client->dev, &dev_attr_temp##n##_input); \ +device_create_file(&client->dev, &dev_attr_temp##n##_max); \ +device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);}) + +#define sysfs_alarms() \ +sysfs_ro(alarms, , GL520_REG_ALARMS) \ +sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \ +sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK) + +#define device_create_file_alarms(client) \ +({device_create_file(&client->dev, &dev_attr_alarms); \ +device_create_file(&client->dev, &dev_attr_beep_enable); \ +device_create_file(&client->dev, &dev_attr_beep_mask);}) + + +sysfs_vid(0) + +sysfs_in(0) +sysfs_in(1) +sysfs_in(2) +sysfs_in(3) +sysfs_in(4) + +sysfs_fan(1) +sysfs_fan(2) +sysfs_fan_off(1) + +sysfs_temp(1) +sysfs_temp(2) + +sysfs_alarms() + + +static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); +} + +#define VDD_FROM_REG(val) (((val)*95+2)/4) +#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) + +#define IN_FROM_REG(val) ((val)*19) +#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) + +static ssize_t get_in_input(struct gl520_data *data, char *buf, int n) +{ + u8 r = data->in_input[n]; + + if (n == 0) + return sprintf(buf, "%d\n", VDD_FROM_REG(r)); + else + return sprintf(buf, "%d\n", IN_FROM_REG(r)); +} + +static ssize_t get_in_min(struct gl520_data *data, char *buf, int n) +{ + u8 r = data->in_min[n]; + + if (n == 0) + return sprintf(buf, "%d\n", VDD_FROM_REG(r)); + else + return sprintf(buf, "%d\n", IN_FROM_REG(r)); +} + +static ssize_t get_in_max(struct gl520_data *data, char *buf, int n) +{ + u8 r = data->in_max[n]; + + if (n == 0) + return sprintf(buf, "%d\n", VDD_FROM_REG(r)); + else + return sprintf(buf, "%d\n", IN_FROM_REG(r)); +} + +static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + u8 r; + + down(&data->update_lock); + + if (n == 0) + r = VDD_TO_REG(v); + else + r = IN_TO_REG(v); + + data->in_min[n] = r; + + if (n < 4) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); + else + gl520_write_value(client, reg, r); + + up(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + u8 r; + + if (n == 0) + r = VDD_TO_REG(v); + else + r = IN_TO_REG(v); + + down(&data->update_lock); + + data->in_max[n] = r; + + if (n < 4) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); + else + gl520_write_value(client, reg, r); + + up(&data->update_lock); + return count; +} + +#define DIV_FROM_REG(val) (1 << (val)) +#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div)))) +#define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255)); + +static ssize_t get_fan_input(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n - 1], data->fan_div[n - 1])); +} + +static ssize_t get_fan_min(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n - 1], data->fan_div[n - 1])); +} + +static ssize_t get_fan_div(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n - 1])); +} + +static ssize_t get_fan_off(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->fan_off); +} + +static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + u8 r; + + down(&data->update_lock); + r = FAN_TO_REG(v, data->fan_div[n - 1]); + data->fan_min[n - 1] = r; + + if (n == 1) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); + else + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); + + data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); + if (data->fan_min[n - 1] == 0) + data->alarm_mask &= (n == 1) ? ~0x20 : ~0x40; + else + data->alarm_mask |= (n == 1) ? 0x20 : 0x40; + data->beep_mask &= data->alarm_mask; + gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); + + up(&data->update_lock); + return count; +} + +static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + unsigned long v = simple_strtoul(buf, NULL, 10); + u8 r; + + switch (v) { + case 1: r = 0; break; + case 2: r = 1; break; + case 4: r = 2; break; + case 8: r = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v); + return -EINVAL; + } + + down(&data->update_lock); + data->fan_div[n - 1] = r; + + if (n == 1) + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xc0) | (r << 6)); + else + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4)); + + up(&data->update_lock); + return count; +} + +static ssize_t set_fan_off(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + u8 r = simple_strtoul(buf, NULL, 10)?1:0; + + down(&data->update_lock); + data->fan_off = r; + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2)); + up(&data->update_lock); + return count; +} + +#define TEMP_FROM_REG(val) (((val) - 130) * 1000) +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255)) + +static ssize_t get_temp_input(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n - 1])); +} + +static ssize_t get_temp_max(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n - 1])); +} + +static ssize_t get_temp_max_hyst(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n - 1])); +} + +static ssize_t set_temp_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max[n - 1] = TEMP_TO_REG(v);; + gl520_write_value(client, reg, data->temp_max[n - 1]); + up(&data->update_lock); + return count; +} + +static ssize_t set_temp_max_hyst(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + long v = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max_hyst[n - 1] = TEMP_TO_REG(v); + gl520_write_value(client, reg, data->temp_max_hyst[n - 1]); + up(&data->update_lock); + return count; +} + +static ssize_t get_alarms(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->alarms); +} + +static ssize_t get_beep_enable(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->beep_enable); +} + +static ssize_t get_beep_mask(struct gl520_data *data, char *buf, int n) +{ + return sprintf(buf, "%d\n", data->beep_mask); +} + +static ssize_t set_beep_enable(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + u8 r = simple_strtoul(buf, NULL, 10)?0:1; + + down(&data->update_lock); + data->beep_enable = !r; + gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2)); + up(&data->update_lock); + return count; +} + +static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +{ + u8 r = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + r &= data->alarm_mask; + data->beep_mask = r; + gl520_write_value(client, reg, r); + up(&data->update_lock); + return count; +} + + +/* + * Real code + */ + +static int gl520_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, gl520_detect); +} + +static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct gl520_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access gl520_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct gl520_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &gl520_driver; + new_client->flags = 0; + + /* Determine the chip type. */ + if (kind < 0) { + if ((gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) || + ((gl520_read_value(new_client, GL520_REG_REVISION) & 0x7f) != 0x00) || + ((gl520_read_value(new_client, GL520_REG_CONF) & 0x80) != 0x00)) { + dev_dbg(&new_client->dev, "Unknown chip type, skipping\n"); + goto exit_free; + } + } + + /* Fill in the remaining client fields */ + strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the GL520SM chip */ + gl520_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file_vid(new_client, 0); + + device_create_file_in(new_client, 0); + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + device_create_file_in(new_client, 3); + if (!data->two_temps) + device_create_file_in(new_client, 4); + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + device_create_file_fan_off(new_client, 1); + + device_create_file_temp(new_client, 1); + if (data->two_temps) + device_create_file_temp(new_client, 2); + + device_create_file_alarms(new_client); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + + +/* Called when we have found a new GL520SM. */ +static void gl520_init_client(struct i2c_client *client) +{ + struct gl520_data *data = i2c_get_clientdata(client); + u8 oldconf, conf; + + conf = oldconf = gl520_read_value(client, GL520_REG_CONF); + + data->alarm_mask = 0xff; + data->vrm = i2c_which_vrm(); + + if (extra_sensor_type == 1) + conf &= ~0x10; + else if (extra_sensor_type == 2) + conf |= 0x10; + data->two_temps = !(conf & 0x10); + + /* If IRQ# is disabled, we can safely force comparator mode */ + if (!(conf & 0x20)) + conf &= 0xf7; + + /* Enable monitoring if needed */ + conf |= 0x40; + + if (conf != oldconf) + gl520_write_value(client, GL520_REG_CONF, conf); + + gl520_update_device(&(client->dev)); + + if (data->fan_min[0] == 0) + data->alarm_mask &= ~0x20; + if (data->fan_min[1] == 0) + data->alarm_mask &= ~0x40; + + data->beep_mask &= data->alarm_mask; + gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); +} + +static int gl520_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + + +/* Registers 0x07 to 0x0c are word-sized, others are byte-sized + GL520 uses a high-byte first convention */ +static int gl520_read_value(struct i2c_client *client, u8 reg) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return swab16(i2c_smbus_read_word_data(client, reg)); + else + return i2c_smbus_read_byte_data(client, reg); +} + +static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return i2c_smbus_write_word_data(client, reg, swab16(value)); + else + return i2c_smbus_write_byte_data(client, reg, value); +} + + +static struct gl520_data *gl520_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int val; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > 2 * HZ) || + (jiffies < data->last_updated) || !data->valid) { + + dev_dbg(&client->dev, "Starting gl520sm update\n"); + + data->alarms = gl520_read_value(client, GL520_REG_ALARMS); + data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); + data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f; + + val = gl520_read_value(client, GL520_REG_IN0_LIMIT); + data->in_min[0] = val & 0xff; + data->in_max[0] = (val >> 8) & 0xff; + val = gl520_read_value(client, GL520_REG_IN1_LIMIT); + data->in_min[1] = val & 0xff; + data->in_max[1] = (val >> 8) & 0xff; + val = gl520_read_value(client, GL520_REG_IN2_LIMIT); + data->in_min[2] = val & 0xff; + data->in_max[2] = (val >> 8) & 0xff; + val = gl520_read_value(client, GL520_REG_IN3_LIMIT); + data->in_min[3] = val & 0xff; + data->in_max[3] = (val >> 8) & 0xff; + + val = gl520_read_value(client, GL520_REG_FAN_INPUT); + data->fan_input[0] = (val >> 8) & 0xff; + data->fan_input[1] = val & 0xff; + + val = gl520_read_value(client, GL520_REG_FAN_MIN); + data->fan_min[0] = (val >> 8) & 0xff; + data->fan_min[1] = val & 0xff; + + data->temp_input[0] = gl520_read_value(client, GL520_REG_TEMP1_INPUT); + data->temp_max[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX); + data->temp_max_hyst[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX_HYST); + + val = gl520_read_value(client, GL520_REG_FAN_DIV); + data->fan_div[0] = (val >> 6) & 0x03; + data->fan_div[1] = (val >> 4) & 0x03; + data->fan_off = (val >> 2) & 0x01; + + data->alarms &= data->alarm_mask; + + val = gl520_read_value(client, GL520_REG_CONF); + data->beep_enable = !((val >> 2) & 1); + + data->in_input[0] = gl520_read_value(client, GL520_REG_IN0_INPUT); + data->in_input[1] = gl520_read_value(client, GL520_REG_IN1_INPUT); + data->in_input[2] = gl520_read_value(client, GL520_REG_IN2_INPUT); + data->in_input[3] = gl520_read_value(client, GL520_REG_IN3_INPUT); + + /* Temp1 and Vin4 are the same input */ + if (data->two_temps) { + data->temp_input[1] = gl520_read_value(client, GL520_REG_TEMP2_INPUT); + data->temp_max[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX); + data->temp_max_hyst[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX_HYST); + } else { + data->in_input[4] = gl520_read_value(client, GL520_REG_IN4_INPUT); + data->in_min[4] = gl520_read_value(client, GL520_REG_IN4_MIN); + data->in_max[4] = gl520_read_value(client, GL520_REG_IN4_MAX); + } + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + + +static int __init sensors_gl520sm_init(void) +{ + return i2c_add_driver(&gl520_driver); +} + +static void __exit sensors_gl520sm_exit(void) +{ + i2c_del_driver(&gl520_driver); +} + + +MODULE_AUTHOR("Frodo Looijaard , " + "Kyösti Mälkki , " + "Maarten Deprez "); +MODULE_DESCRIPTION("GL520SM driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_gl520sm_init); +module_exit(sensors_gl520sm_exit); diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c new file mode 100644 index 00000000000..db20c9e4739 --- /dev/null +++ b/drivers/hwmon/it87.c @@ -0,0 +1,1184 @@ +/* + it87.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring. + + Supports: IT8705F Super I/O chip w/LPC interface & SMBus + IT8712F Super I/O chip w/LPC interface & SMBus + Sis950 A clone of the IT8705F + + Copyright (C) 2001 Chris Gauthron + Largely inspired by lm78.c of the same package + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + djg@pdp8.net David Gesswein 7/18/01 + Modified to fix bug with not all alarms enabled. + Added ability to read battery voltage and select temperature sensor + type at module load time. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_2(it87, it8712); + +#define REG 0x2e /* The register to read/write */ +#define DEV 0x07 /* Register: Logical device select */ +#define VAL 0x2f /* The value to read/write */ +#define PME 0x04 /* The device with the fan registers in it */ +#define DEVID 0x20 /* Register: Device ID */ +#define DEVREV 0x22 /* Register: Device Revision */ + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +static int superio_inw(int reg) +{ + int val; + outb(reg++, REG); + val = inb(VAL) << 8; + outb(reg, REG); + val |= inb(VAL); + return val; +} + +static inline void +superio_select(void) +{ + outb(DEV, REG); + outb(PME, VAL); +} + +static inline void +superio_enter(void) +{ + outb(0x87, REG); + outb(0x01, REG); + outb(0x55, REG); + outb(0x55, REG); +} + +static inline void +superio_exit(void) +{ + outb(0x02, REG); + outb(0x02, VAL); +} + +#define IT8712F_DEVID 0x8712 +#define IT8705F_DEVID 0x8705 +#define IT87_ACT_REG 0x30 +#define IT87_BASE_REG 0x60 + +/* Update battery voltage after every reading if true */ +static int update_vbat; + +/* Not all BIOSes properly configure the PWM registers */ +static int fix_pwm_polarity; + +/* Chip Type */ + +static u16 chip_type; + +/* Many IT87 constants specified below */ + +/* Length of ISA address segment */ +#define IT87_EXTENT 8 + +/* Where are the ISA address/data registers relative to the base address */ +#define IT87_ADDR_REG_OFFSET 5 +#define IT87_DATA_REG_OFFSET 6 + +/*----- The IT87 registers -----*/ + +#define IT87_REG_CONFIG 0x00 + +#define IT87_REG_ALARM1 0x01 +#define IT87_REG_ALARM2 0x02 +#define IT87_REG_ALARM3 0x03 + +#define IT87_REG_VID 0x0a +#define IT87_REG_FAN_DIV 0x0b + +/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ + +#define IT87_REG_FAN(nr) (0x0d + (nr)) +#define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) +#define IT87_REG_FAN_MAIN_CTRL 0x13 +#define IT87_REG_FAN_CTL 0x14 +#define IT87_REG_PWM(nr) (0x15 + (nr)) + +#define IT87_REG_VIN(nr) (0x20 + (nr)) +#define IT87_REG_TEMP(nr) (0x29 + (nr)) + +#define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2) +#define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2) +#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2) +#define IT87_REG_TEMP_LOW(nr) (0x41 + (nr) * 2) + +#define IT87_REG_I2C_ADDR 0x48 + +#define IT87_REG_VIN_ENABLE 0x50 +#define IT87_REG_TEMP_ENABLE 0x51 + +#define IT87_REG_CHIPID 0x58 + +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) +#define IN_FROM_REG(val) ((val) * 16) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, + 254); +} + +#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) + +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\ + ((val)+500)/1000),-128,127)) +#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) + +#define PWM_TO_REG(val) ((val) >> 1) +#define PWM_FROM_REG(val) (((val)&0x7f) << 1) + +static int DIV_TO_REG(int val) +{ + int answer = 0; + while ((val >>= 1) != 0) + answer++; + return answer; +} +#define DIV_FROM_REG(val) (1 << (val)) + + +/* For each registered IT87, we need to keep some data in memory. That + data is pointed to by it87_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new it87 client is + allocated. */ +struct it87_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[9]; /* Register value */ + u8 in_max[9]; /* Register value */ + u8 in_min[9]; /* Register value */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u8 temp[3]; /* Register value */ + u8 temp_high[3]; /* Register value */ + u8 temp_low[3]; /* Register value */ + u8 sensor; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ + u8 vid; /* Register encoding, combined */ + int vrm; + u32 alarms; /* Register encoding, combined */ + u8 fan_main_ctrl; /* Register value */ + u8 manual_pwm_ctl[3]; /* manual PWM value set by user */ +}; + + +static int it87_attach_adapter(struct i2c_adapter *adapter); +static int it87_find(int *address); +static int it87_detect(struct i2c_adapter *adapter, int address, int kind); +static int it87_detach_client(struct i2c_client *client); + +static int it87_read_value(struct i2c_client *client, u8 register); +static int it87_write_value(struct i2c_client *client, u8 register, + u8 value); +static struct it87_data *it87_update_device(struct device *dev); +static int it87_check_pwm(struct i2c_client *client); +static void it87_init_client(struct i2c_client *client, struct it87_data *data); + + +static struct i2c_driver it87_driver = { + .owner = THIS_MODULE, + .name = "it87", + .id = I2C_DRIVERID_IT87, + .flags = I2C_DF_NOTIFY, + .attach_adapter = it87_attach_adapter, + .detach_client = it87_detach_client, +}; + +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); +} + +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); +} + +static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); +} + +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val); + it87_write_value(client, IT87_REG_VIN_MIN(nr), + data->in_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val); + it87_write_value(client, IT87_REG_VIN_MAX(nr), + data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define show_in_offset(offset) \ +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in, NULL, offset); + +#define limit_in_offset(offset) \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset); + +show_in_offset(0); +limit_in_offset(0); +show_in_offset(1); +limit_in_offset(1); +show_in_offset(2); +limit_in_offset(2); +show_in_offset(3); +limit_in_offset(3); +show_in_offset(4); +limit_in_offset(4); +show_in_offset(5); +limit_in_offset(5); +show_in_offset(6); +limit_in_offset(6); +show_in_offset(7); +limit_in_offset(7); +show_in_offset(8); + +/* 3 temperatures */ +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); +} +static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); +} +static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); +} +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_high[nr] = TEMP_TO_REG(val); + it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_low[nr] = TEMP_TO_REG(val); + it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]); + up(&data->update_lock); + return count; +} +#define show_temp_offset(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, set_temp_max, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_min, set_temp_min, offset - 1); + +show_temp_offset(1); +show_temp_offset(2); +show_temp_offset(3); + +static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + u8 reg = data->sensor; /* In case the value is updated while we use it */ + + if (reg & (1 << nr)) + return sprintf(buf, "3\n"); /* thermal diode */ + if (reg & (8 << nr)) + return sprintf(buf, "2\n"); /* thermistor */ + return sprintf(buf, "0\n"); /* disabled */ +} +static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + + data->sensor &= ~(1 << nr); + data->sensor &= ~(8 << nr); + /* 3 = thermal diode; 2 = thermistor; 0 = disabled */ + if (val == 3) + data->sensor |= 1 << nr; + else if (val == 2) + data->sensor |= 8 << nr; + else if (val != 0) { + up(&data->update_lock); + return -EINVAL; + } + it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor); + up(&data->update_lock); + return count; +} +#define show_sensor_offset(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ + show_sensor, set_sensor, offset - 1); + +show_sensor_offset(1); +show_sensor_offset(2); +show_sensor_offset(3); + +/* 3 Fans */ +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr]))); +} +static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf,"%d\n", + FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]))); +} +static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); +} +static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0); +} +static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct it87_data *data = it87_update_device(dev); + return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]); +} +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + int i, min[3]; + u8 old; + + down(&data->update_lock); + old = it87_read_value(client, IT87_REG_FAN_DIV); + + for (i = 0; i < 3; i++) + min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i])); + + switch (nr) { + case 0: + case 1: + data->fan_div[nr] = DIV_TO_REG(val); + break; + case 2: + if (val < 8) + data->fan_div[nr] = 1; + else + data->fan_div[nr] = 3; + } + val = old & 0x80; + val |= (data->fan_div[0] & 0x07); + val |= (data->fan_div[1] & 0x07) << 3; + if (data->fan_div[2] == 3) + val |= 0x1 << 6; + it87_write_value(client, IT87_REG_FAN_DIV, val); + + for (i = 0; i < 3; i++) { + data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i])); + it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]); + } + up(&data->update_lock); + return count; +} +static ssize_t set_pwm_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + + if (val == 0) { + int tmp; + /* make sure the fan is on when in on/off mode */ + tmp = it87_read_value(client, IT87_REG_FAN_CTL); + it87_write_value(client, IT87_REG_FAN_CTL, tmp | (1 << nr)); + /* set on/off mode */ + data->fan_main_ctrl &= ~(1 << nr); + it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); + } else if (val == 1) { + /* set SmartGuardian mode */ + data->fan_main_ctrl |= (1 << nr); + it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); + /* set saved pwm value, clear FAN_CTLX PWM mode bit */ + it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr])); + } else { + up(&data->update_lock); + return -EINVAL; + } + + up(&data->update_lock); + return count; +} +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + if (val < 0 || val > 255) + return -EINVAL; + + down(&data->update_lock); + data->manual_pwm_ctl[nr] = val; + if (data->fan_main_ctrl & (1 << nr)) + it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr])); + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_div, set_fan_div, offset - 1); + +show_fan_offset(1); +show_fan_offset(2); +show_fan_offset(3); + +#define show_pwm_offset(offset) \ +static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ + show_pwm_enable, set_pwm_enable, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_pwm, set_pwm, offset - 1); + +show_pwm_offset(1); +show_pwm_offset(2); +show_pwm_offset(3); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +static ssize_t +show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->vrm); +} +static ssize_t +store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +#define device_create_file_vrm(client) \ +device_create_file(&client->dev, &dev_attr_vrm) + +static ssize_t +show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +#define device_create_file_vid(client) \ +device_create_file(&client->dev, &dev_attr_cpu0_vid) + +/* This function is called when: + * it87_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and it87_driver is still present) */ +static int it87_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, it87_detect); +} + +/* SuperIO detection - will change normal_isa[0] if a chip is found */ +static int it87_find(int *address) +{ + int err = -ENODEV; + + superio_enter(); + chip_type = superio_inw(DEVID); + if (chip_type != IT8712F_DEVID + && chip_type != IT8705F_DEVID) + goto exit; + + superio_select(); + if (!(superio_inb(IT87_ACT_REG) & 0x01)) { + pr_info("it87: Device not activated, skipping\n"); + goto exit; + } + + *address = superio_inw(IT87_BASE_REG) & ~(IT87_EXTENT - 1); + if (*address == 0) { + pr_info("it87: Base address not set, skipping\n"); + goto exit; + } + + err = 0; + pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n", + chip_type, *address, superio_inb(DEVREV) & 0x0f); + +exit: + superio_exit(); + return err; +} + +/* This function is called by i2c_detect */ +int it87_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i; + struct i2c_client *new_client; + struct it87_data *data; + int err = 0; + const char *name = ""; + int is_isa = i2c_is_isa_adapter(adapter); + int enable_pwm_interface; + + if (!is_isa && + !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto ERROR0; + + /* Reserve the ISA region */ + if (is_isa) + if (!request_region(address, IT87_EXTENT, it87_driver.name)) + goto ERROR0; + + /* Probe whether there is anything available on this address. Already + done for SMBus and Super-I/O clients */ + if (kind < 0) { + if (is_isa && !chip_type) { +#define REALLY_SLOW_IO + /* We need the timeouts for at least some IT87-like chips. But only + if we read 'undefined' registers. */ + i = inb_p(address + 1); + if (inb_p(address + 2) != i + || inb_p(address + 3) != i + || inb_p(address + 7) != i) { + err = -ENODEV; + goto ERROR1; + } +#undef REALLY_SLOW_IO + + /* Let's just hope nothing breaks here */ + i = inb_p(address + 5) & 0x7f; + outb_p(~i & 0x7f, address + 5); + if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { + outb_p(i, address + 5); + err = -ENODEV; + goto ERROR1; + } + } + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access it87_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct it87_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR1; + } + memset(data, 0, sizeof(struct it87_data)); + + new_client = &data->client; + if (is_isa) + init_MUTEX(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &it87_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + if (kind < 0) { + if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80) + || (!is_isa + && it87_read_value(new_client, IT87_REG_I2C_ADDR) != address)) { + err = -ENODEV; + goto ERROR2; + } + } + + /* Determine the chip type. */ + if (kind <= 0) { + i = it87_read_value(new_client, IT87_REG_CHIPID); + if (i == 0x90) { + kind = it87; + if ((is_isa) && (chip_type == IT8712F_DEVID)) + kind = it8712; + } + else { + if (kind == 0) + dev_info(&adapter->dev, + "Ignoring 'force' parameter for unknown chip at " + "adapter %d, address 0x%02x\n", + i2c_adapter_id(adapter), address); + err = -ENODEV; + goto ERROR2; + } + } + + if (kind == it87) { + name = "it87"; + } else if (kind == it8712) { + name = "it8712"; + } + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->type = kind; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR2; + + /* Check PWM configuration */ + enable_pwm_interface = it87_check_pwm(new_client); + + /* Initialize the IT87 chip */ + it87_init_client(new_client, data); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); + device_create_file(&new_client->dev, &dev_attr_alarms); + if (enable_pwm_interface) { + device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr); + device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); + } + + if (data->type == it8712) { + data->vrm = i2c_which_vrm(); + device_create_file_vrm(new_client); + device_create_file_vid(new_client); + } + + return 0; + +ERROR2: + kfree(data); +ERROR1: + if (is_isa) + release_region(address, IT87_EXTENT); +ERROR0: + return err; +} + +static int it87_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + if(i2c_is_isa_client(client)) + release_region(client->addr, IT87_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +/* The SMBus locks itself, but ISA access must be locked explicitly! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, + would slow down the IT87 access and should not be necessary. */ +static int it87_read_value(struct i2c_client *client, u8 reg) +{ + struct it87_data *data = i2c_get_clientdata(client); + + int res; + if (i2c_is_isa_client(client)) { + down(&data->lock); + outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); + res = inb_p(client->addr + IT87_DATA_REG_OFFSET); + up(&data->lock); + return res; + } else + return i2c_smbus_read_byte_data(client, reg); +} + +/* The SMBus locks itself, but ISA access muse be locked explicitly! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, + would slow down the IT87 access and should not be necessary. */ +static int it87_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + struct it87_data *data = i2c_get_clientdata(client); + + if (i2c_is_isa_client(client)) { + down(&data->lock); + outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); + outb_p(value, client->addr + IT87_DATA_REG_OFFSET); + up(&data->lock); + return 0; + } else + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* Return 1 if and only if the PWM interface is safe to use */ +static int it87_check_pwm(struct i2c_client *client) +{ + /* Some BIOSes fail to correctly configure the IT87 fans. All fans off + * and polarity set to active low is sign that this is the case so we + * disable pwm control to protect the user. */ + int tmp = it87_read_value(client, IT87_REG_FAN_CTL); + if ((tmp & 0x87) == 0) { + if (fix_pwm_polarity) { + /* The user asks us to attempt a chip reconfiguration. + * This means switching to active high polarity and + * inverting all fan speed values. */ + int i; + u8 pwm[3]; + + for (i = 0; i < 3; i++) + pwm[i] = it87_read_value(client, + IT87_REG_PWM(i)); + + /* If any fan is in automatic pwm mode, the polarity + * might be correct, as suspicious as it seems, so we + * better don't change anything (but still disable the + * PWM interface). */ + if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) { + dev_info(&client->dev, "Reconfiguring PWM to " + "active high polarity\n"); + it87_write_value(client, IT87_REG_FAN_CTL, + tmp | 0x87); + for (i = 0; i < 3; i++) + it87_write_value(client, + IT87_REG_PWM(i), + 0x7f & ~pwm[i]); + return 1; + } + + dev_info(&client->dev, "PWM configuration is " + "too broken to be fixed\n"); + } + + dev_info(&client->dev, "Detected broken BIOS " + "defaults, disabling PWM interface\n"); + return 0; + } else if (fix_pwm_polarity) { + dev_info(&client->dev, "PWM configuration looks " + "sane, won't touch\n"); + } + + return 1; +} + +/* Called when we have found a new IT87. */ +static void it87_init_client(struct i2c_client *client, struct it87_data *data) +{ + int tmp, i; + + /* initialize to sane defaults: + * - if the chip is in manual pwm mode, this will be overwritten with + * the actual settings on the chip (so in this case, initialization + * is not needed) + * - if in automatic or on/off mode, we could switch to manual mode, + * read the registers and set manual_pwm_ctl accordingly, but currently + * this is not implemented, so we initialize to something sane */ + for (i = 0; i < 3; i++) { + data->manual_pwm_ctl[i] = 0xff; + } + + /* Check if temperature channnels are reset manually or by some reason */ + tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE); + if ((tmp & 0x3f) == 0) { + /* Temp1,Temp3=thermistor; Temp2=thermal diode */ + tmp = (tmp & 0xc0) | 0x2a; + it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp); + } + data->sensor = tmp; + + /* Check if voltage monitors are reset manually or by some reason */ + tmp = it87_read_value(client, IT87_REG_VIN_ENABLE); + if ((tmp & 0xff) == 0) { + /* Enable all voltage monitors */ + it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff); + } + + /* Check if tachometers are reset manually or by some reason */ + data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL); + if ((data->fan_main_ctrl & 0x70) == 0) { + /* Enable all fan tachometers */ + data->fan_main_ctrl |= 0x70; + it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); + } + + /* Set current fan mode registers and the default settings for the + * other mode registers */ + for (i = 0; i < 3; i++) { + if (data->fan_main_ctrl & (1 << i)) { + /* pwm mode */ + tmp = it87_read_value(client, IT87_REG_PWM(i)); + if (tmp & 0x80) { + /* automatic pwm - not yet implemented, but + * leave the settings made by the BIOS alone + * until a change is requested via the sysfs + * interface */ + } else { + /* manual pwm */ + data->manual_pwm_ctl[i] = PWM_FROM_REG(tmp); + } + } + } + + /* Start monitoring */ + it87_write_value(client, IT87_REG_CONFIG, + (it87_read_value(client, IT87_REG_CONFIG) & 0x36) + | (update_vbat ? 0x41 : 0x01)); +} + +static struct it87_data *it87_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + if (update_vbat) { + /* Cleared after each update, so reenable. Value + returned by this read will be previous value */ + it87_write_value(client, IT87_REG_CONFIG, + it87_read_value(client, IT87_REG_CONFIG) | 0x40); + } + for (i = 0; i <= 7; i++) { + data->in[i] = + it87_read_value(client, IT87_REG_VIN(i)); + data->in_min[i] = + it87_read_value(client, IT87_REG_VIN_MIN(i)); + data->in_max[i] = + it87_read_value(client, IT87_REG_VIN_MAX(i)); + } + data->in[8] = + it87_read_value(client, IT87_REG_VIN(8)); + /* Temperature sensor doesn't have limit registers, set + to min and max value */ + data->in_min[8] = 0; + data->in_max[8] = 255; + + for (i = 0; i < 3; i++) { + data->fan[i] = + it87_read_value(client, IT87_REG_FAN(i)); + data->fan_min[i] = + it87_read_value(client, IT87_REG_FAN_MIN(i)); + } + for (i = 0; i < 3; i++) { + data->temp[i] = + it87_read_value(client, IT87_REG_TEMP(i)); + data->temp_high[i] = + it87_read_value(client, IT87_REG_TEMP_HIGH(i)); + data->temp_low[i] = + it87_read_value(client, IT87_REG_TEMP_LOW(i)); + } + + i = it87_read_value(client, IT87_REG_FAN_DIV); + data->fan_div[0] = i & 0x07; + data->fan_div[1] = (i >> 3) & 0x07; + data->fan_div[2] = (i & 0x40) ? 3 : 1; + + data->alarms = + it87_read_value(client, IT87_REG_ALARM1) | + (it87_read_value(client, IT87_REG_ALARM2) << 8) | + (it87_read_value(client, IT87_REG_ALARM3) << 16); + data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL); + + data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE); + /* The 8705 does not have VID capability */ + if (data->type == it8712) { + data->vid = it87_read_value(client, IT87_REG_VID); + data->vid &= 0x1f; + } + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sm_it87_init(void) +{ + int addr; + + if (!it87_find(&addr)) { + normal_isa[0] = addr; + } + return i2c_add_driver(&it87_driver); +} + +static void __exit sm_it87_exit(void) +{ + i2c_del_driver(&it87_driver); +} + + +MODULE_AUTHOR("Chris Gauthron "); +MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver"); +module_param(update_vbat, bool, 0); +MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); +module_param(fix_pwm_polarity, bool, 0); +MODULE_PARM_DESC(fix_pwm_polarity, "Force PWM polarity to active high (DANGEROUS)"); +MODULE_LICENSE("GPL"); + +module_init(sm_it87_init); +module_exit(sm_it87_exit); diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c new file mode 100644 index 00000000000..7c6f9ea5a25 --- /dev/null +++ b/drivers/hwmon/lm63.c @@ -0,0 +1,597 @@ +/* + * lm63.c - driver for the National Semiconductor LM63 temperature sensor + * with integrated fan control + * Copyright (C) 2004-2005 Jean Delvare + * Based on the lm90 driver. + * + * The LM63 is a sensor chip made by National Semiconductor. It measures + * two temperatures (its own and one external one) and the speed of one + * fan, those speed it can additionally control. Complete datasheet can be + * obtained from National's website at: + * http://www.national.com/pf/LM/LM63.html + * + * The LM63 is basically an LM86 with fan speed monitoring and control + * capabilities added. It misses some of the LM86 features though: + * - No low limit for local temperature. + * - No critical limit for local temperature. + * - Critical limit for remote temperature can be changed only once. We + * will consider that the critical limit is read-only. + * + * The datasheet isn't very clear about what the tachometer reading is. + * I had a explanation from National Semiconductor though. The two lower + * bits of the read value have to be masked out. The value is still 16 bit + * in width. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan + * Address is fully defined internally and cannot be changed. + */ + +static unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(lm63); + +/* + * The LM63 registers + */ + +#define LM63_REG_CONFIG1 0x03 +#define LM63_REG_CONFIG2 0xBF +#define LM63_REG_CONFIG_FAN 0x4A + +#define LM63_REG_TACH_COUNT_MSB 0x47 +#define LM63_REG_TACH_COUNT_LSB 0x46 +#define LM63_REG_TACH_LIMIT_MSB 0x49 +#define LM63_REG_TACH_LIMIT_LSB 0x48 + +#define LM63_REG_PWM_VALUE 0x4C +#define LM63_REG_PWM_FREQ 0x4D + +#define LM63_REG_LOCAL_TEMP 0x00 +#define LM63_REG_LOCAL_HIGH 0x05 + +#define LM63_REG_REMOTE_TEMP_MSB 0x01 +#define LM63_REG_REMOTE_TEMP_LSB 0x10 +#define LM63_REG_REMOTE_OFFSET_MSB 0x11 +#define LM63_REG_REMOTE_OFFSET_LSB 0x12 +#define LM63_REG_REMOTE_HIGH_MSB 0x07 +#define LM63_REG_REMOTE_HIGH_LSB 0x13 +#define LM63_REG_REMOTE_LOW_MSB 0x08 +#define LM63_REG_REMOTE_LOW_LSB 0x14 +#define LM63_REG_REMOTE_TCRIT 0x19 +#define LM63_REG_REMOTE_TCRIT_HYST 0x21 + +#define LM63_REG_ALERT_STATUS 0x02 +#define LM63_REG_ALERT_MASK 0x16 + +#define LM63_REG_MAN_ID 0xFE +#define LM63_REG_CHIP_ID 0xFF + +/* + * Conversions and various macros + * For tachometer counts, the LM63 uses 16-bit values. + * For local temperature and high limit, remote critical limit and hysteresis + * value, it uses signed 8-bit values with LSB = 1 degree Celsius. + * For remote temperature, low and high limits, it uses signed 11-bit values + * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers. + */ + +#define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ + 5400000 / (reg)) +#define FAN_TO_REG(val) ((val) <= 82 ? 0xFFFC : \ + (5400000 / (val)) & 0xFFFC) +#define TEMP8_FROM_REG(reg) ((reg) * 1000) +#define TEMP8_TO_REG(val) ((val) <= -128000 ? -128 : \ + (val) >= 127000 ? 127 : \ + (val) < 0 ? ((val) - 500) / 1000 : \ + ((val) + 500) / 1000) +#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) +#define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ + (val) >= 127875 ? 0x7FE0 : \ + (val) < 0 ? ((val) - 62) / 125 * 32 : \ + ((val) + 62) / 125 * 32) +#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ + (val) >= 127000 ? 127 : \ + ((val) + 500) / 1000) + +/* + * Functions declaration + */ + +static int lm63_attach_adapter(struct i2c_adapter *adapter); +static int lm63_detach_client(struct i2c_client *client); + +static struct lm63_data *lm63_update_device(struct device *dev); + +static int lm63_detect(struct i2c_adapter *adapter, int address, int kind); +static void lm63_init_client(struct i2c_client *client); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver lm63_driver = { + .owner = THIS_MODULE, + .name = "lm63", + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm63_attach_adapter, + .detach_client = lm63_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct lm63_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + u8 config, config_fan; + u16 fan[2]; /* 0: input + 1: low limit */ + u8 pwm1_freq; + u8 pwm1_value; + s8 temp8[3]; /* 0: local input + 1: local high limit + 2: remote critical limit */ + s16 temp11[3]; /* 0: remote input + 1: remote low limit + 2: remote high limit */ + u8 temp2_crit_hyst; + u8 alarms; +}; + +/* + * Sysfs callback functions and files + */ + +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index])); +} + +static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan[1] = FAN_TO_REG(val); + i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB, + data->fan[1] & 0xFF); + i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB, + data->fan[1] >> 8); + up(&data->update_lock); + return count; +} + +static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? + 255 : (data->pwm1_value * 255 + data->pwm1_freq) / + (2 * data->pwm1_freq)); +} + +static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + unsigned long val; + + if (!(data->config_fan & 0x20)) /* register is read-only */ + return -EPERM; + + val = simple_strtoul(buf, NULL, 10); + down(&data->update_lock); + data->pwm1_value = val <= 0 ? 0 : + val >= 255 ? 2 * data->pwm1_freq : + (val * data->pwm1_freq * 2 + 127) / 255; + i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value); + up(&data->update_lock); + return count; +} + +static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); +} + +static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])); +} + +static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp8[1] = TEMP8_TO_REG(val); + i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); + up(&data->update_lock); + return count; +} + +static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])); +} + +static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM63_REG_REMOTE_LOW_MSB, + LM63_REG_REMOTE_LOW_LSB, + LM63_REG_REMOTE_HIGH_MSB, + LM63_REG_REMOTE_HIGH_LSB, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + data->temp11[nr] = TEMP11_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], + data->temp11[nr] >> 8); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], + data->temp11[nr] & 0xff); + up(&data->update_lock); + return count; +} + +/* Hysteresis register holds a relative value, while we want to present + an absolute to user-space */ +static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2]) + - TEMP8_FROM_REG(data->temp2_crit_hyst)); +} + +/* And now the other way around, user-space provides an absolute + hysteresis value and we have to store a relative one */ +static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + long hyst; + + down(&data->update_lock); + hyst = TEMP8_FROM_REG(data->temp8[2]) - val; + i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, + HYST_TO_REG(hyst)); + up(&data->update_lock); + return count; +} + +static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} + +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, + set_fan, 1); + +static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); +static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 1); + +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 1); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 2); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2); +static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, + set_temp2_crit_hyst); + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* + * Real code + */ + +static int lm63_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm63_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm63_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct lm63_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm63_data)); + + /* The common I2C client data is placed right before the + LM63-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm63_driver; + new_client->flags = 0; + + /* Default to an LM63 if forced */ + if (kind == 0) + kind = lm63; + + if (kind < 0) { /* must identify */ + u8 man_id, chip_id, reg_config1, reg_config2; + u8 reg_alert_status, reg_alert_mask; + + man_id = i2c_smbus_read_byte_data(new_client, + LM63_REG_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + LM63_REG_CHIP_ID); + reg_config1 = i2c_smbus_read_byte_data(new_client, + LM63_REG_CONFIG1); + reg_config2 = i2c_smbus_read_byte_data(new_client, + LM63_REG_CONFIG2); + reg_alert_status = i2c_smbus_read_byte_data(new_client, + LM63_REG_ALERT_STATUS); + reg_alert_mask = i2c_smbus_read_byte_data(new_client, + LM63_REG_ALERT_MASK); + + if (man_id == 0x01 /* National Semiconductor */ + && chip_id == 0x41 /* LM63 */ + && (reg_config1 & 0x18) == 0x00 + && (reg_config2 & 0xF8) == 0x00 + && (reg_alert_status & 0x20) == 0x00 + && (reg_alert_mask & 0xA4) == 0xA4) { + kind = lm63; + } else { /* failed */ + dev_dbg(&adapter->dev, "Unsupported chip " + "(man_id=0x%02X, chip_id=0x%02X).\n", + man_id, chip_id); + goto exit_free; + } + } + + strlcpy(new_client->name, "lm63", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the LM63 chip */ + lm63_init_client(new_client); + + /* Register sysfs hooks */ + if (data->config & 0x04) { /* tachometer enabled */ + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min.dev_attr); + } + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_pwm1_enable); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +/* Idealy we shouldn't have to initialize anything, since the BIOS + should have taken care of everything */ +static void lm63_init_client(struct i2c_client *client) +{ + struct lm63_data *data = i2c_get_clientdata(client); + + data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); + data->config_fan = i2c_smbus_read_byte_data(client, + LM63_REG_CONFIG_FAN); + + /* Start converting if needed */ + if (data->config & 0x40) { /* standby */ + dev_dbg(&client->dev, "Switching to operational mode"); + data->config &= 0xA7; + i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1, + data->config); + } + + /* We may need pwm1_freq before ever updating the client data */ + data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ); + if (data->pwm1_freq == 0) + data->pwm1_freq = 1; + + /* Show some debug info about the LM63 configuration */ + dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", + (data->config & 0x04) ? "tachometer input" : + "alert output"); + dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n", + (data->config_fan & 0x08) ? "1.4" : "360", + ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq); + dev_dbg(&client->dev, "PWM output active %s, %s mode\n", + (data->config_fan & 0x10) ? "low" : "high", + (data->config_fan & 0x20) ? "manual" : "auto"); +} + +static int lm63_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static struct lm63_data *lm63_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + if (data->config & 0x04) { /* tachometer enabled */ + /* order matters for fan1_input */ + data->fan[0] = i2c_smbus_read_byte_data(client, + LM63_REG_TACH_COUNT_LSB) & 0xFC; + data->fan[0] |= i2c_smbus_read_byte_data(client, + LM63_REG_TACH_COUNT_MSB) << 8; + data->fan[1] = (i2c_smbus_read_byte_data(client, + LM63_REG_TACH_LIMIT_LSB) & 0xFC) + | (i2c_smbus_read_byte_data(client, + LM63_REG_TACH_LIMIT_MSB) << 8); + } + + data->pwm1_freq = i2c_smbus_read_byte_data(client, + LM63_REG_PWM_FREQ); + if (data->pwm1_freq == 0) + data->pwm1_freq = 1; + data->pwm1_value = i2c_smbus_read_byte_data(client, + LM63_REG_PWM_VALUE); + + data->temp8[0] = i2c_smbus_read_byte_data(client, + LM63_REG_LOCAL_TEMP); + data->temp8[1] = i2c_smbus_read_byte_data(client, + LM63_REG_LOCAL_HIGH); + + /* order matters for temp2_input */ + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TEMP_MSB) << 8; + data->temp11[0] |= i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TEMP_LSB); + data->temp11[1] = (i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_LOW_MSB) << 8) + | i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_LOW_LSB); + data->temp11[2] = (i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_HIGH_MSB) << 8) + | i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_HIGH_LSB); + data->temp8[2] = i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TCRIT); + data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_TCRIT_HYST); + + data->alarms = i2c_smbus_read_byte_data(client, + LM63_REG_ALERT_STATUS) & 0x7F; + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm63_init(void) +{ + return i2c_add_driver(&lm63_driver); +} + +static void __exit sensors_lm63_exit(void) +{ + i2c_del_driver(&lm63_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("LM63 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm63_init); +module_exit(sensors_lm63_exit); diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c new file mode 100644 index 00000000000..5be164ed278 --- /dev/null +++ b/drivers/hwmon/lm75.c @@ -0,0 +1,296 @@ +/* + lm75.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include "lm75.h" + + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, + 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(lm75); + +/* Many LM75 constants specified below */ + +/* The LM75 registers */ +#define LM75_REG_TEMP 0x00 +#define LM75_REG_CONF 0x01 +#define LM75_REG_TEMP_HYST 0x02 +#define LM75_REG_TEMP_OS 0x03 + +/* Each client has this additional data */ +struct lm75_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + u16 temp_input; /* Register values */ + u16 temp_max; + u16 temp_hyst; +}; + +static int lm75_attach_adapter(struct i2c_adapter *adapter); +static int lm75_detect(struct i2c_adapter *adapter, int address, int kind); +static void lm75_init_client(struct i2c_client *client); +static int lm75_detach_client(struct i2c_client *client); +static int lm75_read_value(struct i2c_client *client, u8 reg); +static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); +static struct lm75_data *lm75_update_device(struct device *dev); + + +/* This is the driver that will be inserted */ +static struct i2c_driver lm75_driver = { + .owner = THIS_MODULE, + .name = "lm75", + .id = I2C_DRIVERID_LM75, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm75_attach_adapter, + .detach_client = lm75_detach_client, +}; + +#define show(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm75_data *data = lm75_update_device(dev); \ + return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ +} +show(temp_max); +show(temp_hyst); +show(temp_input); + +#define set(value, reg) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm75_data *data = i2c_get_clientdata(client); \ + int temp = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = LM75_TEMP_TO_REG(temp); \ + lm75_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} +set(temp_max, LM75_REG_TEMP_OS); +set(temp_hyst, LM75_REG_TEMP_HYST); + +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); +static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); + +static int lm75_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm75_detect); +} + +/* This function is called by i2c_detect */ +static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i; + struct i2c_client *new_client; + struct lm75_data *data; + int err = 0; + const char *name = ""; + + /* Make sure we aren't probing the ISA bus!! This is just a safety check + at this moment; i2c_detect really won't call us. */ +#ifdef DEBUG + if (i2c_is_isa_adapter(adapter)) { + dev_dbg(&adapter->dev, + "lm75_detect called for an ISA bus adapter?!?\n"); + goto exit; + } +#endif + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm75_{read,write}_value. */ + if (!(data = kmalloc(sizeof(struct lm75_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm75_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm75_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. There is no identification- + dedicated register so we have to rely on several tricks: + unused bits, registers cycling over 8-address boundaries, + addresses 0x04-0x07 returning the last read value. + The cycling+unused addresses combination is not tested, + since it would significantly slow the detection down and would + hardly add any value. */ + if (kind < 0) { + int cur, conf, hyst, os; + + /* Unused addresses */ + cur = i2c_smbus_read_word_data(new_client, 0); + conf = i2c_smbus_read_byte_data(new_client, 1); + hyst = i2c_smbus_read_word_data(new_client, 2); + if (i2c_smbus_read_word_data(new_client, 4) != hyst + || i2c_smbus_read_word_data(new_client, 5) != hyst + || i2c_smbus_read_word_data(new_client, 6) != hyst + || i2c_smbus_read_word_data(new_client, 7) != hyst) + goto exit_free; + os = i2c_smbus_read_word_data(new_client, 3); + if (i2c_smbus_read_word_data(new_client, 4) != os + || i2c_smbus_read_word_data(new_client, 5) != os + || i2c_smbus_read_word_data(new_client, 6) != os + || i2c_smbus_read_word_data(new_client, 7) != os) + goto exit_free; + + /* Unused bits */ + if (conf & 0xe0) + goto exit_free; + + /* Addresses cycling */ + for (i = 8; i < 0xff; i += 8) + if (i2c_smbus_read_byte_data(new_client, i + 1) != conf + || i2c_smbus_read_word_data(new_client, i + 2) != hyst + || i2c_smbus_read_word_data(new_client, i + 3) != os) + goto exit_free; + } + + /* Determine the chip type - only one kind supported! */ + if (kind <= 0) + kind = lm75; + + if (kind == lm75) { + name = "lm75"; + } + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the LM75 chip */ + lm75_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int lm75_detach_client(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); + return 0; +} + +/* All registers are word-sized, except for the configuration register. + LM75 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +static int lm75_read_value(struct i2c_client *client, u8 reg) +{ + if (reg == LM75_REG_CONF) + return i2c_smbus_read_byte_data(client, reg); + else + return swab16(i2c_smbus_read_word_data(client, reg)); +} + +/* All registers are word-sized, except for the configuration register. + LM75 uses a high-byte first convention, which is exactly opposite to + the usual practice. */ +static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (reg == LM75_REG_CONF) + return i2c_smbus_write_byte_data(client, reg, value); + else + return i2c_smbus_write_word_data(client, reg, swab16(value)); +} + +static void lm75_init_client(struct i2c_client *client) +{ + /* Initialize the LM75 chip */ + lm75_write_value(client, LM75_REG_CONF, 0); +} + +static struct lm75_data *lm75_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm75_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting lm75 update\n"); + + data->temp_input = lm75_read_value(client, LM75_REG_TEMP); + data->temp_max = lm75_read_value(client, LM75_REG_TEMP_OS); + data->temp_hyst = lm75_read_value(client, LM75_REG_TEMP_HYST); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm75_init(void) +{ + return i2c_add_driver(&lm75_driver); +} + +static void __exit sensors_lm75_exit(void) +{ + i2c_del_driver(&lm75_driver); +} + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("LM75 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm75_init); +module_exit(sensors_lm75_exit); diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h new file mode 100644 index 00000000000..63e3f2fb4c2 --- /dev/null +++ b/drivers/hwmon/lm75.h @@ -0,0 +1,49 @@ +/* + lm75.h - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 2003 Mark M. Hoffman + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + This file contains common code for encoding/decoding LM75 type + temperature readings, which are emulated by many of the chips + we support. As the user is unlikely to load more than one driver + which contains this code, we don't worry about the wasted space. +*/ + +#include + +/* straight from the datasheet */ +#define LM75_TEMP_MIN (-55000) +#define LM75_TEMP_MAX 125000 + +/* TEMP: 0.001C/bit (-55C to +125C) + REG: (0.5C/bit, two's complement) << 7 */ +static inline u16 LM75_TEMP_TO_REG(int temp) +{ + int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); + ntemp += (ntemp<0 ? -250 : 250); + return (u16)((ntemp / 500) << 7); +} + +static inline int LM75_TEMP_FROM_REG(u16 reg) +{ + /* use integer division instead of equivalent right shift to + guarantee arithmetic shift and preserve the sign */ + return ((s16)reg / 128) * 500; +} + diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c new file mode 100644 index 00000000000..b98f4495299 --- /dev/null +++ b/drivers/hwmon/lm77.c @@ -0,0 +1,420 @@ +/* + lm77.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + + Copyright (c) 2004 Andras BALI + + Heavily based on lm75.c by Frodo Looijaard . The LM77 + is a temperature sensor and thermal window comparator with 0.5 deg + resolution made by National Semiconductor. Complete datasheet can be + obtained at their site: + http://www.national.com/pf/LM/LM77.html + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(lm77); + +/* The LM77 registers */ +#define LM77_REG_TEMP 0x00 +#define LM77_REG_CONF 0x01 +#define LM77_REG_TEMP_HYST 0x02 +#define LM77_REG_TEMP_CRIT 0x03 +#define LM77_REG_TEMP_MIN 0x04 +#define LM77_REG_TEMP_MAX 0x05 + +/* Each client has this additional data */ +struct lm77_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; + unsigned long last_updated; /* In jiffies */ + int temp_input; /* Temperatures */ + int temp_crit; + int temp_min; + int temp_max; + int temp_hyst; + u8 alarms; +}; + +static int lm77_attach_adapter(struct i2c_adapter *adapter); +static int lm77_detect(struct i2c_adapter *adapter, int address, int kind); +static void lm77_init_client(struct i2c_client *client); +static int lm77_detach_client(struct i2c_client *client); +static u16 lm77_read_value(struct i2c_client *client, u8 reg); +static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value); + +static struct lm77_data *lm77_update_device(struct device *dev); + + +/* This is the driver that will be inserted */ +static struct i2c_driver lm77_driver = { + .owner = THIS_MODULE, + .name = "lm77", + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm77_attach_adapter, + .detach_client = lm77_detach_client, +}; + +/* straight from the datasheet */ +#define LM77_TEMP_MIN (-55000) +#define LM77_TEMP_MAX 125000 + +/* In the temperature registers, the low 3 bits are not part of the + temperature values; they are the status bits. */ +static inline u16 LM77_TEMP_TO_REG(int temp) +{ + int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX); + return (u16)((ntemp / 500) * 8); +} + +static inline int LM77_TEMP_FROM_REG(u16 reg) +{ + return ((int)reg / 8) * 500; +} + +/* sysfs stuff */ + +/* read routines for temperature limits */ +#define show(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm77_data *data = lm77_update_device(dev); \ + return sprintf(buf, "%d\n", data->value); \ +} + +show(temp_input); +show(temp_crit); +show(temp_min); +show(temp_max); +show(alarms); + +/* read routines for hysteresis values */ +static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm77_data *data = lm77_update_device(dev); + return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst); +} +static ssize_t show_temp_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm77_data *data = lm77_update_device(dev); + return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst); +} +static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm77_data *data = lm77_update_device(dev); + return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst); +} + +/* write routines */ +#define set(value, reg) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm77_data *data = i2c_get_clientdata(client); \ + long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = val; \ + lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \ + up(&data->update_lock); \ + return count; \ +} + +set(temp_min, LM77_REG_TEMP_MIN); +set(temp_max, LM77_REG_TEMP_MAX); + +/* hysteresis is stored as a relative value on the chip, so it has to be + converted first */ +static ssize_t set_temp_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm77_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->temp_hyst = data->temp_crit - val; + lm77_write_value(client, LM77_REG_TEMP_HYST, + LM77_TEMP_TO_REG(data->temp_hyst)); + up(&data->update_lock); + return count; +} + +/* preserve hysteresis when setting T_crit */ +static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm77_data *data = i2c_get_clientdata(client); + long val = simple_strtoul(buf, NULL, 10); + int oldcrithyst; + + down(&data->update_lock); + oldcrithyst = data->temp_crit - data->temp_hyst; + data->temp_crit = val; + data->temp_hyst = data->temp_crit - oldcrithyst; + lm77_write_value(client, LM77_REG_TEMP_CRIT, + LM77_TEMP_TO_REG(data->temp_crit)); + lm77_write_value(client, LM77_REG_TEMP_HYST, + LM77_TEMP_TO_REG(data->temp_hyst)); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, + show_temp_input, NULL); +static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, + show_temp_crit, set_temp_crit); +static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, + show_temp_min, set_temp_min); +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, + show_temp_max, set_temp_max); + +static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, + show_temp_crit_hyst, set_temp_crit_hyst); +static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, + show_temp_min_hyst, NULL); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, + show_temp_max_hyst, NULL); + +static DEVICE_ATTR(alarms, S_IRUGO, + show_alarms, NULL); + +static int lm77_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm77_detect); +} + +/* This function is called by i2c_detect */ +static int lm77_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm77_data *data; + int err = 0; + const char *name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm77_{read,write}_value. */ + if (!(data = kmalloc(sizeof(struct lm77_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm77_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm77_driver; + new_client->flags = 0; + + /* Here comes the remaining detection. Since the LM77 has no + register dedicated to identification, we have to rely on the + following tricks: + + 1. the high 4 bits represent the sign and thus they should + always be the same + 2. the high 3 bits are unused in the configuration register + 3. addresses 0x06 and 0x07 return the last read value + 4. registers cycling over 8-address boundaries + + Word-sized registers are high-byte first. */ + if (kind < 0) { + int i, cur, conf, hyst, crit, min, max; + + /* addresses cycling */ + cur = i2c_smbus_read_word_data(new_client, 0); + conf = i2c_smbus_read_byte_data(new_client, 1); + hyst = i2c_smbus_read_word_data(new_client, 2); + crit = i2c_smbus_read_word_data(new_client, 3); + min = i2c_smbus_read_word_data(new_client, 4); + max = i2c_smbus_read_word_data(new_client, 5); + for (i = 8; i <= 0xff; i += 8) + if (i2c_smbus_read_byte_data(new_client, i + 1) != conf + || i2c_smbus_read_word_data(new_client, i + 2) != hyst + || i2c_smbus_read_word_data(new_client, i + 3) != crit + || i2c_smbus_read_word_data(new_client, i + 4) != min + || i2c_smbus_read_word_data(new_client, i + 5) != max) + goto exit_free; + + /* sign bits */ + if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0) + || ((hyst & 0x00f0) != 0xf0 && (hyst & 0x00f0) != 0x0) + || ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0) + || ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0) + || ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0)) + goto exit_free; + + /* unused bits */ + if (conf & 0xe0) + goto exit_free; + + /* 0x06 and 0x07 return the last read value */ + cur = i2c_smbus_read_word_data(new_client, 0); + if (i2c_smbus_read_word_data(new_client, 6) != cur + || i2c_smbus_read_word_data(new_client, 7) != cur) + goto exit_free; + hyst = i2c_smbus_read_word_data(new_client, 2); + if (i2c_smbus_read_word_data(new_client, 6) != hyst + || i2c_smbus_read_word_data(new_client, 7) != hyst) + goto exit_free; + min = i2c_smbus_read_word_data(new_client, 4); + if (i2c_smbus_read_word_data(new_client, 6) != min + || i2c_smbus_read_word_data(new_client, 7) != min) + goto exit_free; + + } + + /* Determine the chip type - only one kind supported! */ + if (kind <= 0) + kind = lm77; + + if (kind == lm77) { + name = "lm77"; + } + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the LM77 chip */ + lm77_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int lm77_detach_client(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); + return 0; +} + +/* All registers are word-sized, except for the configuration register. + The LM77 uses the high-byte first convention. */ +static u16 lm77_read_value(struct i2c_client *client, u8 reg) +{ + if (reg == LM77_REG_CONF) + return i2c_smbus_read_byte_data(client, reg); + else + return swab16(i2c_smbus_read_word_data(client, reg)); +} + +static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if (reg == LM77_REG_CONF) + return i2c_smbus_write_byte_data(client, reg, value); + else + return i2c_smbus_write_word_data(client, reg, swab16(value)); +} + +static void lm77_init_client(struct i2c_client *client) +{ + /* Initialize the LM77 chip - turn off shutdown mode */ + int conf = lm77_read_value(client, LM77_REG_CONF); + if (conf & 1) + lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); +} + +static struct lm77_data *lm77_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm77_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting lm77 update\n"); + data->temp_input = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP)); + data->temp_hyst = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_HYST)); + data->temp_crit = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_CRIT)); + data->temp_min = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_MIN)); + data->temp_max = + LM77_TEMP_FROM_REG(lm77_read_value(client, + LM77_REG_TEMP_MAX)); + data->alarms = + lm77_read_value(client, LM77_REG_TEMP) & 0x0007; + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm77_init(void) +{ + return i2c_add_driver(&lm77_driver); +} + +static void __exit sensors_lm77_exit(void) +{ + i2c_del_driver(&lm77_driver); +} + +MODULE_AUTHOR("Andras BALI "); +MODULE_DESCRIPTION("LM77 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm77_init); +module_exit(sensors_lm77_exit); diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c new file mode 100644 index 00000000000..29241469dcb --- /dev/null +++ b/drivers/hwmon/lm78.c @@ -0,0 +1,795 @@ +/* + lm78.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, + 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_3(lm78, lm78j, lm79); + +/* Many LM78 constants specified below */ + +/* Length of ISA address segment */ +#define LM78_EXTENT 8 + +/* Where are the ISA address/data registers relative to the base address */ +#define LM78_ADDR_REG_OFFSET 5 +#define LM78_DATA_REG_OFFSET 6 + +/* The LM78 registers */ +#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define LM78_REG_IN(nr) (0x20 + (nr)) + +#define LM78_REG_FAN_MIN(nr) (0x3b + (nr)) +#define LM78_REG_FAN(nr) (0x28 + (nr)) + +#define LM78_REG_TEMP 0x27 +#define LM78_REG_TEMP_OVER 0x39 +#define LM78_REG_TEMP_HYST 0x3a + +#define LM78_REG_ALARM1 0x41 +#define LM78_REG_ALARM2 0x42 + +#define LM78_REG_VID_FANDIV 0x47 + +#define LM78_REG_CONFIG 0x40 +#define LM78_REG_CHIPID 0x49 +#define LM78_REG_I2C_ADDR 0x48 + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. */ + +/* IN: mV, (0V to 4.08V) + REG: 16mV/bit */ +static inline u8 IN_TO_REG(unsigned long val) +{ + unsigned long nval = SENSORS_LIMIT(val, 0, 4080); + return (nval + 8) / 16; +} +#define IN_FROM_REG(val) ((val) * 16) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm <= 0) + return 255; + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +static inline int FAN_FROM_REG(u8 val, int div) +{ + return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); +} + +/* TEMP: mC (-128C to +127C) + REG: 1C/bit, two's complement */ +static inline s8 TEMP_TO_REG(int val) +{ + int nval = SENSORS_LIMIT(val, -128000, 127000) ; + return nval<0 ? (nval-500)/1000 : (nval+500)/1000; +} + +static inline int TEMP_FROM_REG(s8 val) +{ + return val * 1000; +} + +/* VID: mV + REG: (see doc/vid) */ +static inline int VID_FROM_REG(u8 val) +{ + return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50; +} + +#define DIV_FROM_REG(val) (1 << (val)) + +/* There are some complications in a module like this. First off, LM78 chips + may be both present on the SMBus and the ISA bus, and we have to handle + those cases separately at some places. Second, there might be several + LM78 chips available (well, actually, that is probably never done; but + it is a clean illustration of how to handle a case like that). Finally, + a specific chip may be attached to *both* ISA and SMBus, and we would + not like to detect it double. Fortunately, in the case of the LM78 at + least, a register tells us what SMBus address we are on, so that helps + a bit - except if there could be more than one SMBus. Groan. No solution + for this yet. */ + +/* This module may seem overly long and complicated. In fact, it is not so + bad. Quite a lot of bookkeeping is done. A real driver can often cut + some corners. */ + +/* For each registered LM78, we need to keep some data in memory. That + data is pointed to by lm78_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new lm78 client is + allocated. */ +struct lm78_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[7]; /* Register value */ + u8 in_max[7]; /* Register value */ + u8 in_min[7]; /* Register value */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + s8 temp; /* Register value */ + s8 temp_over; /* Register value */ + s8 temp_hyst; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ + u8 vid; /* Register encoding, combined */ + u16 alarms; /* Register encoding, combined */ +}; + + +static int lm78_attach_adapter(struct i2c_adapter *adapter); +static int lm78_detect(struct i2c_adapter *adapter, int address, int kind); +static int lm78_detach_client(struct i2c_client *client); + +static int lm78_read_value(struct i2c_client *client, u8 register); +static int lm78_write_value(struct i2c_client *client, u8 register, u8 value); +static struct lm78_data *lm78_update_device(struct device *dev); +static void lm78_init_client(struct i2c_client *client); + + +static struct i2c_driver lm78_driver = { + .owner = THIS_MODULE, + .name = "lm78", + .id = I2C_DRIVERID_LM78, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm78_attach_adapter, + .detach_client = lm78_detach_client, +}; + +/* 7 Voltages */ +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val); + lm78_write_value(client, LM78_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val); + lm78_write_value(client, LM78_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define show_in_offset(offset) \ +static ssize_t \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in##offset, NULL); \ +static ssize_t \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); +show_in_offset(5); +show_in_offset(6); + +/* Temperature */ +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); +} + +static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); +} + +static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_over = TEMP_TO_REG(val); + lm78_write_value(client, LM78_REG_TEMP_OVER, data->temp_over); + up(&data->update_lock); + return count; +} + +static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); +} + +static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_hyst = TEMP_TO_REG(val); + lm78_write_value(client, LM78_REG_TEMP_HYST, data->temp_hyst); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, + show_temp_over, set_temp_over); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, + show_temp_hyst, set_temp_hyst); + +/* 3 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long min; + u8 reg; + + down(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not " + "supported. Choose one of 1, 2, 4 or 8!\n", val); + up(&data->update_lock); + return -EINVAL; + } + + reg = lm78_read_value(client, LM78_REG_VID_FANDIV); + switch (nr) { + case 0: + reg = (reg & 0xcf) | (data->fan_div[nr] << 4); + break; + case 1: + reg = (reg & 0x3f) | (data->fan_div[nr] << 6); + break; + } + lm78_write_value(client, LM78_REG_VID_FANDIV, reg); + + data->fan_min[nr] = + FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); + +static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 0) ; +} + +static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 1) ; +} + +show_fan_offset(1); +show_fan_offset(2); +show_fan_offset(3); + +/* Fan 3 divisor is locked in H/W */ +static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, + show_fan_1_div, set_fan_1_div); +static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, + show_fan_2_div, set_fan_2_div); +static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL); + +/* VID */ +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%d\n", VID_FROM_REG(data->vid)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* This function is called when: + * lm78_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and lm78_driver is still present) */ +static int lm78_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm78_detect); +} + +/* This function is called by i2c_detect */ +int lm78_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i, err; + struct i2c_client *new_client; + struct lm78_data *data; + const char *client_name = ""; + int is_isa = i2c_is_isa_adapter(adapter); + + if (!is_isa && + !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + err = -ENODEV; + goto ERROR0; + } + + /* Reserve the ISA region */ + if (is_isa) + if (!request_region(address, LM78_EXTENT, lm78_driver.name)) { + err = -EBUSY; + goto ERROR0; + } + + /* Probe whether there is anything available on this address. Already + done for SMBus clients */ + if (kind < 0) { + if (is_isa) { + +#define REALLY_SLOW_IO + /* We need the timeouts for at least some LM78-like + chips. But only if we read 'undefined' registers. */ + i = inb_p(address + 1); + if (inb_p(address + 2) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 3) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 7) != i) { + err = -ENODEV; + goto ERROR1; + } +#undef REALLY_SLOW_IO + + /* Let's just hope nothing breaks here */ + i = inb_p(address + 5) & 0x7f; + outb_p(~i & 0x7f, address + 5); + if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { + outb_p(i, address + 5); + err = -ENODEV; + goto ERROR1; + } + } + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm78_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct lm78_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR1; + } + memset(data, 0, sizeof(struct lm78_data)); + + new_client = &data->client; + if (is_isa) + init_MUTEX(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm78_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + if (kind < 0) { + if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80) { + err = -ENODEV; + goto ERROR2; + } + if (!is_isa && (lm78_read_value( + new_client, LM78_REG_I2C_ADDR) != address)) { + err = -ENODEV; + goto ERROR2; + } + } + + /* Determine the chip type. */ + if (kind <= 0) { + i = lm78_read_value(new_client, LM78_REG_CHIPID); + if (i == 0x00 || i == 0x20) + kind = lm78; + else if (i == 0x40) + kind = lm78j; + else if ((i & 0xfe) == 0xc0) + kind = lm79; + else { + if (kind == 0) + dev_warn(&adapter->dev, "Ignoring 'force' " + "parameter for unknown chip at " + "adapter %d, address 0x%02x\n", + i2c_adapter_id(adapter), address); + err = -ENODEV; + goto ERROR2; + } + } + + if (kind == lm78) { + client_name = "lm78"; + } else if (kind == lm78j) { + client_name = "lm78-j"; + } else if (kind == lm79) { + client_name = "lm79"; + } + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + data->type = kind; + + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR2; + + /* Initialize the LM78 chip */ + lm78_init_client(new_client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 3; i++) { + data->fan_min[i] = lm78_read_value(new_client, + LM78_REG_FAN_MIN(i)); + } + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_in6_input); + device_create_file(&new_client->dev, &dev_attr_in6_min); + device_create_file(&new_client->dev, &dev_attr_in6_max); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_fan3_input); + device_create_file(&new_client->dev, &dev_attr_fan3_min); + device_create_file(&new_client->dev, &dev_attr_fan3_div); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + + return 0; + +ERROR2: + kfree(data); +ERROR1: + if (is_isa) + release_region(address, LM78_EXTENT); +ERROR0: + return err; +} + +static int lm78_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + if(i2c_is_isa_client(client)) + release_region(client->addr, LM78_EXTENT); + + kfree(i2c_get_clientdata(client)); + + return 0; +} + +/* The SMBus locks itself, but ISA access must be locked explicitly! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, + would slow down the LM78 access and should not be necessary. */ +static int lm78_read_value(struct i2c_client *client, u8 reg) +{ + int res; + if (i2c_is_isa_client(client)) { + struct lm78_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); + res = inb_p(client->addr + LM78_DATA_REG_OFFSET); + up(&data->lock); + return res; + } else + return i2c_smbus_read_byte_data(client, reg); +} + +/* The SMBus locks itself, but ISA access muse be locked explicitly! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, + would slow down the LM78 access and should not be necessary. + There are some ugly typecasts here, but the good new is - they should + nowhere else be necessary! */ +static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + if (i2c_is_isa_client(client)) { + struct lm78_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); + outb_p(value, client->addr + LM78_DATA_REG_OFFSET); + up(&data->lock); + return 0; + } else + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* Called when we have found a new LM78. It should set limits, etc. */ +static void lm78_init_client(struct i2c_client *client) +{ + u8 config = lm78_read_value(client, LM78_REG_CONFIG); + + /* Start monitoring */ + if (!(config & 0x01)) + lm78_write_value(client, LM78_REG_CONFIG, + (config & 0xf7) | 0x01); +} + +static struct lm78_data *lm78_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + dev_dbg(&client->dev, "Starting lm78 update\n"); + + for (i = 0; i <= 6; i++) { + data->in[i] = + lm78_read_value(client, LM78_REG_IN(i)); + data->in_min[i] = + lm78_read_value(client, LM78_REG_IN_MIN(i)); + data->in_max[i] = + lm78_read_value(client, LM78_REG_IN_MAX(i)); + } + for (i = 0; i < 3; i++) { + data->fan[i] = + lm78_read_value(client, LM78_REG_FAN(i)); + data->fan_min[i] = + lm78_read_value(client, LM78_REG_FAN_MIN(i)); + } + data->temp = lm78_read_value(client, LM78_REG_TEMP); + data->temp_over = + lm78_read_value(client, LM78_REG_TEMP_OVER); + data->temp_hyst = + lm78_read_value(client, LM78_REG_TEMP_HYST); + i = lm78_read_value(client, LM78_REG_VID_FANDIV); + data->vid = i & 0x0f; + if (data->type == lm79) + data->vid |= + (lm78_read_value(client, LM78_REG_CHIPID) & + 0x01) << 4; + else + data->vid |= 0x10; + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = lm78_read_value(client, LM78_REG_ALARM1) + + (lm78_read_value(client, LM78_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + + data->fan_div[2] = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sm_lm78_init(void) +{ + return i2c_add_driver(&lm78_driver); +} + +static void __exit sm_lm78_exit(void) +{ + i2c_del_driver(&lm78_driver); +} + + + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver"); +MODULE_LICENSE("GPL"); + +module_init(sm_lm78_init); +module_exit(sm_lm78_exit); diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c new file mode 100644 index 00000000000..8100595feb4 --- /dev/null +++ b/drivers/hwmon/lm80.c @@ -0,0 +1,601 @@ +/* + * lm80.c - From lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 1998, 1999 Frodo Looijaard + * and Philip Edelbrock + * + * Ported to Linux 2.6 by Tiago Sousa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, + 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(lm80); + +/* Many LM80 constants specified below */ + +/* The LM80 registers */ +#define LM80_REG_IN_MAX(nr) (0x2a + (nr) * 2) +#define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2) +#define LM80_REG_IN(nr) (0x20 + (nr)) + +#define LM80_REG_FAN1 0x28 +#define LM80_REG_FAN2 0x29 +#define LM80_REG_FAN_MIN(nr) (0x3b + (nr)) + +#define LM80_REG_TEMP 0x27 +#define LM80_REG_TEMP_HOT_MAX 0x38 +#define LM80_REG_TEMP_HOT_HYST 0x39 +#define LM80_REG_TEMP_OS_MAX 0x3a +#define LM80_REG_TEMP_OS_HYST 0x3b + +#define LM80_REG_CONFIG 0x00 +#define LM80_REG_ALARM1 0x01 +#define LM80_REG_ALARM2 0x02 +#define LM80_REG_MASK1 0x03 +#define LM80_REG_MASK2 0x04 +#define LM80_REG_FANDIV 0x05 +#define LM80_REG_RES 0x06 + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ + +#define IN_TO_REG(val) (SENSORS_LIMIT(((val)+5)/10,0,255)) +#define IN_FROM_REG(val) ((val)*10) + +static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm*div / 2) / (rpm*div), 1, 254); +} + +#define FAN_FROM_REG(val,div) ((val)==0?-1:\ + (val)==255?0:1350000/((div)*(val))) + +static inline long TEMP_FROM_REG(u16 temp) +{ + long res; + + temp >>= 4; + if (temp < 0x0800) + res = 625 * (long) temp; + else + res = ((long) temp - 0x01000) * 625; + + return res / 10; +} + +#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) + +#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val)<0?\ + ((val)-500)/1000:((val)+500)/1000,0,255) + +#define DIV_FROM_REG(val) (1 << (val)) + +/* + * Client data (each client gets its own) + */ + +struct lm80_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[7]; /* Register value */ + u8 in_max[7]; /* Register value */ + u8 in_min[7]; /* Register value */ + u8 fan[2]; /* Register value */ + u8 fan_min[2]; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u16 temp; /* Register values, shifted right */ + u8 temp_hot_max; /* Register value */ + u8 temp_hot_hyst; /* Register value */ + u8 temp_os_max; /* Register value */ + u8 temp_os_hyst; /* Register value */ + u16 alarms; /* Register encoding, combined */ +}; + +/* + * Functions declaration + */ + +static int lm80_attach_adapter(struct i2c_adapter *adapter); +static int lm80_detect(struct i2c_adapter *adapter, int address, int kind); +static void lm80_init_client(struct i2c_client *client); +static int lm80_detach_client(struct i2c_client *client); +static struct lm80_data *lm80_update_device(struct device *dev); +static int lm80_read_value(struct i2c_client *client, u8 reg); +static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver lm80_driver = { + .owner = THIS_MODULE, + .name = "lm80", + .id = I2C_DRIVERID_LM80, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm80_attach_adapter, + .detach_client = lm80_detach_client, +}; + +/* + * Sysfs stuff + */ + +#define show_in(suffix, value) \ +static ssize_t show_in_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm80_data *data = lm80_update_device(dev); \ + return sprintf(buf, "%d\n", IN_FROM_REG(data->value)); \ +} +show_in(min0, in_min[0]); +show_in(min1, in_min[1]); +show_in(min2, in_min[2]); +show_in(min3, in_min[3]); +show_in(min4, in_min[4]); +show_in(min5, in_min[5]); +show_in(min6, in_min[6]); +show_in(max0, in_max[0]); +show_in(max1, in_max[1]); +show_in(max2, in_max[2]); +show_in(max3, in_max[3]); +show_in(max4, in_max[4]); +show_in(max5, in_max[5]); +show_in(max6, in_max[6]); +show_in(input0, in[0]); +show_in(input1, in[1]); +show_in(input2, in[2]); +show_in(input3, in[3]); +show_in(input4, in[4]); +show_in(input5, in[5]); +show_in(input6, in[6]); + +#define set_in(suffix, value, reg) \ +static ssize_t set_in_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm80_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock);\ + data->value = IN_TO_REG(val); \ + lm80_write_value(client, reg, data->value); \ + up(&data->update_lock);\ + return count; \ +} +set_in(min0, in_min[0], LM80_REG_IN_MIN(0)); +set_in(min1, in_min[1], LM80_REG_IN_MIN(1)); +set_in(min2, in_min[2], LM80_REG_IN_MIN(2)); +set_in(min3, in_min[3], LM80_REG_IN_MIN(3)); +set_in(min4, in_min[4], LM80_REG_IN_MIN(4)); +set_in(min5, in_min[5], LM80_REG_IN_MIN(5)); +set_in(min6, in_min[6], LM80_REG_IN_MIN(6)); +set_in(max0, in_max[0], LM80_REG_IN_MAX(0)); +set_in(max1, in_max[1], LM80_REG_IN_MAX(1)); +set_in(max2, in_max[2], LM80_REG_IN_MAX(2)); +set_in(max3, in_max[3], LM80_REG_IN_MAX(3)); +set_in(max4, in_max[4], LM80_REG_IN_MAX(4)); +set_in(max5, in_max[5], LM80_REG_IN_MAX(5)); +set_in(max6, in_max[6], LM80_REG_IN_MAX(6)); + +#define show_fan(suffix, value, div) \ +static ssize_t show_fan_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm80_data *data = lm80_update_device(dev); \ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->value, \ + DIV_FROM_REG(data->div))); \ +} +show_fan(min1, fan_min[0], fan_div[0]); +show_fan(min2, fan_min[1], fan_div[1]); +show_fan(input1, fan[0], fan_div[0]); +show_fan(input2, fan[1], fan_div[1]); + +#define show_fan_div(suffix, value) \ +static ssize_t show_fan_div##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm80_data *data = lm80_update_device(dev); \ + return sprintf(buf, "%d\n", DIV_FROM_REG(data->value)); \ +} +show_fan_div(1, fan_div[0]); +show_fan_div(2, fan_div[1]); + +#define set_fan(suffix, value, reg, div) \ +static ssize_t set_fan_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm80_data *data = i2c_get_clientdata(client); \ + long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock);\ + data->value = FAN_TO_REG(val, DIV_FROM_REG(data->div)); \ + lm80_write_value(client, reg, data->value); \ + up(&data->update_lock);\ + return count; \ +} +set_fan(min1, fan_min[0], LM80_REG_FAN_MIN(1), fan_div[0]); +set_fan(min2, fan_min[1], LM80_REG_FAN_MIN(2), fan_div[1]); + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm80_data *data = i2c_get_clientdata(client); + unsigned long min, val = simple_strtoul(buf, NULL, 10); + u8 reg; + + /* Save fan_min */ + down(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not " + "supported. Choose one of 1, 2, 4 or 8!\n", val); + up(&data->update_lock); + return -EINVAL; + } + + reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1)))) + | (data->fan_div[nr] << (2 * (nr + 1))); + lm80_write_value(client, LM80_REG_FANDIV, reg); + + /* Restore fan_min */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); + up(&data->update_lock); + + return count; +} + +#define set_fan_div(number) \ +static ssize_t set_fan_div##number(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_fan_div(dev, buf, count, number - 1); \ +} +set_fan_div(1); +set_fan_div(2); + +static ssize_t show_temp_input1(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm80_data *data = lm80_update_device(dev); + return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp)); +} + +#define show_temp(suffix, value) \ +static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm80_data *data = lm80_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \ +} +show_temp(hot_max, temp_hot_max); +show_temp(hot_hyst, temp_hot_hyst); +show_temp(os_max, temp_os_max); +show_temp(os_hyst, temp_os_hyst); + +#define set_temp(suffix, value, reg) \ +static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm80_data *data = i2c_get_clientdata(client); \ + long val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_LIMIT_TO_REG(val); \ + lm80_write_value(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} +set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX); +set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST); +set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX); +set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm80_data *data = lm80_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} + +static DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min0, set_in_min0); +static DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min1, set_in_min1); +static DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min2, set_in_min2); +static DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min3, set_in_min3); +static DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min4, set_in_min4); +static DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min5, set_in_min5); +static DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min6, set_in_min6); +static DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max0, set_in_max0); +static DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max1, set_in_max1); +static DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max2, set_in_max2); +static DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max3, set_in_max3); +static DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max4, set_in_max4); +static DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max5, set_in_max5); +static DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max6, set_in_max6); +static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL); +static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL); +static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL); +static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL); +static DEVICE_ATTR(in4_input, S_IRUGO, show_in_input4, NULL); +static DEVICE_ATTR(in5_input, S_IRUGO, show_in_input5, NULL); +static DEVICE_ATTR(in6_input, S_IRUGO, show_in_input6, NULL); +static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min1, + set_fan_min1); +static DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min2, + set_fan_min2); +static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); +static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); +static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div1, set_fan_div1); +static DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div2, set_fan_div2); +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max, + set_temp_hot_max); +static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst, + set_temp_hot_hyst); +static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max, + set_temp_os_max); +static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst, + set_temp_os_hyst); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* + * Real code + */ + +static int lm80_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm80_detect); +} + +int lm80_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i, cur; + struct i2c_client *new_client; + struct lm80_data *data; + int err = 0; + const char *name; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm80_{read,write}_value. */ + if (!(data = kmalloc(sizeof(struct lm80_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm80_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm80_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. It is lousy. */ + if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0) + goto error_free; + for (i = 0x2a; i <= 0x3d; i++) { + cur = i2c_smbus_read_byte_data(new_client, i); + if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur) + || (i2c_smbus_read_byte_data(new_client, i + 0x80) != cur) + || (i2c_smbus_read_byte_data(new_client, i + 0xc0) != cur)) + goto error_free; + } + + /* Determine the chip type - only one kind supported! */ + kind = lm80; + name = "lm80"; + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto error_free; + + /* Initialize the LM80 chip */ + lm80_init_client(new_client); + + /* A few vars need to be filled upon startup */ + data->fan_min[0] = lm80_read_value(new_client, LM80_REG_FAN_MIN(1)); + data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2)); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in6_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_in6_max); + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in6_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +error_free: + kfree(data); +exit: + return err; +} + +static int lm80_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static int lm80_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* Called when we have found a new LM80. */ +static void lm80_init_client(struct i2c_client *client) +{ + /* Reset all except Watchdog values and last conversion values + This sets fan-divs to 2, among others. This makes most other + initializations unnecessary */ + lm80_write_value(client, LM80_REG_CONFIG, 0x80); + /* Set 11-bit temperature resolution */ + lm80_write_value(client, LM80_REG_RES, 0x08); + + /* Start monitoring */ + lm80_write_value(client, LM80_REG_CONFIG, 0x01); +} + +static struct lm80_data *lm80_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm80_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + dev_dbg(&client->dev, "Starting lm80 update\n"); + for (i = 0; i <= 6; i++) { + data->in[i] = + lm80_read_value(client, LM80_REG_IN(i)); + data->in_min[i] = + lm80_read_value(client, LM80_REG_IN_MIN(i)); + data->in_max[i] = + lm80_read_value(client, LM80_REG_IN_MAX(i)); + } + data->fan[0] = lm80_read_value(client, LM80_REG_FAN1); + data->fan_min[0] = + lm80_read_value(client, LM80_REG_FAN_MIN(1)); + data->fan[1] = lm80_read_value(client, LM80_REG_FAN2); + data->fan_min[1] = + lm80_read_value(client, LM80_REG_FAN_MIN(2)); + + data->temp = + (lm80_read_value(client, LM80_REG_TEMP) << 8) | + (lm80_read_value(client, LM80_REG_RES) & 0xf0); + data->temp_os_max = + lm80_read_value(client, LM80_REG_TEMP_OS_MAX); + data->temp_os_hyst = + lm80_read_value(client, LM80_REG_TEMP_OS_HYST); + data->temp_hot_max = + lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); + data->temp_hot_hyst = + lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); + + i = lm80_read_value(client, LM80_REG_FANDIV); + data->fan_div[0] = (i >> 2) & 0x03; + data->fan_div[1] = (i >> 4) & 0x03; + data->alarms = lm80_read_value(client, LM80_REG_ALARM1) + + (lm80_read_value(client, LM80_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm80_init(void) +{ + return i2c_add_driver(&lm80_driver); +} + +static void __exit sensors_lm80_exit(void) +{ + i2c_del_driver(&lm80_driver); +} + +MODULE_AUTHOR("Frodo Looijaard and " + "Philip Edelbrock "); +MODULE_DESCRIPTION("LM80 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm80_init); +module_exit(sensors_lm80_exit); diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c new file mode 100644 index 00000000000..a49008b444c --- /dev/null +++ b/drivers/hwmon/lm83.c @@ -0,0 +1,408 @@ +/* + * lm83.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2003-2005 Jean Delvare + * + * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is + * a sensor chip made by National Semiconductor. It reports up to four + * temperatures (its own plus up to three external ones) with a 1 deg + * resolution and a 3-4 deg accuracy. Complete datasheet can be obtained + * from National's website at: + * http://www.national.com/pf/LM/LM83.html + * Since the datasheet omits to give the chip stepping code, I give it + * here: 0x03 (at register 0xff). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan + * Address is selected using 2 three-level pins, resulting in 9 possible + * addresses. + */ + +static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, + 0x29, 0x2a, 0x2b, + 0x4c, 0x4d, 0x4e, + I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(lm83); + +/* + * The LM83 registers + * Manufacturer ID is 0x01 for National Semiconductor. + */ + +#define LM83_REG_R_MAN_ID 0xFE +#define LM83_REG_R_CHIP_ID 0xFF +#define LM83_REG_R_CONFIG 0x03 +#define LM83_REG_W_CONFIG 0x09 +#define LM83_REG_R_STATUS1 0x02 +#define LM83_REG_R_STATUS2 0x35 +#define LM83_REG_R_LOCAL_TEMP 0x00 +#define LM83_REG_R_LOCAL_HIGH 0x05 +#define LM83_REG_W_LOCAL_HIGH 0x0B +#define LM83_REG_R_REMOTE1_TEMP 0x30 +#define LM83_REG_R_REMOTE1_HIGH 0x38 +#define LM83_REG_W_REMOTE1_HIGH 0x50 +#define LM83_REG_R_REMOTE2_TEMP 0x01 +#define LM83_REG_R_REMOTE2_HIGH 0x07 +#define LM83_REG_W_REMOTE2_HIGH 0x0D +#define LM83_REG_R_REMOTE3_TEMP 0x31 +#define LM83_REG_R_REMOTE3_HIGH 0x3A +#define LM83_REG_W_REMOTE3_HIGH 0x52 +#define LM83_REG_R_TCRIT 0x42 +#define LM83_REG_W_TCRIT 0x5A + +/* + * Conversions and various macros + * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius. + */ + +#define TEMP_FROM_REG(val) ((val) * 1000) +#define TEMP_TO_REG(val) ((val) <= -128000 ? -128 : \ + (val) >= 127000 ? 127 : \ + (val) < 0 ? ((val) - 500) / 1000 : \ + ((val) + 500) / 1000) + +static const u8 LM83_REG_R_TEMP[] = { + LM83_REG_R_LOCAL_TEMP, + LM83_REG_R_REMOTE1_TEMP, + LM83_REG_R_REMOTE2_TEMP, + LM83_REG_R_REMOTE3_TEMP, + LM83_REG_R_LOCAL_HIGH, + LM83_REG_R_REMOTE1_HIGH, + LM83_REG_R_REMOTE2_HIGH, + LM83_REG_R_REMOTE3_HIGH, + LM83_REG_R_TCRIT, +}; + +static const u8 LM83_REG_W_HIGH[] = { + LM83_REG_W_LOCAL_HIGH, + LM83_REG_W_REMOTE1_HIGH, + LM83_REG_W_REMOTE2_HIGH, + LM83_REG_W_REMOTE3_HIGH, + LM83_REG_W_TCRIT, +}; + +/* + * Functions declaration + */ + +static int lm83_attach_adapter(struct i2c_adapter *adapter); +static int lm83_detect(struct i2c_adapter *adapter, int address, int kind); +static int lm83_detach_client(struct i2c_client *client); +static struct lm83_data *lm83_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver lm83_driver = { + .owner = THIS_MODULE, + .name = "lm83", + .id = I2C_DRIVERID_LM83, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm83_attach_adapter, + .detach_client = lm83_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct lm83_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + s8 temp[9]; /* 0..3: input 1-4, + 4..7: high limit 1-4, + 8 : critical limit */ + u16 alarms; /* bitvector, combined */ +}; + +/* + * Sysfs stuff + */ + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm83_data *data = lm83_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); +} + +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm83_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + data->temp[nr] = TEMP_TO_REG(val); + i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4], + data->temp[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm83_data *data = lm83_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 4); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 5); +static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 6); +static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, 7); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp, + set_temp, 8); +static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* + * Real code + */ + +static int lm83_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm83_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm83_data *data; + int err = 0; + const char *name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct lm83_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm83_data)); + + /* The common I2C client data is placed right after the + * LM83-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm83_driver; + new_client->flags = 0; + + /* Now we do the detection and identification. A negative kind + * means that the driver was loaded with no force parameter + * (default), so we must both detect and identify the chip + * (actually there is only one possible kind of chip for now, LM83). + * A zero kind means that the driver was loaded with the force + * parameter, the detection step shall be skipped. A positive kind + * means that the driver was loaded with the force parameter and a + * given kind of chip is requested, so both the detection and the + * identification steps are skipped. */ + + /* Default to an LM83 if forced */ + if (kind == 0) + kind = lm83; + + if (kind < 0) { /* detection */ + if (((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1) + & 0xA8) != 0x00) || + ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS2) + & 0x48) != 0x00) || + ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG) + & 0x41) != 0x00)) { + dev_dbg(&adapter->dev, + "LM83 detection failed at 0x%02x.\n", address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + u8 man_id, chip_id; + + man_id = i2c_smbus_read_byte_data(new_client, + LM83_REG_R_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + LM83_REG_R_CHIP_ID); + + if (man_id == 0x01) { /* National Semiconductor */ + if (chip_id == 0x03) { + kind = lm83; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%02X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + } + + if (kind == lm83) { + name = "lm83"; + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* + * Initialize the LM83 chip + * (Nothing to do for this one.) + */ + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_crit.dev_attr); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int lm83_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static struct lm83_data *lm83_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm83_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + int nr; + + dev_dbg(&client->dev, "Updating lm83 data.\n"); + for (nr = 0; nr < 9; nr++) { + data->temp[nr] = + i2c_smbus_read_byte_data(client, + LM83_REG_R_TEMP[nr]); + } + data->alarms = + i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) + + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) + << 8); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm83_init(void) +{ + return i2c_add_driver(&lm83_driver); +} + +static void __exit sensors_lm83_exit(void) +{ + i2c_del_driver(&lm83_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("LM83 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm83_init); +module_exit(sensors_lm83_exit); diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c new file mode 100644 index 00000000000..b4d7fd41826 --- /dev/null +++ b/drivers/hwmon/lm85.c @@ -0,0 +1,1575 @@ +/* + lm85.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + Copyright (c) 2002, 2003 Philip Pokorny + Copyright (c) 2003 Margit Schubert-While + Copyright (c) 2004 Justin Thiessen + + Chip details at + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); + +/* The LM85 registers */ + +#define LM85_REG_IN(nr) (0x20 + (nr)) +#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2) +#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2) + +#define LM85_REG_TEMP(nr) (0x25 + (nr)) +#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2) +#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2) + +/* Fan speeds are LSB, MSB (2 bytes) */ +#define LM85_REG_FAN(nr) (0x28 + (nr) *2) +#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) *2) + +#define LM85_REG_PWM(nr) (0x30 + (nr)) + +#define ADT7463_REG_OPPOINT(nr) (0x33 + (nr)) + +#define ADT7463_REG_TMIN_CTL1 0x36 +#define ADT7463_REG_TMIN_CTL2 0x37 + +#define LM85_REG_DEVICE 0x3d +#define LM85_REG_COMPANY 0x3e +#define LM85_REG_VERSTEP 0x3f +/* These are the recognized values for the above regs */ +#define LM85_DEVICE_ADX 0x27 +#define LM85_COMPANY_NATIONAL 0x01 +#define LM85_COMPANY_ANALOG_DEV 0x41 +#define LM85_COMPANY_SMSC 0x5c +#define LM85_VERSTEP_VMASK 0xf0 +#define LM85_VERSTEP_GENERIC 0x60 +#define LM85_VERSTEP_LM85C 0x60 +#define LM85_VERSTEP_LM85B 0x62 +#define LM85_VERSTEP_ADM1027 0x60 +#define LM85_VERSTEP_ADT7463 0x62 +#define LM85_VERSTEP_ADT7463C 0x6A +#define LM85_VERSTEP_EMC6D100_A0 0x60 +#define LM85_VERSTEP_EMC6D100_A1 0x61 +#define LM85_VERSTEP_EMC6D102 0x65 + +#define LM85_REG_CONFIG 0x40 + +#define LM85_REG_ALARM1 0x41 +#define LM85_REG_ALARM2 0x42 + +#define LM85_REG_VID 0x43 + +/* Automated FAN control */ +#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr)) +#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr)) +#define LM85_REG_AFAN_SPIKE1 0x62 +#define LM85_REG_AFAN_SPIKE2 0x63 +#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr)) +#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr)) +#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr)) +#define LM85_REG_AFAN_HYST1 0x6d +#define LM85_REG_AFAN_HYST2 0x6e + +#define LM85_REG_TACH_MODE 0x74 +#define LM85_REG_SPINUP_CTL 0x75 + +#define ADM1027_REG_TEMP_OFFSET(nr) (0x70 + (nr)) +#define ADM1027_REG_CONFIG2 0x73 +#define ADM1027_REG_INTMASK1 0x74 +#define ADM1027_REG_INTMASK2 0x75 +#define ADM1027_REG_EXTEND_ADC1 0x76 +#define ADM1027_REG_EXTEND_ADC2 0x77 +#define ADM1027_REG_CONFIG3 0x78 +#define ADM1027_REG_FAN_PPR 0x7b + +#define ADT7463_REG_THERM 0x79 +#define ADT7463_REG_THERM_LIMIT 0x7A + +#define EMC6D100_REG_ALARM3 0x7d +/* IN5, IN6 and IN7 */ +#define EMC6D100_REG_IN(nr) (0x70 + ((nr)-5)) +#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr)-5) * 2) +#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr)-5) * 2) +#define EMC6D102_REG_EXTEND_ADC1 0x85 +#define EMC6D102_REG_EXTEND_ADC2 0x86 +#define EMC6D102_REG_EXTEND_ADC3 0x87 +#define EMC6D102_REG_EXTEND_ADC4 0x88 + +#define LM85_ALARM_IN0 0x0001 +#define LM85_ALARM_IN1 0x0002 +#define LM85_ALARM_IN2 0x0004 +#define LM85_ALARM_IN3 0x0008 +#define LM85_ALARM_TEMP1 0x0010 +#define LM85_ALARM_TEMP2 0x0020 +#define LM85_ALARM_TEMP3 0x0040 +#define LM85_ALARM_ALARM2 0x0080 +#define LM85_ALARM_IN4 0x0100 +#define LM85_ALARM_RESERVED 0x0200 +#define LM85_ALARM_FAN1 0x0400 +#define LM85_ALARM_FAN2 0x0800 +#define LM85_ALARM_FAN3 0x1000 +#define LM85_ALARM_FAN4 0x2000 +#define LM85_ALARM_TEMP1_FAULT 0x4000 +#define LM85_ALARM_TEMP3_FAULT 0x8000 + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + */ + +/* IN are scaled acording to built-in resistors */ +static int lm85_scaling[] = { /* .001 Volts */ + 2500, 2250, 3300, 5000, 12000, + 3300, 1500, 1800 /*EMC6D100*/ + }; +#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) + +#define INS_TO_REG(n,val) \ + SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255) + +#define INSEXT_FROM_REG(n,val,ext,scale) \ + SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n]) + +#define INS_FROM_REG(n,val) INSEXT_FROM_REG(n,val,0,1) + +/* FAN speed is measured using 90kHz clock */ +#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534)) +#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) + +/* Temperature is reported in .001 degC increments */ +#define TEMP_TO_REG(val) \ + SENSORS_LIMIT(SCALE(val,1000,1),-127,127) +#define TEMPEXT_FROM_REG(val,ext,scale) \ + SCALE((val)*scale + (ext),scale,1000) +#define TEMP_FROM_REG(val) \ + TEMPEXT_FROM_REG(val,0,1) + +#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) +#define PWM_FROM_REG(val) (val) + + +/* ZONEs have the following parameters: + * Limit (low) temp, 1. degC + * Hysteresis (below limit), 1. degC (0-15) + * Range of speed control, .1 degC (2-80) + * Critical (high) temp, 1. degC + * + * FAN PWMs have the following parameters: + * Reference Zone, 1, 2, 3, etc. + * Spinup time, .05 sec + * PWM value at limit/low temp, 1 count + * PWM Frequency, 1. Hz + * PWM is Min or OFF below limit, flag + * Invert PWM output, flag + * + * Some chips filter the temp, others the fan. + * Filter constant (or disabled) .1 seconds + */ + +/* These are the zone temperature range encodings in .001 degree C */ +static int lm85_range_map[] = { + 2000, 2500, 3300, 4000, 5000, 6600, + 8000, 10000, 13300, 16000, 20000, 26600, + 32000, 40000, 53300, 80000 + }; +static int RANGE_TO_REG( int range ) +{ + int i; + + if ( range < lm85_range_map[0] ) { + return 0 ; + } else if ( range > lm85_range_map[15] ) { + return 15 ; + } else { /* find closest match */ + for ( i = 14 ; i >= 0 ; --i ) { + if ( range > lm85_range_map[i] ) { /* range bracketed */ + if ((lm85_range_map[i+1] - range) < + (range - lm85_range_map[i])) { + i++; + break; + } + break; + } + } + } + return( i & 0x0f ); +} +#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f]) + +/* These are the Acoustic Enhancement, or Temperature smoothing encodings + * NOTE: The enable/disable bit is INCLUDED in these encodings as the + * MSB (bit 3, value 8). If the enable bit is 0, the encoded value + * is ignored, or set to 0. + */ +/* These are the PWM frequency encodings */ +static int lm85_freq_map[] = { /* .1 Hz */ + 100, 150, 230, 300, 380, 470, 620, 940 + }; +static int FREQ_TO_REG( int freq ) +{ + int i; + + if( freq >= lm85_freq_map[7] ) { return 7 ; } + for( i = 0 ; i < 7 ; ++i ) + if( freq <= lm85_freq_map[i] ) + break ; + return( i & 0x07 ); +} +#define FREQ_FROM_REG(val) (lm85_freq_map[(val)&0x07]) + +/* Since we can't use strings, I'm abusing these numbers + * to stand in for the following meanings: + * 1 -- PWM responds to Zone 1 + * 2 -- PWM responds to Zone 2 + * 3 -- PWM responds to Zone 3 + * 23 -- PWM responds to the higher temp of Zone 2 or 3 + * 123 -- PWM responds to highest of Zone 1, 2, or 3 + * 0 -- PWM is always at 0% (ie, off) + * -1 -- PWM is always at 100% + * -2 -- PWM responds to manual control + */ + +static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 }; +#define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07]) + +static int ZONE_TO_REG( int zone ) +{ + int i; + + for( i = 0 ; i <= 7 ; ++i ) + if( zone == lm85_zone_map[i] ) + break ; + if( i > 7 ) /* Not found. */ + i = 3; /* Always 100% */ + return( (i & 0x07)<<5 ); +} + +#define HYST_TO_REG(val) (SENSORS_LIMIT(((val)+500)/1000,0,15)) +#define HYST_FROM_REG(val) ((val)*1000) + +#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) +#define OFFSET_FROM_REG(val) ((val)*25) + +#define PPR_MASK(fan) (0x03<<(fan *2)) +#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2)) +#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1) + +/* i2c-vid.h defines vid_from_reg() */ +#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm))) + +/* Unlike some other drivers we DO NOT set initial limits. Use + * the config file to set limits. Some users have reported + * motherboards shutting down when we set limits in a previous + * version of the driver. + */ + +/* Chip sampling rates + * + * Some sensors are not updated more frequently than once per second + * so it doesn't make sense to read them more often than that. + * We cache the results and return the saved data if the driver + * is called again before a second has elapsed. + * + * Also, there is significant configuration data for this chip + * given the automatic PWM fan control that is possible. There + * are about 47 bytes of config data to only 22 bytes of actual + * readings. So, we keep the config data up to date in the cache + * when it is written and only sample it once every 1 *minute* + */ +#define LM85_DATA_INTERVAL (HZ + HZ / 2) +#define LM85_CONFIG_INTERVAL (1 * 60 * HZ) + +/* For each registered LM85, we need to keep some data in memory. That + data is pointed to by lm85_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new lm85 client is + allocated. */ + +/* LM85 can automatically adjust fan speeds based on temperature + * This structure encapsulates an entire Zone config. There are + * three zones (one for each temperature input) on the lm85 + */ +struct lm85_zone { + s8 limit; /* Low temp limit */ + u8 hyst; /* Low limit hysteresis. (0-15) */ + u8 range; /* Temp range, encoded */ + s8 critical; /* "All fans ON" temp limit */ + u8 off_desired; /* Actual "off" temperature specified. Preserved + * to prevent "drift" as other autofan control + * values change. + */ + u8 max_desired; /* Actual "max" temperature specified. Preserved + * to prevent "drift" as other autofan control + * values change. + */ +}; + +struct lm85_autofan { + u8 config; /* Register value */ + u8 freq; /* PWM frequency, encoded */ + u8 min_pwm; /* Minimum PWM value, encoded */ + u8 min_off; /* Min PWM or OFF below "limit", flag */ +}; + +struct lm85_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + int valid; /* !=0 if following fields are valid */ + unsigned long last_reading; /* In jiffies */ + unsigned long last_config; /* In jiffies */ + + u8 in[8]; /* Register value */ + u8 in_max[8]; /* Register value */ + u8 in_min[8]; /* Register value */ + s8 temp[3]; /* Register value */ + s8 temp_min[3]; /* Register value */ + s8 temp_max[3]; /* Register value */ + s8 temp_offset[3]; /* Register value */ + u16 fan[4]; /* Register value */ + u16 fan_min[4]; /* Register value */ + u8 pwm[3]; /* Register value */ + u8 spinup_ctl; /* Register encoding, combined */ + u8 tach_mode; /* Register encoding, combined */ + u8 temp_ext[3]; /* Decoded values */ + u8 in_ext[8]; /* Decoded values */ + u8 adc_scale; /* ADC Extended bits scaling factor */ + u8 fan_ppr; /* Register value */ + u8 smooth[3]; /* Register encoding */ + u8 vid; /* Register value */ + u8 vrm; /* VRM version */ + u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */ + u8 oppoint[3]; /* Register value */ + u16 tmin_ctl; /* Register value */ + unsigned long therm_total; /* Cummulative therm count */ + u8 therm_limit; /* Register value */ + u32 alarms; /* Register encoding, combined */ + struct lm85_autofan autofan[3]; + struct lm85_zone zone[3]; +}; + +static int lm85_attach_adapter(struct i2c_adapter *adapter); +static int lm85_detect(struct i2c_adapter *adapter, int address, + int kind); +static int lm85_detach_client(struct i2c_client *client); + +static int lm85_read_value(struct i2c_client *client, u8 register); +static int lm85_write_value(struct i2c_client *client, u8 register, int value); +static struct lm85_data *lm85_update_device(struct device *dev); +static void lm85_init_client(struct i2c_client *client); + + +static struct i2c_driver lm85_driver = { + .owner = THIS_MODULE, + .name = "lm85", + .id = I2C_DRIVERID_LM85, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm85_attach_adapter, + .detach_client = lm85_detach_client, +}; + + +/* 4 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) ); +} +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) ); +} +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val); + lm85_write_value(client, LM85_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ + NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); + +show_fan_offset(1); +show_fan_offset(2); +show_fan_offset(3); +show_fan_offset(4); + +/* vid, vrm, alarms */ + +static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); +} + +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); + +static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->vrm); +} + +static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + return count; +} + +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); + +static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); + +/* pwm */ + +static ssize_t show_pwm(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) ); +} +static ssize_t set_pwm(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->pwm[nr] = PWM_TO_REG(val); + lm85_write_value(client, LM85_REG_PWM(nr), data->pwm[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + int pwm_zone; + + pwm_zone = ZONE_FROM_REG(data->autofan[nr].config); + return sprintf(buf,"%d\n", (pwm_zone != 0 && pwm_zone != -1) ); +} + +#define show_pwm_reg(offset) \ +static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwm(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_pwm_enable##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwm_enable(dev, buf, offset - 1); \ +} \ +static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_pwm_##offset, set_pwm_##offset); \ +static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \ + show_pwm_enable##offset, NULL); + +show_pwm_reg(1); +show_pwm_reg(2); +show_pwm_reg(3); + +/* Voltages */ + +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf( buf, "%d\n", INSEXT_FROM_REG(nr, + data->in[nr], + data->in_ext[nr], + data->adc_scale) ); +} +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) ); +} +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = INS_TO_REG(nr, val); + lm85_write_value(client, LM85_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) ); +} +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = INS_TO_REG(nr, val); + lm85_write_value(client, LM85_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); + return count; +} +#define show_in_reg(offset) \ +static ssize_t show_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static ssize_t show_in_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t show_in_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t set_in_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t set_in_##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, \ + NULL); \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_##offset##_min, set_in_##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_##offset##_max, set_in_##offset##_max); + +show_in_reg(0); +show_in_reg(1); +show_in_reg(2); +show_in_reg(3); +show_in_reg(4); + +/* Temps */ + +static ssize_t show_temp(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr], + data->temp_ext[nr], + data->adc_scale) ); +} +static ssize_t show_temp_min(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) ); +} +static ssize_t set_temp_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_min[nr] = TEMP_TO_REG(val); + lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t show_temp_max(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) ); +} +static ssize_t set_temp_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_max[nr] = TEMP_TO_REG(val); + lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]); + up(&data->update_lock); + return count; +} +#define show_temp_reg(offset) \ +static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, offset - 1); \ +} \ +static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_max(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_max(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ + NULL); \ +static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_min, set_temp_##offset##_min); \ +static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_max, set_temp_##offset##_max); + +show_temp_reg(1); +show_temp_reg(2); +show_temp_reg(3); + + +/* Automatic PWM control */ + +static ssize_t show_pwm_auto_channels(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", ZONE_FROM_REG(data->autofan[nr].config)); +} +static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->autofan[nr].config = (data->autofan[nr].config & (~0xe0)) + | ZONE_TO_REG(val) ; + lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), + data->autofan[nr].config); + up(&data->update_lock); + return count; +} +static ssize_t show_pwm_auto_pwm_min(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm)); +} +static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->autofan[nr].min_pwm = PWM_TO_REG(val); + lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr), + data->autofan[nr].min_pwm); + up(&data->update_lock); + return count; +} +static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", data->autofan[nr].min_off); +} +static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->autofan[nr].min_off = val; + lm85_write_value(client, LM85_REG_AFAN_SPIKE1, data->smooth[0] + | data->syncpwm3 + | (data->autofan[0].min_off ? 0x20 : 0) + | (data->autofan[1].min_off ? 0x40 : 0) + | (data->autofan[2].min_off ? 0x80 : 0) + ); + up(&data->update_lock); + return count; +} +static ssize_t show_pwm_auto_pwm_freq(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", FREQ_FROM_REG(data->autofan[nr].freq)); +} +static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->autofan[nr].freq = FREQ_TO_REG(val); + lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), + (data->zone[nr].range << 4) + | data->autofan[nr].freq + ); + up(&data->update_lock); + return count; +} +#define pwm_auto(offset) \ +static ssize_t show_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_pwm_auto_channels(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm_auto_channels(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_pwm_auto_pwm_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm_auto_pwm_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_pwm_auto_pwm_minctl(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm_auto_pwm_minctl(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_pwm##offset##_auto_pwm_freq (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_pwm_auto_pwm_freq(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset##_auto_pwm_freq(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm_auto_pwm_freq(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(pwm##offset##_auto_channels, S_IRUGO | S_IWUSR, \ + show_pwm##offset##_auto_channels, \ + set_pwm##offset##_auto_channels); \ +static DEVICE_ATTR(pwm##offset##_auto_pwm_min, S_IRUGO | S_IWUSR, \ + show_pwm##offset##_auto_pwm_min, \ + set_pwm##offset##_auto_pwm_min); \ +static DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, S_IRUGO | S_IWUSR, \ + show_pwm##offset##_auto_pwm_minctl, \ + set_pwm##offset##_auto_pwm_minctl); \ +static DEVICE_ATTR(pwm##offset##_auto_pwm_freq, S_IRUGO | S_IWUSR, \ + show_pwm##offset##_auto_pwm_freq, \ + set_pwm##offset##_auto_pwm_freq); +pwm_auto(1); +pwm_auto(2); +pwm_auto(3); + +/* Temperature settings for automatic PWM control */ + +static ssize_t show_temp_auto_temp_off(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) - + HYST_FROM_REG(data->zone[nr].hyst)); +} +static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + int min; + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + min = TEMP_FROM_REG(data->zone[nr].limit); + data->zone[nr].off_desired = TEMP_TO_REG(val); + data->zone[nr].hyst = HYST_TO_REG(min - val); + if ( nr == 0 || nr == 1 ) { + lm85_write_value(client, LM85_REG_AFAN_HYST1, + (data->zone[0].hyst << 4) + | data->zone[1].hyst + ); + } else { + lm85_write_value(client, LM85_REG_AFAN_HYST2, + (data->zone[2].hyst << 4) + ); + } + up(&data->update_lock); + return count; +} +static ssize_t show_temp_auto_temp_min(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) ); +} +static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->zone[nr].limit = TEMP_TO_REG(val); + lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr), + data->zone[nr].limit); + +/* Update temp_auto_max and temp_auto_range */ + data->zone[nr].range = RANGE_TO_REG( + TEMP_FROM_REG(data->zone[nr].max_desired) - + TEMP_FROM_REG(data->zone[nr].limit)); + lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), + ((data->zone[nr].range & 0x0f) << 4) + | (data->autofan[nr].freq & 0x07)); + +/* Update temp_auto_hyst and temp_auto_off */ + data->zone[nr].hyst = HYST_TO_REG(TEMP_FROM_REG( + data->zone[nr].limit) - TEMP_FROM_REG( + data->zone[nr].off_desired)); + if ( nr == 0 || nr == 1 ) { + lm85_write_value(client, LM85_REG_AFAN_HYST1, + (data->zone[0].hyst << 4) + | data->zone[1].hyst + ); + } else { + lm85_write_value(client, LM85_REG_AFAN_HYST2, + (data->zone[2].hyst << 4) + ); + } + up(&data->update_lock); + return count; +} +static ssize_t show_temp_auto_temp_max(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) + + RANGE_FROM_REG(data->zone[nr].range)); +} +static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + int min; + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + min = TEMP_FROM_REG(data->zone[nr].limit); + data->zone[nr].max_desired = TEMP_TO_REG(val); + data->zone[nr].range = RANGE_TO_REG( + val - min); + lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), + ((data->zone[nr].range & 0x0f) << 4) + | (data->autofan[nr].freq & 0x07)); + up(&data->update_lock); + return count; +} +static ssize_t show_temp_auto_temp_crit(struct device *dev, char *buf, int nr) +{ + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].critical)); +} +static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->zone[nr].critical = TEMP_TO_REG(val); + lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr), + data->zone[nr].critical); + up(&data->update_lock); + return count; +} +#define temp_auto(offset) \ +static ssize_t show_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp_auto_temp_off(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_auto_temp_off(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp_auto_temp_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_auto_temp_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp_auto_temp_max(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_auto_temp_max(dev, buf, count, offset - 1); \ +} \ +static ssize_t show_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp_auto_temp_crit(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_auto_temp_crit(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(temp##offset##_auto_temp_off, S_IRUGO | S_IWUSR, \ + show_temp##offset##_auto_temp_off, \ + set_temp##offset##_auto_temp_off); \ +static DEVICE_ATTR(temp##offset##_auto_temp_min, S_IRUGO | S_IWUSR, \ + show_temp##offset##_auto_temp_min, \ + set_temp##offset##_auto_temp_min); \ +static DEVICE_ATTR(temp##offset##_auto_temp_max, S_IRUGO | S_IWUSR, \ + show_temp##offset##_auto_temp_max, \ + set_temp##offset##_auto_temp_max); \ +static DEVICE_ATTR(temp##offset##_auto_temp_crit, S_IRUGO | S_IWUSR, \ + show_temp##offset##_auto_temp_crit, \ + set_temp##offset##_auto_temp_crit); +temp_auto(1); +temp_auto(2); +temp_auto(3); + +int lm85_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm85_detect); +} + +int lm85_detect(struct i2c_adapter *adapter, int address, + int kind) +{ + int company, verstep ; + struct i2c_client *new_client = NULL; + struct lm85_data *data; + int err = 0; + const char *type_name = ""; + + if (i2c_is_isa_adapter(adapter)) { + /* This chip has no ISA interface */ + goto ERROR0 ; + }; + + if (!i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + /* We need to be able to do byte I/O */ + goto ERROR0 ; + }; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm85_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct lm85_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + memset(data, 0, sizeof(struct lm85_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm85_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + company = lm85_read_value(new_client, LM85_REG_COMPANY); + verstep = lm85_read_value(new_client, LM85_REG_VERSTEP); + + dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with" + " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", + i2c_adapter_id(new_client->adapter), new_client->addr, + company, verstep); + + /* If auto-detecting, Determine the chip type. */ + if (kind <= 0) { + dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x ...\n", + i2c_adapter_id(adapter), address ); + if( company == LM85_COMPANY_NATIONAL + && verstep == LM85_VERSTEP_LM85C ) { + kind = lm85c ; + } else if( company == LM85_COMPANY_NATIONAL + && verstep == LM85_VERSTEP_LM85B ) { + kind = lm85b ; + } else if( company == LM85_COMPANY_NATIONAL + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) { + dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x" + " Defaulting to LM85.\n", verstep); + kind = any_chip ; + } else if( company == LM85_COMPANY_ANALOG_DEV + && verstep == LM85_VERSTEP_ADM1027 ) { + kind = adm1027 ; + } else if( company == LM85_COMPANY_ANALOG_DEV + && (verstep == LM85_VERSTEP_ADT7463 + || verstep == LM85_VERSTEP_ADT7463C) ) { + kind = adt7463 ; + } else if( company == LM85_COMPANY_ANALOG_DEV + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) { + dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x" + " Defaulting to Generic LM85.\n", verstep ); + kind = any_chip ; + } else if( company == LM85_COMPANY_SMSC + && (verstep == LM85_VERSTEP_EMC6D100_A0 + || verstep == LM85_VERSTEP_EMC6D100_A1) ) { + /* Unfortunately, we can't tell a '100 from a '101 + * from the registers. Since a '101 is a '100 + * in a package with fewer pins and therefore no + * 3.3V, 1.5V or 1.8V inputs, perhaps if those + * inputs read 0, then it's a '101. + */ + kind = emc6d100 ; + } else if( company == LM85_COMPANY_SMSC + && verstep == LM85_VERSTEP_EMC6D102) { + kind = emc6d102 ; + } else if( company == LM85_COMPANY_SMSC + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { + dev_err(&adapter->dev, "lm85: Detected SMSC chip\n"); + dev_err(&adapter->dev, "lm85: Unrecognized version/stepping 0x%02x" + " Defaulting to Generic LM85.\n", verstep ); + kind = any_chip ; + } else if( kind == any_chip + && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { + dev_err(&adapter->dev, "Generic LM85 Version 6 detected\n"); + /* Leave kind as "any_chip" */ + } else { + dev_dbg(&adapter->dev, "Autodetection failed\n"); + /* Not an LM85 ... */ + if( kind == any_chip ) { /* User used force=x,y */ + dev_err(&adapter->dev, "Generic LM85 Version 6 not" + " found at %d,0x%02x. Try force_lm85c.\n", + i2c_adapter_id(adapter), address ); + } + err = 0 ; + goto ERROR1; + } + } + + /* Fill in the chip specific driver values */ + if ( kind == any_chip ) { + type_name = "lm85"; + } else if ( kind == lm85b ) { + type_name = "lm85b"; + } else if ( kind == lm85c ) { + type_name = "lm85c"; + } else if ( kind == adm1027 ) { + type_name = "adm1027"; + } else if ( kind == adt7463 ) { + type_name = "adt7463"; + } else if ( kind == emc6d100){ + type_name = "emc6d100"; + } else if ( kind == emc6d102 ) { + type_name = "emc6d102"; + } + strlcpy(new_client->name, type_name, I2C_NAME_SIZE); + + /* Fill in the remaining client fields */ + data->type = kind; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR1; + + /* Set the VRM version */ + data->vrm = i2c_which_vrm(); + + /* Initialize the LM85 chip */ + lm85_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan3_input); + device_create_file(&new_client->dev, &dev_attr_fan4_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan3_min); + device_create_file(&new_client->dev, &dev_attr_fan4_min); + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_pwm2); + device_create_file(&new_client->dev, &dev_attr_pwm3); + device_create_file(&new_client->dev, &dev_attr_pwm1_enable); + device_create_file(&new_client->dev, &dev_attr_pwm2_enable); + device_create_file(&new_client->dev, &dev_attr_pwm3_enable); + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp3_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp3_max); + device_create_file(&new_client->dev, &dev_attr_vrm); + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_pwm1_auto_channels); + device_create_file(&new_client->dev, &dev_attr_pwm2_auto_channels); + device_create_file(&new_client->dev, &dev_attr_pwm3_auto_channels); + device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_min); + device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_min); + device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_min); + device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_minctl); + device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_minctl); + device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_minctl); + device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_freq); + device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_freq); + device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_freq); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_off); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_off); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_off); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_min); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_min); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_min); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_max); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_max); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_max); + device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_crit); + device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_crit); + + return 0; + + /* Error out and cleanup code */ + ERROR1: + kfree(data); + ERROR0: + return err; +} + +int lm85_detach_client(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); + return 0; +} + + +int lm85_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + /* What size location is it? */ + switch( reg ) { + case LM85_REG_FAN(0) : /* Read WORD data */ + case LM85_REG_FAN(1) : + case LM85_REG_FAN(2) : + case LM85_REG_FAN(3) : + case LM85_REG_FAN_MIN(0) : + case LM85_REG_FAN_MIN(1) : + case LM85_REG_FAN_MIN(2) : + case LM85_REG_FAN_MIN(3) : + case LM85_REG_ALARM1 : /* Read both bytes at once */ + res = i2c_smbus_read_byte_data(client, reg) & 0xff ; + res |= i2c_smbus_read_byte_data(client, reg+1) << 8 ; + break ; + case ADT7463_REG_TMIN_CTL1 : /* Read WORD MSB, LSB */ + res = i2c_smbus_read_byte_data(client, reg) << 8 ; + res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff ; + break ; + default: /* Read BYTE data */ + res = i2c_smbus_read_byte_data(client, reg); + break ; + } + + return res ; +} + +int lm85_write_value(struct i2c_client *client, u8 reg, int value) +{ + int res ; + + switch( reg ) { + case LM85_REG_FAN(0) : /* Write WORD data */ + case LM85_REG_FAN(1) : + case LM85_REG_FAN(2) : + case LM85_REG_FAN(3) : + case LM85_REG_FAN_MIN(0) : + case LM85_REG_FAN_MIN(1) : + case LM85_REG_FAN_MIN(2) : + case LM85_REG_FAN_MIN(3) : + /* NOTE: ALARM is read only, so not included here */ + res = i2c_smbus_write_byte_data(client, reg, value & 0xff) ; + res |= i2c_smbus_write_byte_data(client, reg+1, (value>>8) & 0xff) ; + break ; + case ADT7463_REG_TMIN_CTL1 : /* Write WORD MSB, LSB */ + res = i2c_smbus_write_byte_data(client, reg, (value>>8) & 0xff); + res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff) ; + break ; + default: /* Write BYTE data */ + res = i2c_smbus_write_byte_data(client, reg, value); + break ; + } + + return res ; +} + +void lm85_init_client(struct i2c_client *client) +{ + int value; + struct lm85_data *data = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "Initializing device\n"); + + /* Warn if part was not "READY" */ + value = lm85_read_value(client, LM85_REG_CONFIG); + dev_dbg(&client->dev, "LM85_REG_CONFIG is: 0x%02x\n", value); + if( value & 0x02 ) { + dev_err(&client->dev, "Client (%d,0x%02x) config is locked.\n", + i2c_adapter_id(client->adapter), client->addr ); + }; + if( ! (value & 0x04) ) { + dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n", + i2c_adapter_id(client->adapter), client->addr ); + }; + if( value & 0x10 + && ( data->type == adm1027 + || data->type == adt7463 ) ) { + dev_err(&client->dev, "Client (%d,0x%02x) VxI mode is set. " + "Please report this to the lm85 maintainer.\n", + i2c_adapter_id(client->adapter), client->addr ); + }; + + /* WE INTENTIONALLY make no changes to the limits, + * offsets, pwms, fans and zones. If they were + * configured, we don't want to mess with them. + * If they weren't, the default is 100% PWM, no + * control and will suffice until 'sensors -s' + * can be run by the user. + */ + + /* Start monitoring */ + value = lm85_read_value(client, LM85_REG_CONFIG); + /* Try to clear LOCK, Set START, save everything else */ + value = (value & ~ 0x02) | 0x01 ; + dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value); + lm85_write_value(client, LM85_REG_CONFIG, value); +} + +static struct lm85_data *lm85_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm85_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if ( !data->valid || + time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL) ) { + /* Things that change quickly */ + dev_dbg(&client->dev, "Reading sensor values\n"); + + /* Have to read extended bits first to "freeze" the + * more significant bits that are read later. + */ + if ( (data->type == adm1027) || (data->type == adt7463) ) { + int ext1 = lm85_read_value(client, + ADM1027_REG_EXTEND_ADC1); + int ext2 = lm85_read_value(client, + ADM1027_REG_EXTEND_ADC2); + int val = (ext1 << 8) + ext2; + + for(i = 0; i <= 4; i++) + data->in_ext[i] = (val>>(i * 2))&0x03; + + for(i = 0; i <= 2; i++) + data->temp_ext[i] = (val>>((i + 5) * 2))&0x03; + } + + /* adc_scale is 2^(number of LSBs). There are 4 extra bits in + the emc6d102 and 2 in the adt7463 and adm1027. In all + other chips ext is always 0 and the value of scale is + irrelevant. So it is left in 4*/ + data->adc_scale = (data->type == emc6d102 ) ? 16 : 4; + + for (i = 0; i <= 4; ++i) { + data->in[i] = + lm85_read_value(client, LM85_REG_IN(i)); + } + + for (i = 0; i <= 3; ++i) { + data->fan[i] = + lm85_read_value(client, LM85_REG_FAN(i)); + } + + for (i = 0; i <= 2; ++i) { + data->temp[i] = + lm85_read_value(client, LM85_REG_TEMP(i)); + } + + for (i = 0; i <= 2; ++i) { + data->pwm[i] = + lm85_read_value(client, LM85_REG_PWM(i)); + } + + data->alarms = lm85_read_value(client, LM85_REG_ALARM1); + + if ( data->type == adt7463 ) { + if( data->therm_total < ULONG_MAX - 256 ) { + data->therm_total += + lm85_read_value(client, ADT7463_REG_THERM ); + } + } else if ( data->type == emc6d100 ) { + /* Three more voltage sensors */ + for (i = 5; i <= 7; ++i) { + data->in[i] = + lm85_read_value(client, EMC6D100_REG_IN(i)); + } + /* More alarm bits */ + data->alarms |= + lm85_read_value(client, EMC6D100_REG_ALARM3) << 16; + } else if (data->type == emc6d102 ) { + /* Have to read LSB bits after the MSB ones because + the reading of the MSB bits has frozen the + LSBs (backward from the ADM1027). + */ + int ext1 = lm85_read_value(client, + EMC6D102_REG_EXTEND_ADC1); + int ext2 = lm85_read_value(client, + EMC6D102_REG_EXTEND_ADC2); + int ext3 = lm85_read_value(client, + EMC6D102_REG_EXTEND_ADC3); + int ext4 = lm85_read_value(client, + EMC6D102_REG_EXTEND_ADC4); + data->in_ext[0] = ext3 & 0x0f; + data->in_ext[1] = ext4 & 0x0f; + data->in_ext[2] = (ext4 >> 4) & 0x0f; + data->in_ext[3] = (ext3 >> 4) & 0x0f; + data->in_ext[4] = (ext2 >> 4) & 0x0f; + + data->temp_ext[0] = ext1 & 0x0f; + data->temp_ext[1] = ext2 & 0x0f; + data->temp_ext[2] = (ext1 >> 4) & 0x0f; + } + + data->last_reading = jiffies ; + }; /* last_reading */ + + if ( !data->valid || + time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL) ) { + /* Things that don't change often */ + dev_dbg(&client->dev, "Reading config values\n"); + + for (i = 0; i <= 4; ++i) { + data->in_min[i] = + lm85_read_value(client, LM85_REG_IN_MIN(i)); + data->in_max[i] = + lm85_read_value(client, LM85_REG_IN_MAX(i)); + } + + if ( data->type == emc6d100 ) { + for (i = 5; i <= 7; ++i) { + data->in_min[i] = + lm85_read_value(client, EMC6D100_REG_IN_MIN(i)); + data->in_max[i] = + lm85_read_value(client, EMC6D100_REG_IN_MAX(i)); + } + } + + for (i = 0; i <= 3; ++i) { + data->fan_min[i] = + lm85_read_value(client, LM85_REG_FAN_MIN(i)); + } + + for (i = 0; i <= 2; ++i) { + data->temp_min[i] = + lm85_read_value(client, LM85_REG_TEMP_MIN(i)); + data->temp_max[i] = + lm85_read_value(client, LM85_REG_TEMP_MAX(i)); + } + + data->vid = lm85_read_value(client, LM85_REG_VID); + + for (i = 0; i <= 2; ++i) { + int val ; + data->autofan[i].config = + lm85_read_value(client, LM85_REG_AFAN_CONFIG(i)); + val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i)); + data->autofan[i].freq = val & 0x07 ; + data->zone[i].range = (val >> 4) & 0x0f ; + data->autofan[i].min_pwm = + lm85_read_value(client, LM85_REG_AFAN_MINPWM(i)); + data->zone[i].limit = + lm85_read_value(client, LM85_REG_AFAN_LIMIT(i)); + data->zone[i].critical = + lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i)); + } + + i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); + data->smooth[0] = i & 0x0f ; + data->syncpwm3 = i & 0x10 ; /* Save PWM3 config */ + data->autofan[0].min_off = (i & 0x20) != 0 ; + data->autofan[1].min_off = (i & 0x40) != 0 ; + data->autofan[2].min_off = (i & 0x80) != 0 ; + i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2); + data->smooth[1] = (i>>4) & 0x0f ; + data->smooth[2] = i & 0x0f ; + + i = lm85_read_value(client, LM85_REG_AFAN_HYST1); + data->zone[0].hyst = (i>>4) & 0x0f ; + data->zone[1].hyst = i & 0x0f ; + + i = lm85_read_value(client, LM85_REG_AFAN_HYST2); + data->zone[2].hyst = (i>>4) & 0x0f ; + + if ( (data->type == lm85b) || (data->type == lm85c) ) { + data->tach_mode = lm85_read_value(client, + LM85_REG_TACH_MODE ); + data->spinup_ctl = lm85_read_value(client, + LM85_REG_SPINUP_CTL ); + } else if ( (data->type == adt7463) || (data->type == adm1027) ) { + if ( data->type == adt7463 ) { + for (i = 0; i <= 2; ++i) { + data->oppoint[i] = lm85_read_value(client, + ADT7463_REG_OPPOINT(i) ); + } + data->tmin_ctl = lm85_read_value(client, + ADT7463_REG_TMIN_CTL1 ); + data->therm_limit = lm85_read_value(client, + ADT7463_REG_THERM_LIMIT ); + } + for (i = 0; i <= 2; ++i) { + data->temp_offset[i] = lm85_read_value(client, + ADM1027_REG_TEMP_OFFSET(i) ); + } + data->tach_mode = lm85_read_value(client, + ADM1027_REG_CONFIG3 ); + data->fan_ppr = lm85_read_value(client, + ADM1027_REG_FAN_PPR ); + } + + data->last_config = jiffies; + }; /* last_config */ + + data->valid = 1; + + up(&data->update_lock); + + return data; +} + + +static int __init sm_lm85_init(void) +{ + return i2c_add_driver(&lm85_driver); +} + +static void __exit sm_lm85_exit(void) +{ + i2c_del_driver(&lm85_driver); +} + +/* Thanks to Richard Barrington for adding the LM85 to sensors-detect. + * Thanks to Margit Schubert-While for help with + * post 2.7.0 CVS changes. + */ +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Philip Pokorny , Margit Schubert-While , Justin Thiessen + * Philip Edelbrock + * Stephen Rousset + * Dan Eaton + * Copyright (C) 2004 Jean Delvare + * + * Original port to Linux 2.6 by Jeff Oliver. + * + * The LM87 is a sensor chip made by National Semiconductor. It monitors up + * to 8 voltages (including its own power source), up to three temperatures + * (its own plus up to two external ones) and up to two fans. The default + * configuration is 6 voltages, two temperatures and two fans (see below). + * Voltages are scaled internally with ratios such that the nominal value of + * each voltage correspond to a register value of 192 (which means a + * resolution of about 0.5% of the nominal value). Temperature values are + * reported with a 1 deg resolution and a 3-4 deg accuracy. Complete + * datasheet can be obtained from National's website at: + * http://www.national.com/pf/LM/LM87.html + * + * Some functions share pins, so not all functions are available at the same + * time. Which are depends on the hardware setup. This driver assumes that + * the BIOS configured the chip correctly. In that respect, it differs from + * the original driver (from lm_sensors for Linux 2.4), which would force the + * LM87 to an arbitrary, compile-time chosen mode, regardless of the actual + * chipset wiring. + * For reference, here is the list of exclusive functions: + * - in0+in5 (default) or temp3 + * - fan1 (default) or in6 + * - fan2 (default) or in7 + * - VID lines (default) or IRQ lines (not handled by this driver) + * + * The LM87 additionally features an analog output, supposedly usable to + * control the speed of a fan. All new chips use pulse width modulation + * instead. The LM87 is the only hardware monitoring chipset I know of + * which uses amplitude modulation. Be careful when using this feature. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan + * LM87 has three possible addresses: 0x2c, 0x2d and 0x2e. + */ + +static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(lm87); + +/* + * The LM87 registers + */ + +/* nr in 0..5 */ +#define LM87_REG_IN(nr) (0x20 + (nr)) +#define LM87_REG_IN_MAX(nr) (0x2B + (nr) * 2) +#define LM87_REG_IN_MIN(nr) (0x2C + (nr) * 2) +/* nr in 0..1 */ +#define LM87_REG_AIN(nr) (0x28 + (nr)) +#define LM87_REG_AIN_MIN(nr) (0x1A + (nr)) +#define LM87_REG_AIN_MAX(nr) (0x3B + (nr)) + +static u8 LM87_REG_TEMP[3] = { 0x27, 0x26, 0x20 }; +static u8 LM87_REG_TEMP_HIGH[3] = { 0x39, 0x37, 0x2B }; +static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; + +#define LM87_REG_TEMP_HW_INT_LOCK 0x13 +#define LM87_REG_TEMP_HW_EXT_LOCK 0x14 +#define LM87_REG_TEMP_HW_INT 0x17 +#define LM87_REG_TEMP_HW_EXT 0x18 + +/* nr in 0..1 */ +#define LM87_REG_FAN(nr) (0x28 + (nr)) +#define LM87_REG_FAN_MIN(nr) (0x3B + (nr)) +#define LM87_REG_AOUT 0x19 + +#define LM87_REG_CONFIG 0x40 +#define LM87_REG_CHANNEL_MODE 0x16 +#define LM87_REG_VID_FAN_DIV 0x47 +#define LM87_REG_VID4 0x49 + +#define LM87_REG_ALARMS1 0x41 +#define LM87_REG_ALARMS2 0x42 + +#define LM87_REG_COMPANY_ID 0x3E +#define LM87_REG_REVISION 0x3F + +/* + * Conversions and various macros + * The LM87 uses signed 8-bit values for temperatures. + */ + +#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) +#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ + (val) * 192 >= (scale) * 255 ? 255 : \ + ((val) * 192 + (scale)/2) / (scale)) + +#define TEMP_FROM_REG(reg) ((reg) * 1000) +#define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \ + (val) >= 126500 ? 127 : \ + (((val) < 0 ? (val)-500 : (val)+500) / 1000)) + +#define FAN_FROM_REG(reg,div) ((reg) == 255 || (reg) == 0 ? 0 : \ + 1350000 + (reg)*(div) / 2) / ((reg)*(div)) +#define FAN_TO_REG(val,div) ((val)*(div) * 255 <= 1350000 ? 255 : \ + (1350000 + (val)*(div) / 2) / ((val)*(div))) + +#define FAN_DIV_FROM_REG(reg) (1 << (reg)) + +/* analog out is 9.80mV/LSB */ +#define AOUT_FROM_REG(reg) (((reg) * 98 + 5) / 10) +#define AOUT_TO_REG(val) ((val) <= 0 ? 0 : \ + (val) >= 2500 ? 255 : \ + ((val) * 10 + 49) / 98) + +/* nr in 0..1 */ +#define CHAN_NO_FAN(nr) (1 << (nr)) +#define CHAN_TEMP3 (1 << 2) +#define CHAN_VCC_5V (1 << 3) +#define CHAN_NO_VID (1 << 8) + +/* + * Functions declaration + */ + +static int lm87_attach_adapter(struct i2c_adapter *adapter); +static int lm87_detect(struct i2c_adapter *adapter, int address, int kind); +static void lm87_init_client(struct i2c_client *client); +static int lm87_detach_client(struct i2c_client *client); +static struct lm87_data *lm87_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver lm87_driver = { + .owner = THIS_MODULE, + .name = "lm87", + .id = I2C_DRIVERID_LM87, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm87_attach_adapter, + .detach_client = lm87_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct lm87_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 channel; /* register value */ + + u8 in[8]; /* register value */ + u8 in_max[8]; /* register value */ + u8 in_min[8]; /* register value */ + u16 in_scale[8]; + + s8 temp[3]; /* register value */ + s8 temp_high[3]; /* register value */ + s8 temp_low[3]; /* register value */ + s8 temp_crit_int; /* min of two register values */ + s8 temp_crit_ext; /* min of two register values */ + + u8 fan[2]; /* register value */ + u8 fan_min[2]; /* register value */ + u8 fan_div[2]; /* register value, shifted right */ + u8 aout; /* register value */ + + u16 alarms; /* register values, combined */ + u8 vid; /* register values, combined */ + u8 vrm; +}; + +/* + * Sysfs stuff + */ + +static inline int lm87_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +#define show_in(offset) \ +static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ + data->in_scale[offset])); \ +} \ +static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ + data->in_scale[offset])); \ +} \ +static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ + data->in_scale[offset])); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in##offset##_input, NULL); +show_in(0); +show_in(1); +show_in(2); +show_in(3); +show_in(4); +show_in(5); +show_in(6); +show_in(7); + +static void set_in_min(struct device *dev, const char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]); + lm87_write_value(client, nr<6 ? LM87_REG_IN_MIN(nr) : + LM87_REG_AIN_MIN(nr-6), data->in_min[nr]); + up(&data->update_lock); +} + +static void set_in_max(struct device *dev, const char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]); + lm87_write_value(client, nr<6 ? LM87_REG_IN_MAX(nr) : + LM87_REG_AIN_MAX(nr-6), data->in_max[nr]); + up(&data->update_lock); +} + +#define set_in(offset) \ +static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + set_in_min(dev, buf, offset); \ + return count; \ +} \ +static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + set_in_max(dev, buf, offset); \ + return count; \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); +set_in(0); +set_in(1); +set_in(2); +set_in(3); +set_in(4); +set_in(5); +set_in(6); +set_in(7); + +#define show_temp(offset) \ +static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ +} \ +static ssize_t show_temp##offset##_low(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[offset-1])); \ +} \ +static ssize_t show_temp##offset##_high(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[offset-1])); \ +}\ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp##offset##_input, NULL); +show_temp(1); +show_temp(2); +show_temp(3); + +static void set_temp_low(struct device *dev, const char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_low[nr] = TEMP_TO_REG(val); + lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]); + up(&data->update_lock); +} + +static void set_temp_high(struct device *dev, const char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_high[nr] = TEMP_TO_REG(val); + lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]); + up(&data->update_lock); +} + +#define set_temp(offset) \ +static ssize_t set_temp##offset##_low(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + set_temp_low(dev, buf, offset-1); \ + return count; \ +} \ +static ssize_t set_temp##offset##_high(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + set_temp_high(dev, buf, offset-1); \ + return count; \ +} \ +static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp##offset##_high, set_temp##offset##_high); \ +static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp##offset##_low, set_temp##offset##_low); +set_temp(1); +set_temp(2); +set_temp(3); + +static ssize_t show_temp_crit_int(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_int)); +} + +static ssize_t show_temp_crit_ext(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_ext)); +} + +static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit_int, NULL); +static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit_ext, NULL); +static DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit_ext, NULL); + +#define show_fan(offset) \ +static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[offset-1], \ + FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ +} \ +static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[offset-1], \ + FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ +} \ +static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm87_data *data = lm87_update_device(dev); \ + return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[offset-1])); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan##offset##_input, NULL); +show_fan(1); +show_fan(2); + +static void set_fan_min(struct device *dev, const char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, + FAN_DIV_FROM_REG(data->fan_div[nr])); + lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan clock divider. This follows the principle + of least suprise; the user doesn't expect the fan minimum to change just + because the divider changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + unsigned long min; + u8 reg; + + down(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], + FAN_DIV_FROM_REG(data->fan_div[nr])); + + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + up(&data->update_lock); + return -EINVAL; + } + + reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV); + switch (nr) { + case 0: + reg = (reg & 0xCF) | (data->fan_div[0] << 4); + break; + case 1: + reg = (reg & 0x3F) | (data->fan_div[1] << 6); + break; + } + lm87_write_value(client, LM87_REG_VID_FAN_DIV, reg); + + data->fan_min[nr] = FAN_TO_REG(min, val); + lm87_write_value(client, LM87_REG_FAN_MIN(nr), + data->fan_min[nr]); + up(&data->update_lock); + + return count; +} + +#define set_fan(offset) \ +static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + set_fan_min(dev, buf, offset-1); \ + return count; \ +} \ +static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_fan_div(dev, buf, count, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan##offset##_min, set_fan##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan##offset##_div, set_fan##offset##_div); +set_fan(1); +set_fan(2); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", data->vrm); +} +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + data->vrm = simple_strtoul(buf, NULL, 10); + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); + +static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); +} +static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->aout = AOUT_TO_REG(val); + lm87_write_value(client, LM87_REG_AOUT, data->aout); + up(&data->update_lock); + return count; +} +static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); + +/* + * Real code + */ + +static int lm87_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm87_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm87_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm87_data)); + + /* The common I2C client data is placed right before the + LM87-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm87_driver; + new_client->flags = 0; + + /* Default to an LM87 if forced */ + if (kind == 0) + kind = lm87; + + /* Now, we do the remaining detection. */ + if (kind < 0) { + u8 rev = lm87_read_value(new_client, LM87_REG_REVISION); + + if (rev < 0x01 || rev > 0x08 + || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80) + || lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02) { + dev_dbg(&adapter->dev, + "LM87 detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, "lm87", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the LM87 chip */ + lm87_init_client(new_client); + + data->in_scale[0] = 2500; + data->in_scale[1] = 2700; + data->in_scale[2] = (data->channel & CHAN_VCC_5V) ? 5000 : 3300; + data->in_scale[3] = 5000; + data->in_scale[4] = 12000; + data->in_scale[5] = 2700; + data->in_scale[6] = 1875; + data->in_scale[7] = 1875; + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + + if (data->channel & CHAN_NO_FAN(0)) { + device_create_file(&new_client->dev, &dev_attr_in6_input); + device_create_file(&new_client->dev, &dev_attr_in6_min); + device_create_file(&new_client->dev, &dev_attr_in6_max); + } else { + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + } + if (data->channel & CHAN_NO_FAN(1)) { + device_create_file(&new_client->dev, &dev_attr_in7_input); + device_create_file(&new_client->dev, &dev_attr_in7_min); + device_create_file(&new_client->dev, &dev_attr_in7_max); + } else { + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + } + + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp2_crit); + + if (data->channel & CHAN_TEMP3) { + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp3_max); + device_create_file(&new_client->dev, &dev_attr_temp3_min); + device_create_file(&new_client->dev, &dev_attr_temp3_crit); + } else { + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in5_max); + } + + if (!(data->channel & CHAN_NO_VID)) { + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + device_create_file(&new_client->dev, &dev_attr_vrm); + } + + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_aout_output); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static void lm87_init_client(struct i2c_client *client) +{ + struct lm87_data *data = i2c_get_clientdata(client); + u8 config; + + data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE); + data->vrm = i2c_which_vrm(); + + config = lm87_read_value(client, LM87_REG_CONFIG); + if (!(config & 0x01)) { + int i; + + /* Limits are left uninitialized after power-up */ + for (i = 1; i < 6; i++) { + lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00); + lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF); + } + for (i = 0; i < 2; i++) { + lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F); + lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00); + lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00); + lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF); + } + if (data->channel & CHAN_TEMP3) { + lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F); + lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00); + } else { + lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00); + lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF); + } + } + if ((config & 0x81) != 0x01) { + /* Start monitoring */ + lm87_write_value(client, LM87_REG_CONFIG, + (config & 0xF7) | 0x01); + } +} + +static int lm87_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static struct lm87_data *lm87_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + int i, j; + + dev_dbg(&client->dev, "Updating data.\n"); + + i = (data->channel & CHAN_TEMP3) ? 1 : 0; + j = (data->channel & CHAN_TEMP3) ? 5 : 6; + for (; i < j; i++) { + data->in[i] = lm87_read_value(client, + LM87_REG_IN(i)); + data->in_min[i] = lm87_read_value(client, + LM87_REG_IN_MIN(i)); + data->in_max[i] = lm87_read_value(client, + LM87_REG_IN_MAX(i)); + } + + for (i = 0; i < 2; i++) { + if (data->channel & CHAN_NO_FAN(i)) { + data->in[6+i] = lm87_read_value(client, + LM87_REG_AIN(i)); + data->in_max[6+i] = lm87_read_value(client, + LM87_REG_AIN_MAX(i)); + data->in_min[6+i] = lm87_read_value(client, + LM87_REG_AIN_MIN(i)); + + } else { + data->fan[i] = lm87_read_value(client, + LM87_REG_FAN(i)); + data->fan_min[i] = lm87_read_value(client, + LM87_REG_FAN_MIN(i)); + } + } + + j = (data->channel & CHAN_TEMP3) ? 3 : 2; + for (i = 0 ; i < j; i++) { + data->temp[i] = lm87_read_value(client, + LM87_REG_TEMP[i]); + data->temp_high[i] = lm87_read_value(client, + LM87_REG_TEMP_HIGH[i]); + data->temp_low[i] = lm87_read_value(client, + LM87_REG_TEMP_LOW[i]); + } + + i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK); + j = lm87_read_value(client, LM87_REG_TEMP_HW_INT); + data->temp_crit_int = min(i, j); + + i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK); + j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT); + data->temp_crit_ext = min(i, j); + + i = lm87_read_value(client, LM87_REG_VID_FAN_DIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + data->vid = (i & 0x0F) + | (lm87_read_value(client, LM87_REG_VID4) & 0x01) + << 4; + + data->alarms = lm87_read_value(client, LM87_REG_ALARMS1) + | (lm87_read_value(client, LM87_REG_ALARMS2) + << 8); + data->aout = lm87_read_value(client, LM87_REG_AOUT); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm87_init(void) +{ + return i2c_add_driver(&lm87_driver); +} + +static void __exit sensors_lm87_exit(void) +{ + i2c_del_driver(&lm87_driver); +} + +MODULE_AUTHOR("Jean Delvare and others"); +MODULE_DESCRIPTION("LM87 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm87_init); +module_exit(sensors_lm87_exit); diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c new file mode 100644 index 00000000000..a67dcadf7cb --- /dev/null +++ b/drivers/hwmon/lm90.c @@ -0,0 +1,655 @@ +/* + * lm90.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2003-2005 Jean Delvare + * + * Based on the lm83 driver. The LM90 is a sensor chip made by National + * Semiconductor. It reports up to two temperatures (its own plus up to + * one external one) with a 0.125 deg resolution (1 deg for local + * temperature) and a 3-4 deg accuracy. Complete datasheet can be + * obtained from National's website at: + * http://www.national.com/pf/LM/LM90.html + * + * This driver also supports the LM89 and LM99, two other sensor chips + * made by National Semiconductor. Both have an increased remote + * temperature measurement accuracy (1 degree), and the LM99 + * additionally shifts remote temperatures (measured and limits) by 16 + * degrees, which allows for higher temperatures measurement. The + * driver doesn't handle it since it can be done easily in user-space. + * Complete datasheets can be obtained from National's website at: + * http://www.national.com/pf/LM/LM89.html + * http://www.national.com/pf/LM/LM99.html + * Note that there is no way to differentiate between both chips. + * + * This driver also supports the LM86, another sensor chip made by + * National Semiconductor. It is exactly similar to the LM90 except it + * has a higher accuracy. + * Complete datasheet can be obtained from National's website at: + * http://www.national.com/pf/LM/LM86.html + * + * This driver also supports the ADM1032, a sensor chip made by Analog + * Devices. That chip is similar to the LM90, with a few differences + * that are not handled by this driver. Complete datasheet can be + * obtained from Analog's website at: + * http://products.analog.com/products/info.asp?product=ADM1032 + * Among others, it has a higher accuracy than the LM90, much like the + * LM86 does. + * + * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor + * chips made by Maxim. These chips are similar to the LM86. Complete + * datasheet can be obtained at Maxim's website at: + * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 + * Note that there is no easy way to differentiate between the three + * variants. The extra address and features of the MAX6659 are not + * supported by this driver. + * + * This driver also supports the ADT7461 chip from Analog Devices but + * only in its "compatability mode". If an ADT7461 chip is found but + * is configured in non-compatible mode (where its temperature + * register values are decoded differently) it is ignored by this + * driver. Complete datasheet can be obtained from Analog's website + * at: + * http://products.analog.com/products/info.asp?product=ADT7461 + * + * Since the LM90 was the first chipset supported by this driver, most + * comments will refer to this chipset, but are actually general and + * concern all supported chipsets, unless mentioned otherwise. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Addresses to scan + * Address is fully defined internally and cannot be changed except for + * MAX6659. + * LM86, LM89, LM90, LM99, ADM1032, MAX6657 and MAX6658 have address 0x4c. + * LM89-1, and LM99-1 have address 0x4d. + * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported). + * ADT7461 always has address 0x4c. + */ + +static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461); + +/* + * The LM90 registers + */ + +#define LM90_REG_R_MAN_ID 0xFE +#define LM90_REG_R_CHIP_ID 0xFF +#define LM90_REG_R_CONFIG1 0x03 +#define LM90_REG_W_CONFIG1 0x09 +#define LM90_REG_R_CONFIG2 0xBF +#define LM90_REG_W_CONFIG2 0xBF +#define LM90_REG_R_CONVRATE 0x04 +#define LM90_REG_W_CONVRATE 0x0A +#define LM90_REG_R_STATUS 0x02 +#define LM90_REG_R_LOCAL_TEMP 0x00 +#define LM90_REG_R_LOCAL_HIGH 0x05 +#define LM90_REG_W_LOCAL_HIGH 0x0B +#define LM90_REG_R_LOCAL_LOW 0x06 +#define LM90_REG_W_LOCAL_LOW 0x0C +#define LM90_REG_R_LOCAL_CRIT 0x20 +#define LM90_REG_W_LOCAL_CRIT 0x20 +#define LM90_REG_R_REMOTE_TEMPH 0x01 +#define LM90_REG_R_REMOTE_TEMPL 0x10 +#define LM90_REG_R_REMOTE_OFFSH 0x11 +#define LM90_REG_W_REMOTE_OFFSH 0x11 +#define LM90_REG_R_REMOTE_OFFSL 0x12 +#define LM90_REG_W_REMOTE_OFFSL 0x12 +#define LM90_REG_R_REMOTE_HIGHH 0x07 +#define LM90_REG_W_REMOTE_HIGHH 0x0D +#define LM90_REG_R_REMOTE_HIGHL 0x13 +#define LM90_REG_W_REMOTE_HIGHL 0x13 +#define LM90_REG_R_REMOTE_LOWH 0x08 +#define LM90_REG_W_REMOTE_LOWH 0x0E +#define LM90_REG_R_REMOTE_LOWL 0x14 +#define LM90_REG_W_REMOTE_LOWL 0x14 +#define LM90_REG_R_REMOTE_CRIT 0x19 +#define LM90_REG_W_REMOTE_CRIT 0x19 +#define LM90_REG_R_TCRIT_HYST 0x21 +#define LM90_REG_W_TCRIT_HYST 0x21 + +/* + * Conversions and various macros + * For local temperatures and limits, critical limits and the hysteresis + * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius. + * For remote temperatures and limits, it uses signed 11-bit values with + * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. + */ + +#define TEMP1_FROM_REG(val) ((val) * 1000) +#define TEMP1_TO_REG(val) ((val) <= -128000 ? -128 : \ + (val) >= 127000 ? 127 : \ + (val) < 0 ? ((val) - 500) / 1000 : \ + ((val) + 500) / 1000) +#define TEMP2_FROM_REG(val) ((val) / 32 * 125) +#define TEMP2_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ + (val) >= 127875 ? 0x7FE0 : \ + (val) < 0 ? ((val) - 62) / 125 * 32 : \ + ((val) + 62) / 125 * 32) +#define HYST_TO_REG(val) ((val) <= 0 ? 0 : (val) >= 30500 ? 31 : \ + ((val) + 500) / 1000) + +/* + * ADT7461 is almost identical to LM90 except that attempts to write + * values that are outside the range 0 < temp < 127 are treated as + * the boundary value. + */ + +#define TEMP1_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ + (val) >= 127000 ? 127 : \ + ((val) + 500) / 1000) +#define TEMP2_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ + (val) >= 127750 ? 0x7FC0 : \ + ((val) + 125) / 250 * 64) + +/* + * Functions declaration + */ + +static int lm90_attach_adapter(struct i2c_adapter *adapter); +static int lm90_detect(struct i2c_adapter *adapter, int address, + int kind); +static void lm90_init_client(struct i2c_client *client); +static int lm90_detach_client(struct i2c_client *client); +static struct lm90_data *lm90_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver lm90_driver = { + .owner = THIS_MODULE, + .name = "lm90", + .id = I2C_DRIVERID_LM90, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm90_attach_adapter, + .detach_client = lm90_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct lm90_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + int kind; + + /* registers values */ + s8 temp8[5]; /* 0: local input + 1: local low limit + 2: local high limit + 3: local critical limit + 4: remote critical limit */ + s16 temp11[3]; /* 0: remote input + 1: remote low limit + 2: remote high limit */ + u8 temp_hyst; + u8 alarms; /* bitvector */ +}; + +/* + * Sysfs stuff + */ + +static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index])); +} + +static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM90_REG_W_LOCAL_LOW, + LM90_REG_W_LOCAL_HIGH, + LM90_REG_W_LOCAL_CRIT, + LM90_REG_W_REMOTE_CRIT, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + if (data->kind == adt7461) + data->temp8[nr] = TEMP1_TO_REG_ADT7461(val); + else + data->temp8[nr] = TEMP1_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[nr - 1], data->temp8[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP2_FROM_REG(data->temp11[attr->index])); +} + +static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + static const u8 reg[4] = { + LM90_REG_W_REMOTE_LOWH, + LM90_REG_W_REMOTE_LOWL, + LM90_REG_W_REMOTE_HIGHH, + LM90_REG_W_REMOTE_HIGHL, + }; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + + down(&data->update_lock); + if (data->kind == adt7461) + data->temp11[nr] = TEMP2_TO_REG_ADT7461(val); + else + data->temp11[nr] = TEMP2_TO_REG(val); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], + data->temp11[nr] >> 8); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], + data->temp11[nr] & 0xff); + up(&data->update_lock); + return count; +} + +static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index]) + - TEMP1_FROM_REG(data->temp_hyst)); +} + +static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + long hyst; + + down(&data->update_lock); + hyst = TEMP1_FROM_REG(data->temp8[3]) - val; + i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, + HYST_TO_REG(hyst)); + up(&data->update_lock); + return count; +} + +static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, + char *buf) +{ + struct lm90_data *data = lm90_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 1); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 1); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 2); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 2); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 3); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, + set_temp8, 4); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, + set_temphyst, 3); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* + * Real code + */ + +static int lm90_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm90_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm90_data *data; + int err = 0; + const char *name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct lm90_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm90_data)); + + /* The common I2C client data is placed right before the + LM90-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm90_driver; + new_client->flags = 0; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip. A zero kind means that + * the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + + /* Default to an LM90 if forced */ + if (kind == 0) + kind = lm90; + + if (kind < 0) { /* detection and identification */ + u8 man_id, chip_id, reg_config1, reg_convrate; + + man_id = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CHIP_ID); + reg_config1 = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONFIG1); + reg_convrate = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONVRATE); + + if (man_id == 0x01) { /* National Semiconductor */ + u8 reg_config2; + + reg_config2 = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONFIG2); + + if ((reg_config1 & 0x2A) == 0x00 + && (reg_config2 & 0xF8) == 0x00 + && reg_convrate <= 0x09) { + if (address == 0x4C + && (chip_id & 0xF0) == 0x20) { /* LM90 */ + kind = lm90; + } else + if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */ + kind = lm99; + } else + if (address == 0x4C + && (chip_id & 0xF0) == 0x10) { /* LM86 */ + kind = lm86; + } + } + } else + if (man_id == 0x41) { /* Analog Devices */ + if (address == 0x4C + && (chip_id & 0xF0) == 0x40 /* ADM1032 */ + && (reg_config1 & 0x3F) == 0x00 + && reg_convrate <= 0x0A) { + kind = adm1032; + } else + if (address == 0x4c + && chip_id == 0x51 /* ADT7461 */ + && (reg_config1 & 0x1F) == 0x00 /* check compat mode */ + && reg_convrate <= 0x0A) { + kind = adt7461; + } + } else + if (man_id == 0x4D) { /* Maxim */ + /* + * The Maxim variants do NOT have a chip_id register. + * Reading from that address will return the last read + * value, which in our case is those of the man_id + * register. Likewise, the config1 register seems to + * lack a low nibble, so the value will be those of the + * previous read, so in our case those of the man_id + * register. + */ + if (chip_id == man_id + && (reg_config1 & 0x1F) == (man_id & 0x0F) + && reg_convrate <= 0x09) { + kind = max6657; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%02X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + } + + if (kind == lm90) { + name = "lm90"; + } else if (kind == adm1032) { + name = "adm1032"; + } else if (kind == lm99) { + name = "lm99"; + } else if (kind == lm86) { + name = "lm86"; + } else if (kind == max6657) { + name = "max6657"; + } else if (kind == adt7461) { + name = "adt7461"; + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + data->kind = kind; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the LM90 chip */ + lm90_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit_hyst.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit_hyst.dev_attr); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static void lm90_init_client(struct i2c_client *client) +{ + u8 config; + + /* + * Start the conversions. + */ + i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, + 5); /* 2 Hz */ + config = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1); + if (config & 0x40) + i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, + config & 0xBF); /* run */ +} + +static int lm90_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static struct lm90_data *lm90_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm90_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + u8 oldh, newh; + + dev_dbg(&client->dev, "Updating lm90 data.\n"); + data->temp8[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_TEMP); + data->temp8[1] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_LOW); + data->temp8[2] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_HIGH); + data->temp8[3] = i2c_smbus_read_byte_data(client, + LM90_REG_R_LOCAL_CRIT); + data->temp8[4] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_CRIT); + data->temp_hyst = i2c_smbus_read_byte_data(client, + LM90_REG_R_TCRIT_HYST); + + /* + * There is a trick here. We have to read two registers to + * have the remote sensor temperature, but we have to beware + * a conversion could occur inbetween the readings. The + * datasheet says we should either use the one-shot + * conversion register, which we don't want to do (disables + * hardware monitoring) or monitor the busy bit, which is + * impossible (we can't read the values and monitor that bit + * at the exact same time). So the solution used here is to + * read the high byte once, then the low byte, then the high + * byte again. If the new high byte matches the old one, + * then we have a valid reading. Else we have to read the low + * byte again, and now we believe we have a correct reading. + */ + oldh = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPH); + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPL); + newh = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPH); + if (newh != oldh) { + data->temp11[0] = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPL); +#ifdef DEBUG + oldh = i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_TEMPH); + /* oldh is actually newer */ + if (newh != oldh) + dev_warn(&client->dev, "Remote temperature may be " + "wrong.\n"); +#endif + } + data->temp11[0] |= (newh << 8); + + data->temp11[1] = (i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_LOWH) << 8) + + i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_LOWL); + data->temp11[2] = (i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_HIGHH) << 8) + + i2c_smbus_read_byte_data(client, + LM90_REG_R_REMOTE_HIGHL); + data->alarms = i2c_smbus_read_byte_data(client, + LM90_REG_R_STATUS); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_lm90_init(void) +{ + return i2c_add_driver(&lm90_driver); +} + +static void __exit sensors_lm90_exit(void) +{ + i2c_del_driver(&lm90_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("LM90/ADM1032 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm90_init); +module_exit(sensors_lm90_exit); diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c new file mode 100644 index 00000000000..215c8e40ffd --- /dev/null +++ b/drivers/hwmon/lm92.c @@ -0,0 +1,429 @@ +/* + * lm92 - Hardware monitoring driver + * Copyright (C) 2005 Jean Delvare + * + * Based on the lm90 driver, with some ideas taken from the lm_sensors + * lm92 driver as well. + * + * The LM92 is a sensor chip made by National Semiconductor. It reports + * its own temperature with a 0.0625 deg resolution and a 0.33 deg + * accuracy. Complete datasheet can be obtained from National's website + * at: + * http://www.national.com/pf/LM/LM92.html + * + * This driver also supports the MAX6635 sensor chip made by Maxim. + * This chip is compatible with the LM92, but has a lesser accuracy + * (1.0 deg). Complete datasheet can be obtained from Maxim's website + * at: + * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074 + * + * Since the LM92 was the first chipset supported by this driver, most + * comments will refer to this chipset, but are actually general and + * concern all supported chipsets, unless mentioned otherwise. + * + * Support could easily be added for the National Semiconductor LM76 + * and Maxim MAX6633 and MAX6634 chips, which are mostly compatible + * with the LM92. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + + +/* The LM92 and MAX6635 have 2 two-state pins for address selection, + resulting in 4 possible addresses. */ +static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, + I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(lm92); + +/* The LM92 registers */ +#define LM92_REG_CONFIG 0x01 /* 8-bit, RW */ +#define LM92_REG_TEMP 0x00 /* 16-bit, RO */ +#define LM92_REG_TEMP_HYST 0x02 /* 16-bit, RW */ +#define LM92_REG_TEMP_CRIT 0x03 /* 16-bit, RW */ +#define LM92_REG_TEMP_LOW 0x04 /* 16-bit, RW */ +#define LM92_REG_TEMP_HIGH 0x05 /* 16-bit, RW */ +#define LM92_REG_MAN_ID 0x07 /* 16-bit, RO, LM92 only */ + +/* The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius, + left-justified in 16-bit registers. No rounding is done, with such + a resolution it's just not worth it. Note that the MAX6635 doesn't + make use of the 4 lower bits for limits (i.e. effective resolution + for limits is 1 degree Celsius). */ +static inline int TEMP_FROM_REG(s16 reg) +{ + return reg / 8 * 625 / 10; +} + +static inline s16 TEMP_TO_REG(int val) +{ + if (val <= -60000) + return -60000 * 10 / 625 * 8; + if (val >= 160000) + return 160000 * 10 / 625 * 8; + return val * 10 / 625 * 8; +} + +/* Alarm flags are stored in the 3 LSB of the temperature register */ +static inline u8 ALARMS_FROM_REG(s16 reg) +{ + return reg & 0x0007; +} + +/* Driver data (common to all clients) */ +static struct i2c_driver lm92_driver; + +/* Client data (each client gets its own) */ +struct lm92_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst; +}; + + +/* + * Sysfs attributes and callback functions + */ + +static struct lm92_data *lm92_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm92_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) + || !data->valid) { + dev_dbg(&client->dev, "Updating lm92 data\n"); + data->temp1_input = swab16(i2c_smbus_read_word_data(client, + LM92_REG_TEMP)); + data->temp1_hyst = swab16(i2c_smbus_read_word_data(client, + LM92_REG_TEMP_HYST)); + data->temp1_crit = swab16(i2c_smbus_read_word_data(client, + LM92_REG_TEMP_CRIT)); + data->temp1_min = swab16(i2c_smbus_read_word_data(client, + LM92_REG_TEMP_LOW)); + data->temp1_max = swab16(i2c_smbus_read_word_data(client, + LM92_REG_TEMP_HIGH)); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +#define show_temp(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm92_data *data = lm92_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ +} +show_temp(temp1_input); +show_temp(temp1_crit); +show_temp(temp1_min); +show_temp(temp1_max); + +#define set_temp(value, reg) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm92_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_TO_REG(val); \ + i2c_smbus_write_word_data(client, reg, swab16(data->value)); \ + up(&data->update_lock); \ + return count; \ +} +set_temp(temp1_crit, LM92_REG_TEMP_CRIT); +set_temp(temp1_min, LM92_REG_TEMP_LOW); +set_temp(temp1_max, LM92_REG_TEMP_HIGH); + +static ssize_t show_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm92_data *data = lm92_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit) + - TEMP_FROM_REG(data->temp1_hyst)); +} +static ssize_t show_temp1_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm92_data *data = lm92_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max) + - TEMP_FROM_REG(data->temp1_hyst)); +} +static ssize_t show_temp1_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm92_data *data = lm92_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min) + + TEMP_FROM_REG(data->temp1_hyst)); +} + +static ssize_t set_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm92_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val; + i2c_smbus_write_word_data(client, LM92_REG_TEMP_HYST, + swab16(TEMP_TO_REG(data->temp1_hyst))); + up(&data->update_lock); + return count; +} + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct lm92_data *data = lm92_update_device(dev); + return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input)); +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL); +static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit, + set_temp1_crit); +static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst, + set_temp1_crit_hyst); +static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min, + set_temp1_min); +static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL); +static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max, + set_temp1_max); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + + +/* + * Detection and registration + */ + +static void lm92_init_client(struct i2c_client *client) +{ + u8 config; + + /* Start the conversions if needed */ + config = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); + if (config & 0x01) + i2c_smbus_write_byte_data(client, LM92_REG_CONFIG, + config & 0xFE); +} + +/* The MAX6635 has no identification register, so we have to use tricks + to identify it reliably. This is somewhat slow. + Note that we do NOT rely on the 2 MSB of the configuration register + always reading 0, as suggested by the datasheet, because it was once + reported not to be true. */ +static int max6635_check(struct i2c_client *client) +{ + u16 temp_low, temp_high, temp_hyst, temp_crit; + u8 conf; + int i; + + /* No manufacturer ID register, so a read from this address will + always return the last read value. */ + temp_low = i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW); + if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_low) + return 0; + temp_high = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HIGH); + if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_high) + return 0; + + /* Limits are stored as integer values (signed, 9-bit). */ + if ((temp_low & 0x7f00) || (temp_high & 0x7f00)) + return 0; + temp_hyst = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HYST); + temp_crit = i2c_smbus_read_word_data(client, LM92_REG_TEMP_CRIT); + if ((temp_hyst & 0x7f00) || (temp_crit & 0x7f00)) + return 0; + + /* Registers addresses were found to cycle over 16-byte boundaries. + We don't test all registers with all offsets so as to save some + reads and time, but this should still be sufficient to dismiss + non-MAX6635 chips. */ + conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); + for (i=16; i<96; i*=2) { + if (temp_hyst != i2c_smbus_read_word_data(client, + LM92_REG_TEMP_HYST + i - 16) + || temp_crit != i2c_smbus_read_word_data(client, + LM92_REG_TEMP_CRIT + i) + || temp_low != i2c_smbus_read_word_data(client, + LM92_REG_TEMP_LOW + i + 16) + || temp_high != i2c_smbus_read_word_data(client, + LM92_REG_TEMP_HIGH + i + 32) + || conf != i2c_smbus_read_byte_data(client, + LM92_REG_CONFIG + i)) + return 0; + } + + return 1; +} + +/* The following function does more than just detection. If detection + succeeds, it also registers the new chip. */ +static int lm92_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm92_data *data; + int err = 0; + char *name; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct lm92_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct lm92_data)); + + /* Fill in enough client fields so that we can read from the chip, + which is required for identication */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm92_driver; + new_client->flags = 0; + + /* A negative kind means that the driver was loaded with no force + parameter (default), so we must identify the chip. */ + if (kind < 0) { + u8 config = i2c_smbus_read_byte_data(new_client, + LM92_REG_CONFIG); + u16 man_id = i2c_smbus_read_word_data(new_client, + LM92_REG_MAN_ID); + + if ((config & 0xe0) == 0x00 + && man_id == 0x0180) { + pr_info("lm92: Found National Semiconductor LM92 chip\n"); + kind = lm92; + } else + if (max6635_check(new_client)) { + pr_info("lm92: Found Maxim MAX6635 chip\n"); + kind = lm92; /* No separate prefix */ + } + else + goto exit_free; + } else + if (kind == 0) /* Default to an LM92 if forced */ + kind = lm92; + + /* Give it the proper name */ + if (kind == lm92) { + name = "lm92"; + } else { /* Supposedly cannot happen */ + dev_dbg(&new_client->dev, "Kind out of range?\n"); + goto exit_free; + } + + /* Fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the i2c subsystem a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the chipset */ + lm92_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int lm92_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, lm92_detect); +} + +static int lm92_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + + +/* + * Module and driver stuff + */ + +static struct i2c_driver lm92_driver = { + .owner = THIS_MODULE, + .name = "lm92", + .id = I2C_DRIVERID_LM92, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm92_attach_adapter, + .detach_client = lm92_detach_client, +}; + +static int __init sensors_lm92_init(void) +{ + return i2c_add_driver(&lm92_driver); +} + +static void __exit sensors_lm92_exit(void) +{ + i2c_del_driver(&lm92_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("LM92/MAX6635 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm92_init); +module_exit(sensors_lm92_exit); diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c new file mode 100644 index 00000000000..bf553dcd97d --- /dev/null +++ b/drivers/hwmon/max1619.c @@ -0,0 +1,372 @@ +/* + * max1619.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2003-2004 Alexey Fisher + * Jean Delvare + * + * Based on the lm90 driver. The MAX1619 is a sensor chip made by Maxim. + * It reports up to two temperatures (its own plus up to + * one external one). Complete datasheet can be + * obtained from Maxim's website at: + * http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include + + +static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, + 0x29, 0x2a, 0x2b, + 0x4c, 0x4d, 0x4e, + I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(max1619); + +/* + * The MAX1619 registers + */ + +#define MAX1619_REG_R_MAN_ID 0xFE +#define MAX1619_REG_R_CHIP_ID 0xFF +#define MAX1619_REG_R_CONFIG 0x03 +#define MAX1619_REG_W_CONFIG 0x09 +#define MAX1619_REG_R_CONVRATE 0x04 +#define MAX1619_REG_W_CONVRATE 0x0A +#define MAX1619_REG_R_STATUS 0x02 +#define MAX1619_REG_R_LOCAL_TEMP 0x00 +#define MAX1619_REG_R_REMOTE_TEMP 0x01 +#define MAX1619_REG_R_REMOTE_HIGH 0x07 +#define MAX1619_REG_W_REMOTE_HIGH 0x0D +#define MAX1619_REG_R_REMOTE_LOW 0x08 +#define MAX1619_REG_W_REMOTE_LOW 0x0E +#define MAX1619_REG_R_REMOTE_CRIT 0x10 +#define MAX1619_REG_W_REMOTE_CRIT 0x12 +#define MAX1619_REG_R_TCRIT_HYST 0x11 +#define MAX1619_REG_W_TCRIT_HYST 0x13 + +/* + * Conversions and various macros + */ + +#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000) +#define TEMP_TO_REG(val) ((val < 0 ? val+0x100*1000 : val) / 1000) + +/* + * Functions declaration + */ + +static int max1619_attach_adapter(struct i2c_adapter *adapter); +static int max1619_detect(struct i2c_adapter *adapter, int address, + int kind); +static void max1619_init_client(struct i2c_client *client); +static int max1619_detach_client(struct i2c_client *client); +static struct max1619_data *max1619_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver max1619_driver = { + .owner = THIS_MODULE, + .name = "max1619", + .flags = I2C_DF_NOTIFY, + .attach_adapter = max1619_attach_adapter, + .detach_client = max1619_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct max1619_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + u8 temp_input1; /* local */ + u8 temp_input2, temp_low2, temp_high2; /* remote */ + u8 temp_crit2; + u8 temp_hyst2; + u8 alarms; +}; + +/* + * Sysfs stuff + */ + +#define show_temp(value) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct max1619_data *data = max1619_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ +} +show_temp(temp_input1); +show_temp(temp_input2); +show_temp(temp_low2); +show_temp(temp_high2); +show_temp(temp_crit2); +show_temp(temp_hyst2); + +#define set_temp2(value, reg) \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct max1619_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->value = TEMP_TO_REG(val); \ + i2c_smbus_write_byte_data(client, reg, data->value); \ + up(&data->update_lock); \ + return count; \ +} + +set_temp2(temp_low2, MAX1619_REG_W_REMOTE_LOW); +set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH); +set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT); +set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST); + +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct max1619_data *data = max1619_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); +static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); +static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, + set_temp_low2); +static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, + set_temp_high2); +static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, + set_temp_crit2); +static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2, + set_temp_hyst2); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* + * Real code + */ + +static int max1619_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, max1619_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct max1619_data *data; + int err = 0; + const char *name = ""; + u8 reg_config=0, reg_convrate=0, reg_status=0; + u8 man_id, chip_id; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct max1619_data)); + + /* The common I2C client data is placed right before the + MAX1619-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &max1619_driver; + new_client->flags = 0; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip. A zero kind means that + * the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + if (kind < 0) { /* detection */ + reg_config = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CONFIG); + reg_convrate = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CONVRATE); + reg_status = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_STATUS); + if ((reg_config & 0x03) != 0x00 + || reg_convrate > 0x07 || (reg_status & 0x61 ) !=0x00) { + dev_dbg(&adapter->dev, + "MAX1619 detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + + man_id = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CHIP_ID); + + if ((man_id == 0x4D) && (chip_id == 0x04)){ + kind = max1619; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%02X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + + + if (kind == max1619){ + name = "max1619"; + } + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the MAX1619 chip */ + max1619_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp2_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static void max1619_init_client(struct i2c_client *client) +{ + u8 config; + + /* + * Start the conversions. + */ + i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, + 5); /* 2 Hz */ + config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); + if (config & 0x40) + i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, + config & 0xBF); /* run */ +} + +static int max1619_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static struct max1619_data *max1619_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max1619_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + dev_dbg(&client->dev, "Updating max1619 data.\n"); + data->temp_input1 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_LOCAL_TEMP); + data->temp_input2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_TEMP); + data->temp_high2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_HIGH); + data->temp_low2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_LOW); + data->temp_crit2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_CRIT); + data->temp_hyst2 = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_TCRIT_HYST); + data->alarms = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_STATUS); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_max1619_init(void) +{ + return i2c_add_driver(&max1619_driver); +} + +static void __exit sensors_max1619_exit(void) +{ + i2c_del_driver(&max1619_driver); +} + +MODULE_AUTHOR("Alexey Fisher and" + "Jean Delvare "); +MODULE_DESCRIPTION("MAX1619 sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_max1619_init); +module_exit(sensors_max1619_exit); diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c new file mode 100644 index 00000000000..876c68f3af3 --- /dev/null +++ b/drivers/hwmon/pc87360.c @@ -0,0 +1,1348 @@ +/* + * pc87360.c - Part of lm_sensors, Linux kernel modules + * for hardware monitoring + * Copyright (C) 2004 Jean Delvare + * + * Copied from smsc47m1.c: + * Copyright (C) 2002 Mark D. Studebaker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Supports the following chips: + * + * Chip #vin #fan #pwm #temp devid + * PC87360 - 2 2 - 0xE1 + * PC87363 - 2 2 - 0xE8 + * PC87364 - 3 3 - 0xE4 + * PC87365 11 3 3 2 0xE5 + * PC87366 11 3 3 3-4 0xE9 + * + * This driver assumes that no more than one chip is present, and one of + * the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; +static struct i2c_force_data forces[] = {{ NULL }}; +static u8 devid; +static unsigned int extra_isa[3]; +static u8 confreg[4]; + +enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 }; +static struct i2c_address_data addr_data = { + .normal_i2c = normal_i2c, + .normal_isa = normal_isa, + .forces = forces, +}; + +static int init = 1; +module_param(init, int, 0); +MODULE_PARM_DESC(init, + "Chip initialization level:\n" + " 0: None\n" + "*1: Forcibly enable internal voltage and temperature channels, except in9\n" + " 2: Forcibly enable all voltage and temperature channels, except in9\n" + " 3: Forcibly enable all voltage and temperature channels, including in9"); + +/* + * Super-I/O registers and operations + */ + +#define DEV 0x07 /* Register: Logical device select */ +#define DEVID 0x20 /* Register: Device ID */ +#define ACT 0x30 /* Register: Device activation */ +#define BASE 0x60 /* Register: Base address */ + +#define FSCM 0x09 /* Logical device: fans */ +#define VLM 0x0d /* Logical device: voltages */ +#define TMS 0x0e /* Logical device: temperatures */ +static const u8 logdev[3] = { FSCM, VLM, TMS }; + +#define LD_FAN 0 +#define LD_IN 1 +#define LD_TEMP 2 + +static inline void superio_outb(int sioaddr, int reg, int val) +{ + outb(reg, sioaddr); + outb(val, sioaddr+1); +} + +static inline int superio_inb(int sioaddr, int reg) +{ + outb(reg, sioaddr); + return inb(sioaddr+1); +} + +static inline void superio_exit(int sioaddr) +{ + outb(0x02, sioaddr); + outb(0x02, sioaddr+1); +} + +/* + * Logical devices + */ + +#define PC87360_EXTENT 0x10 +#define PC87365_REG_BANK 0x09 +#define NO_BANK 0xff + +/* + * Fan registers and conversions + */ + +/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */ +#define PC87360_REG_PRESCALE(nr) (0x00 + 2 * (nr)) +#define PC87360_REG_PWM(nr) (0x01 + 2 * (nr)) +#define PC87360_REG_FAN_MIN(nr) (0x06 + 3 * (nr)) +#define PC87360_REG_FAN(nr) (0x07 + 3 * (nr)) +#define PC87360_REG_FAN_STATUS(nr) (0x08 + 3 * (nr)) + +#define FAN_FROM_REG(val,div) ((val) == 0 ? 0: \ + 480000 / ((val)*(div))) +#define FAN_TO_REG(val,div) ((val) <= 100 ? 0 : \ + 480000 / ((val)*(div))) +#define FAN_DIV_FROM_REG(val) (1 << ((val >> 5) & 0x03)) +#define FAN_STATUS_FROM_REG(val) ((val) & 0x07) + +#define FAN_CONFIG_MONITOR(val,nr) (((val) >> (2 + nr * 3)) & 1) +#define FAN_CONFIG_CONTROL(val,nr) (((val) >> (3 + nr * 3)) & 1) +#define FAN_CONFIG_INVERT(val,nr) (((val) >> (4 + nr * 3)) & 1) + +#define PWM_FROM_REG(val,inv) ((inv) ? 255 - (val) : (val)) +static inline u8 PWM_TO_REG(int val, int inv) +{ + if (inv) + val = 255 - val; + if (val < 0) + return 0; + if (val > 255) + return 255; + return val; +} + +/* + * Voltage registers and conversions + */ + +#define PC87365_REG_IN_CONVRATE 0x07 +#define PC87365_REG_IN_CONFIG 0x08 +#define PC87365_REG_IN 0x0B +#define PC87365_REG_IN_MIN 0x0D +#define PC87365_REG_IN_MAX 0x0C +#define PC87365_REG_IN_STATUS 0x0A +#define PC87365_REG_IN_ALARMS1 0x00 +#define PC87365_REG_IN_ALARMS2 0x01 +#define PC87365_REG_VID 0x06 + +#define IN_FROM_REG(val,ref) (((val) * (ref) + 128) / 256) +#define IN_TO_REG(val,ref) ((val) < 0 ? 0 : \ + (val)*256 >= (ref)*255 ? 255: \ + ((val) * 256 + (ref)/2) / (ref)) + +/* + * Temperature registers and conversions + */ + +#define PC87365_REG_TEMP_CONFIG 0x08 +#define PC87365_REG_TEMP 0x0B +#define PC87365_REG_TEMP_MIN 0x0D +#define PC87365_REG_TEMP_MAX 0x0C +#define PC87365_REG_TEMP_CRIT 0x0E +#define PC87365_REG_TEMP_STATUS 0x0A +#define PC87365_REG_TEMP_ALARMS 0x00 + +#define TEMP_FROM_REG(val) ((val) * 1000) +#define TEMP_TO_REG(val) ((val) < -55000 ? -55 : \ + (val) > 127000 ? 127 : \ + (val) < 0 ? ((val) - 500) / 1000 : \ + ((val) + 500) / 1000) + +/* + * Client data (each client gets its own) + */ + +struct pc87360_data { + struct i2c_client client; + struct semaphore lock; + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + int address[3]; + + u8 fannr, innr, tempnr; + + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u8 fan_status[3]; /* Register value */ + u8 pwm[3]; /* Register value */ + u16 fan_conf; /* Configuration register values, combined */ + + u16 in_vref; /* 1 mV/bit */ + u8 in[14]; /* Register value */ + u8 in_min[14]; /* Register value */ + u8 in_max[14]; /* Register value */ + u8 in_crit[3]; /* Register value */ + u8 in_status[14]; /* Register value */ + u16 in_alarms; /* Register values, combined, masked */ + u8 vid_conf; /* Configuration register value */ + u8 vrm; + u8 vid; /* Register value */ + + s8 temp[3]; /* Register value */ + s8 temp_min[3]; /* Register value */ + s8 temp_max[3]; /* Register value */ + s8 temp_crit[3]; /* Register value */ + u8 temp_status[3]; /* Register value */ + u8 temp_alarms; /* Register value, masked */ +}; + +/* + * Functions declaration + */ + +static int pc87360_attach_adapter(struct i2c_adapter *adapter); +static int pc87360_detect(struct i2c_adapter *adapter, int address, int kind); +static int pc87360_detach_client(struct i2c_client *client); + +static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, + u8 reg); +static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, + u8 reg, u8 value); +static void pc87360_init_client(struct i2c_client *client, int use_thermistors); +static struct pc87360_data *pc87360_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver pc87360_driver = { + .owner = THIS_MODULE, + .name = "pc87360", + .flags = I2C_DF_NOTIFY, + .attach_adapter = pc87360_attach_adapter, + .detach_client = pc87360_detach_client, +}; + +/* + * Sysfs stuff + */ + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pc87360_data *data = i2c_get_clientdata(client); + long fan_min = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[nr])); + + /* If it wouldn't fit, change clock divisor */ + while (fan_min > 255 + && (data->fan_status[nr] & 0x60) != 0x60) { + fan_min >>= 1; + data->fan[nr] >>= 1; + data->fan_status[nr] += 0x20; + } + data->fan_min[nr] = fan_min > 255 ? 255 : fan_min; + pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(nr), + data->fan_min[nr]); + + /* Write new divider, preserve alarm bits */ + pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(nr), + data->fan_status[nr] & 0xF9); + up(&data->update_lock); + + return count; +} + +#define show_and_set_fan(offset) \ +static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[offset-1], \ + FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \ +} \ +static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[offset-1], \ + FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \ +} \ +static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", \ + FAN_DIV_FROM_REG(data->fan_status[offset-1])); \ +} \ +static ssize_t show_fan##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", \ + FAN_STATUS_FROM_REG(data->fan_status[offset-1])); \ +} \ +static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan##offset##_input, NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \ + show_fan##offset##_min, set_fan##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ + show_fan##offset##_div, NULL); \ +static DEVICE_ATTR(fan##offset##_status, S_IRUGO, \ + show_fan##offset##_status, NULL); +show_and_set_fan(1) +show_and_set_fan(2) +show_and_set_fan(3) + +#define show_and_set_pwm(offset) \ +static ssize_t show_pwm##offset(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", \ + PWM_FROM_REG(data->pwm[offset-1], \ + FAN_CONFIG_INVERT(data->fan_conf, \ + offset-1))); \ +} \ +static ssize_t set_pwm##offset(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->pwm[offset-1] = PWM_TO_REG(val, \ + FAN_CONFIG_INVERT(data->fan_conf, offset-1)); \ + pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(offset-1), \ + data->pwm[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \ + show_pwm##offset, set_pwm##offset); +show_and_set_pwm(1) +show_and_set_pwm(2) +show_and_set_pwm(3) + +#define show_and_set_in(offset) \ +static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ + data->in_vref)); \ +} \ +static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ + data->in_vref)); \ +} \ +static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ + data->in_vref)); \ +} \ +static ssize_t show_in##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", data->in_status[offset]); \ +} \ +static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_min[offset] = IN_TO_REG(val, data->in_vref); \ + pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MIN, \ + data->in_min[offset]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_max[offset] = IN_TO_REG(val, \ + data->in_vref); \ + pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MAX, \ + data->in_max[offset]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in##offset##_input, NULL); \ +static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ + show_in##offset##_max, set_in##offset##_max); \ +static DEVICE_ATTR(in##offset##_status, S_IRUGO, \ + show_in##offset##_status, NULL); +show_and_set_in(0) +show_and_set_in(1) +show_and_set_in(2) +show_and_set_in(3) +show_and_set_in(4) +show_and_set_in(5) +show_and_set_in(6) +show_and_set_in(7) +show_and_set_in(8) +show_and_set_in(9) +show_and_set_in(10) + +#define show_and_set_therm(offset) \ +static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset+7], \ + data->in_vref)); \ +} \ +static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset+7], \ + data->in_vref)); \ +} \ +static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset+7], \ + data->in_vref)); \ +} \ +static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[offset-4], \ + data->in_vref)); \ +} \ +static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%u\n", data->in_status[offset+7]); \ +} \ +static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_min[offset+7] = IN_TO_REG(val, data->in_vref); \ + pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MIN, \ + data->in_min[offset+7]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_max[offset+7] = IN_TO_REG(val, data->in_vref); \ + pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MAX, \ + data->in_max[offset+7]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_crit[offset-4] = IN_TO_REG(val, data->in_vref); \ + pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_CRIT, \ + data->in_crit[offset-4]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp##offset##_input, NULL); \ +static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ + show_temp##offset##_min, set_temp##offset##_min); \ +static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ + show_temp##offset##_max, set_temp##offset##_max); \ +static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \ + show_temp##offset##_crit, set_temp##offset##_crit); \ +static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \ + show_temp##offset##_status, NULL); +show_and_set_therm(4) +show_and_set_therm(5) +show_and_set_therm(6) + +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", data->vrm); +} +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pc87360_data *data = i2c_get_clientdata(client); + data->vrm = simple_strtoul(buf, NULL, 10); + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); + +static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", data->in_alarms); +} +static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); + +#define show_and_set_temp(offset) \ +static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ +} \ +static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ +} \ +static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ +}\ +static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[offset-1])); \ +}\ +static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct pc87360_data *data = pc87360_update_device(dev); \ + return sprintf(buf, "%d\n", data->temp_status[offset-1]); \ +}\ +static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp_min[offset-1] = TEMP_TO_REG(val); \ + pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MIN, \ + data->temp_min[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp_max[offset-1] = TEMP_TO_REG(val); \ + pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MAX, \ + data->temp_max[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \ + size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct pc87360_data *data = i2c_get_clientdata(client); \ + long val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp_crit[offset-1] = TEMP_TO_REG(val); \ + pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_CRIT, \ + data->temp_crit[offset-1]); \ + up(&data->update_lock); \ + return count; \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp##offset##_input, NULL); \ +static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ + show_temp##offset##_min, set_temp##offset##_min); \ +static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ + show_temp##offset##_max, set_temp##offset##_max); \ +static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \ + show_temp##offset##_crit, set_temp##offset##_crit); \ +static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \ + show_temp##offset##_status, NULL); +show_and_set_temp(1) +show_and_set_temp(2) +show_and_set_temp(3) + +static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", data->temp_alarms); +} +static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL); + +/* + * Device detection, registration and update + */ + +static int pc87360_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, pc87360_detect); +} + +static int pc87360_find(int sioaddr, u8 *devid, int *address) +{ + u16 val; + int i; + int nrdev; /* logical device count */ + + /* No superio_enter */ + + /* Identify device */ + val = superio_inb(sioaddr, DEVID); + switch (val) { + case 0xE1: /* PC87360 */ + case 0xE8: /* PC87363 */ + case 0xE4: /* PC87364 */ + nrdev = 1; + break; + case 0xE5: /* PC87365 */ + case 0xE9: /* PC87366 */ + nrdev = 3; + break; + default: + superio_exit(sioaddr); + return -ENODEV; + } + /* Remember the device id */ + *devid = val; + + for (i = 0; i < nrdev; i++) { + /* select logical device */ + superio_outb(sioaddr, DEV, logdev[i]); + + val = superio_inb(sioaddr, ACT); + if (!(val & 0x01)) { + printk(KERN_INFO "pc87360: Device 0x%02x not " + "activated\n", logdev[i]); + continue; + } + + val = (superio_inb(sioaddr, BASE) << 8) + | superio_inb(sioaddr, BASE + 1); + if (!val) { + printk(KERN_INFO "pc87360: Base address not set for " + "device 0x%02x\n", logdev[i]); + continue; + } + + address[i] = val; + + if (i==0) { /* Fans */ + confreg[0] = superio_inb(sioaddr, 0xF0); + confreg[1] = superio_inb(sioaddr, 0xF1); + +#ifdef DEBUG + printk(KERN_DEBUG "pc87360: Fan 1: mon=%d " + "ctrl=%d inv=%d\n", (confreg[0]>>2)&1, + (confreg[0]>>3)&1, (confreg[0]>>4)&1); + printk(KERN_DEBUG "pc87360: Fan 2: mon=%d " + "ctrl=%d inv=%d\n", (confreg[0]>>5)&1, + (confreg[0]>>6)&1, (confreg[0]>>7)&1); + printk(KERN_DEBUG "pc87360: Fan 3: mon=%d " + "ctrl=%d inv=%d\n", confreg[1]&1, + (confreg[1]>>1)&1, (confreg[1]>>2)&1); +#endif + } else if (i==1) { /* Voltages */ + /* Are we using thermistors? */ + if (*devid == 0xE9) { /* PC87366 */ + /* These registers are not logical-device + specific, just that we won't need them if + we don't use the VLM device */ + confreg[2] = superio_inb(sioaddr, 0x2B); + confreg[3] = superio_inb(sioaddr, 0x25); + + if (confreg[2] & 0x40) { + printk(KERN_INFO "pc87360: Using " + "thermistors for temperature " + "monitoring\n"); + } + if (confreg[3] & 0xE0) { + printk(KERN_INFO "pc87360: VID " + "inputs routed (mode %u)\n", + confreg[3] >> 5); + } + } + } + } + + superio_exit(sioaddr); + return 0; +} + +/* We don't really care about the address. + Read from extra_isa instead. */ +int pc87360_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i; + struct i2c_client *new_client; + struct pc87360_data *data; + int err = 0; + const char *name = "pc87360"; + int use_thermistors = 0; + + if (!i2c_is_isa_adapter(adapter)) + return -ENODEV; + + if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL))) + return -ENOMEM; + memset(data, 0x00, sizeof(struct pc87360_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &pc87360_driver; + new_client->flags = 0; + + data->fannr = 2; + data->innr = 0; + data->tempnr = 0; + + switch (devid) { + case 0xe8: + name = "pc87363"; + break; + case 0xe4: + name = "pc87364"; + data->fannr = 3; + break; + case 0xe5: + name = "pc87365"; + data->fannr = extra_isa[0] ? 3 : 0; + data->innr = extra_isa[1] ? 11 : 0; + data->tempnr = extra_isa[2] ? 2 : 0; + break; + case 0xe9: + name = "pc87366"; + data->fannr = extra_isa[0] ? 3 : 0; + data->innr = extra_isa[1] ? 14 : 0; + data->tempnr = extra_isa[2] ? 3 : 0; + break; + } + + strcpy(new_client->name, name); + data->valid = 0; + init_MUTEX(&data->update_lock); + + for (i = 0; i < 3; i++) { + if (((data->address[i] = extra_isa[i])) + && !request_region(extra_isa[i], PC87360_EXTENT, + pc87360_driver.name)) { + dev_err(&new_client->dev, "Region 0x%x-0x%x already " + "in use!\n", extra_isa[i], + extra_isa[i]+PC87360_EXTENT-1); + for (i--; i >= 0; i--) + release_region(extra_isa[i], PC87360_EXTENT); + err = -EBUSY; + goto ERROR1; + } + } + + /* Retrieve the fans configuration from Super-I/O space */ + if (data->fannr) + data->fan_conf = confreg[0] | (confreg[1] << 8); + + if ((err = i2c_attach_client(new_client))) + goto ERROR2; + + /* Use the correct reference voltage + Unless both the VLM and the TMS logical devices agree to + use an external Vref, the internal one is used. */ + if (data->innr) { + i = pc87360_read_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONFIG); + if (data->tempnr) { + i &= pc87360_read_value(data, LD_TEMP, NO_BANK, + PC87365_REG_TEMP_CONFIG); + } + data->in_vref = (i&0x02) ? 3025 : 2966; + dev_dbg(&new_client->dev, "Using %s reference voltage\n", + (i&0x02) ? "external" : "internal"); + + data->vid_conf = confreg[3]; + data->vrm = 90; + } + + /* Fan clock dividers may be needed before any data is read */ + for (i = 0; i < data->fannr; i++) { + if (FAN_CONFIG_MONITOR(data->fan_conf, i)) + data->fan_status[i] = pc87360_read_value(data, + LD_FAN, NO_BANK, + PC87360_REG_FAN_STATUS(i)); + } + + if (init > 0) { + if (devid == 0xe9 && data->address[1]) /* PC87366 */ + use_thermistors = confreg[2] & 0x40; + + pc87360_init_client(new_client, use_thermistors); + } + + /* Register sysfs hooks */ + if (data->innr) { + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in5_input); + device_create_file(&new_client->dev, &dev_attr_in6_input); + device_create_file(&new_client->dev, &dev_attr_in7_input); + device_create_file(&new_client->dev, &dev_attr_in8_input); + device_create_file(&new_client->dev, &dev_attr_in9_input); + device_create_file(&new_client->dev, &dev_attr_in10_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in5_min); + device_create_file(&new_client->dev, &dev_attr_in6_min); + device_create_file(&new_client->dev, &dev_attr_in7_min); + device_create_file(&new_client->dev, &dev_attr_in8_min); + device_create_file(&new_client->dev, &dev_attr_in9_min); + device_create_file(&new_client->dev, &dev_attr_in10_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_in5_max); + device_create_file(&new_client->dev, &dev_attr_in6_max); + device_create_file(&new_client->dev, &dev_attr_in7_max); + device_create_file(&new_client->dev, &dev_attr_in8_max); + device_create_file(&new_client->dev, &dev_attr_in9_max); + device_create_file(&new_client->dev, &dev_attr_in10_max); + device_create_file(&new_client->dev, &dev_attr_in0_status); + device_create_file(&new_client->dev, &dev_attr_in1_status); + device_create_file(&new_client->dev, &dev_attr_in2_status); + device_create_file(&new_client->dev, &dev_attr_in3_status); + device_create_file(&new_client->dev, &dev_attr_in4_status); + device_create_file(&new_client->dev, &dev_attr_in5_status); + device_create_file(&new_client->dev, &dev_attr_in6_status); + device_create_file(&new_client->dev, &dev_attr_in7_status); + device_create_file(&new_client->dev, &dev_attr_in8_status); + device_create_file(&new_client->dev, &dev_attr_in9_status); + device_create_file(&new_client->dev, &dev_attr_in10_status); + + device_create_file(&new_client->dev, &dev_attr_cpu0_vid); + device_create_file(&new_client->dev, &dev_attr_vrm); + device_create_file(&new_client->dev, &dev_attr_alarms_in); + } + + if (data->tempnr) { + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp1_min); + device_create_file(&new_client->dev, &dev_attr_temp2_min); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp1_crit); + device_create_file(&new_client->dev, &dev_attr_temp2_crit); + device_create_file(&new_client->dev, &dev_attr_temp1_status); + device_create_file(&new_client->dev, &dev_attr_temp2_status); + + device_create_file(&new_client->dev, &dev_attr_alarms_temp); + } + if (data->tempnr == 3) { + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp3_min); + device_create_file(&new_client->dev, &dev_attr_temp3_max); + device_create_file(&new_client->dev, &dev_attr_temp3_crit); + device_create_file(&new_client->dev, &dev_attr_temp3_status); + } + if (data->innr == 14) { + device_create_file(&new_client->dev, &dev_attr_temp4_input); + device_create_file(&new_client->dev, &dev_attr_temp5_input); + device_create_file(&new_client->dev, &dev_attr_temp6_input); + device_create_file(&new_client->dev, &dev_attr_temp4_min); + device_create_file(&new_client->dev, &dev_attr_temp5_min); + device_create_file(&new_client->dev, &dev_attr_temp6_min); + device_create_file(&new_client->dev, &dev_attr_temp4_max); + device_create_file(&new_client->dev, &dev_attr_temp5_max); + device_create_file(&new_client->dev, &dev_attr_temp6_max); + device_create_file(&new_client->dev, &dev_attr_temp4_crit); + device_create_file(&new_client->dev, &dev_attr_temp5_crit); + device_create_file(&new_client->dev, &dev_attr_temp6_crit); + device_create_file(&new_client->dev, &dev_attr_temp4_status); + device_create_file(&new_client->dev, &dev_attr_temp5_status); + device_create_file(&new_client->dev, &dev_attr_temp6_status); + } + + if (data->fannr) { + if (FAN_CONFIG_MONITOR(data->fan_conf, 0)) { + device_create_file(&new_client->dev, + &dev_attr_fan1_input); + device_create_file(&new_client->dev, + &dev_attr_fan1_min); + device_create_file(&new_client->dev, + &dev_attr_fan1_div); + device_create_file(&new_client->dev, + &dev_attr_fan1_status); + } + + if (FAN_CONFIG_MONITOR(data->fan_conf, 1)) { + device_create_file(&new_client->dev, + &dev_attr_fan2_input); + device_create_file(&new_client->dev, + &dev_attr_fan2_min); + device_create_file(&new_client->dev, + &dev_attr_fan2_div); + device_create_file(&new_client->dev, + &dev_attr_fan2_status); + } + + if (FAN_CONFIG_CONTROL(data->fan_conf, 0)) + device_create_file(&new_client->dev, &dev_attr_pwm1); + if (FAN_CONFIG_CONTROL(data->fan_conf, 1)) + device_create_file(&new_client->dev, &dev_attr_pwm2); + } + if (data->fannr == 3) { + if (FAN_CONFIG_MONITOR(data->fan_conf, 2)) { + device_create_file(&new_client->dev, + &dev_attr_fan3_input); + device_create_file(&new_client->dev, + &dev_attr_fan3_min); + device_create_file(&new_client->dev, + &dev_attr_fan3_div); + device_create_file(&new_client->dev, + &dev_attr_fan3_status); + } + + if (FAN_CONFIG_CONTROL(data->fan_conf, 2)) + device_create_file(&new_client->dev, &dev_attr_pwm3); + } + + return 0; + +ERROR2: + for (i = 0; i < 3; i++) { + if (data->address[i]) { + release_region(data->address[i], PC87360_EXTENT); + } + } +ERROR1: + kfree(data); + return err; +} + +static int pc87360_detach_client(struct i2c_client *client) +{ + struct pc87360_data *data = i2c_get_clientdata(client); + int i; + + if ((i = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return i; + } + + for (i = 0; i < 3; i++) { + if (data->address[i]) { + release_region(data->address[i], PC87360_EXTENT); + } + } + kfree(data); + + return 0; +} + +/* ldi is the logical device index + bank is for voltages and temperatures only */ +static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, + u8 reg) +{ + int res; + + down(&(data->lock)); + if (bank != NO_BANK) + outb_p(bank, data->address[ldi] + PC87365_REG_BANK); + res = inb_p(data->address[ldi] + reg); + up(&(data->lock)); + + return res; +} + +static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, + u8 reg, u8 value) +{ + down(&(data->lock)); + if (bank != NO_BANK) + outb_p(bank, data->address[ldi] + PC87365_REG_BANK); + outb_p(value, data->address[ldi] + reg); + up(&(data->lock)); +} + +static void pc87360_init_client(struct i2c_client *client, int use_thermistors) +{ + struct pc87360_data *data = i2c_get_clientdata(client); + int i, nr; + const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; + const u8 init_temp[3] = { 2, 2, 1 }; + u8 reg; + + if (init >= 2 && data->innr) { + reg = pc87360_read_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONVRATE); + dev_info(&client->dev, "VLM conversion set to" + "1s period, 160us delay\n"); + pc87360_write_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONVRATE, + (reg & 0xC0) | 0x11); + } + + nr = data->innr < 11 ? data->innr : 11; + for (i=0; i= init_in[i]) { + /* Forcibly enable voltage channel */ + reg = pc87360_read_value(data, LD_IN, i, + PC87365_REG_IN_STATUS); + if (!(reg & 0x01)) { + dev_dbg(&client->dev, "Forcibly " + "enabling in%d\n", i); + pc87360_write_value(data, LD_IN, i, + PC87365_REG_IN_STATUS, + (reg & 0x68) | 0x87); + } + } + } + + /* We can't blindly trust the Super-I/O space configuration bit, + most BIOS won't set it properly */ + for (i=11; iinnr; i++) { + reg = pc87360_read_value(data, LD_IN, i, + PC87365_REG_TEMP_STATUS); + use_thermistors = use_thermistors || (reg & 0x01); + } + + i = use_thermistors ? 2 : 0; + for (; itempnr; i++) { + if (init >= init_temp[i]) { + /* Forcibly enable temperature channel */ + reg = pc87360_read_value(data, LD_TEMP, i, + PC87365_REG_TEMP_STATUS); + if (!(reg & 0x01)) { + dev_dbg(&client->dev, "Forcibly " + "enabling temp%d\n", i+1); + pc87360_write_value(data, LD_TEMP, i, + PC87365_REG_TEMP_STATUS, + 0xCF); + } + } + } + + if (use_thermistors) { + for (i=11; iinnr; i++) { + if (init >= init_in[i]) { + /* The pin may already be used by thermal + diodes */ + reg = pc87360_read_value(data, LD_TEMP, + (i-11)/2, PC87365_REG_TEMP_STATUS); + if (reg & 0x01) { + dev_dbg(&client->dev, "Skipping " + "temp%d, pin already in use " + "by temp%d\n", i-7, (i-11)/2); + continue; + } + + /* Forcibly enable thermistor channel */ + reg = pc87360_read_value(data, LD_IN, i, + PC87365_REG_IN_STATUS); + if (!(reg & 0x01)) { + dev_dbg(&client->dev, "Forcibly " + "enabling temp%d\n", i-7); + pc87360_write_value(data, LD_IN, i, + PC87365_REG_TEMP_STATUS, + (reg & 0x60) | 0x8F); + } + } + } + } + + if (data->innr) { + reg = pc87360_read_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONFIG); + if (reg & 0x01) { + dev_dbg(&client->dev, "Forcibly " + "enabling monitoring (VLM)\n"); + pc87360_write_value(data, LD_IN, NO_BANK, + PC87365_REG_IN_CONFIG, + reg & 0xFE); + } + } + + if (data->tempnr) { + reg = pc87360_read_value(data, LD_TEMP, NO_BANK, + PC87365_REG_TEMP_CONFIG); + if (reg & 0x01) { + dev_dbg(&client->dev, "Forcibly enabling " + "monitoring (TMS)\n"); + pc87360_write_value(data, LD_TEMP, NO_BANK, + PC87365_REG_TEMP_CONFIG, + reg & 0xFE); + } + + if (init >= 2) { + /* Chip config as documented by National Semi. */ + pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08); + /* We voluntarily omit the bank here, in case the + sequence itself matters. It shouldn't be a problem, + since nobody else is supposed to access the + device at that point. */ + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04); + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35); + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05); + pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05); + } + } +} + +static void pc87360_autodiv(struct i2c_client *client, int nr) +{ + struct pc87360_data *data = i2c_get_clientdata(client); + u8 old_min = data->fan_min[nr]; + + /* Increase clock divider if needed and possible */ + if ((data->fan_status[nr] & 0x04) /* overflow flag */ + || (data->fan[nr] >= 224)) { /* next to overflow */ + if ((data->fan_status[nr] & 0x60) != 0x60) { + data->fan_status[nr] += 0x20; + data->fan_min[nr] >>= 1; + data->fan[nr] >>= 1; + dev_dbg(&client->dev, "Increasing " + "clock divider to %d for fan %d\n", + FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1); + } + } else { + /* Decrease clock divider if possible */ + while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */ + && data->fan[nr] < 85 /* bad accuracy */ + && (data->fan_status[nr] & 0x60) != 0x00) { + data->fan_status[nr] -= 0x20; + data->fan_min[nr] <<= 1; + data->fan[nr] <<= 1; + dev_dbg(&client->dev, "Decreasing " + "clock divider to %d for fan %d\n", + FAN_DIV_FROM_REG(data->fan_status[nr]), + nr+1); + } + } + + /* Write new fan min if it changed */ + if (old_min != data->fan_min[nr]) { + pc87360_write_value(data, LD_FAN, NO_BANK, + PC87360_REG_FAN_MIN(nr), + data->fan_min[nr]); + } +} + +static struct pc87360_data *pc87360_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pc87360_data *data = i2c_get_clientdata(client); + u8 i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { + dev_dbg(&client->dev, "Data update\n"); + + /* Fans */ + for (i = 0; i < data->fannr; i++) { + if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { + data->fan_status[i] = + pc87360_read_value(data, LD_FAN, + NO_BANK, PC87360_REG_FAN_STATUS(i)); + data->fan[i] = pc87360_read_value(data, LD_FAN, + NO_BANK, PC87360_REG_FAN(i)); + data->fan_min[i] = pc87360_read_value(data, + LD_FAN, NO_BANK, + PC87360_REG_FAN_MIN(i)); + /* Change clock divider if needed */ + pc87360_autodiv(client, i); + /* Clear bits and write new divider */ + pc87360_write_value(data, LD_FAN, NO_BANK, + PC87360_REG_FAN_STATUS(i), + data->fan_status[i]); + } + if (FAN_CONFIG_CONTROL(data->fan_conf, i)) + data->pwm[i] = pc87360_read_value(data, LD_FAN, + NO_BANK, PC87360_REG_PWM(i)); + } + + /* Voltages */ + for (i = 0; i < data->innr; i++) { + data->in_status[i] = pc87360_read_value(data, LD_IN, i, + PC87365_REG_IN_STATUS); + /* Clear bits */ + pc87360_write_value(data, LD_IN, i, + PC87365_REG_IN_STATUS, + data->in_status[i]); + if ((data->in_status[i] & 0x81) == 0x81) { + data->in[i] = pc87360_read_value(data, LD_IN, + i, PC87365_REG_IN); + } + if (data->in_status[i] & 0x01) { + data->in_min[i] = pc87360_read_value(data, + LD_IN, i, + PC87365_REG_IN_MIN); + data->in_max[i] = pc87360_read_value(data, + LD_IN, i, + PC87365_REG_IN_MAX); + if (i >= 11) + data->in_crit[i-11] = + pc87360_read_value(data, LD_IN, + i, PC87365_REG_TEMP_CRIT); + } + } + if (data->innr) { + data->in_alarms = pc87360_read_value(data, LD_IN, + NO_BANK, PC87365_REG_IN_ALARMS1) + | ((pc87360_read_value(data, LD_IN, + NO_BANK, PC87365_REG_IN_ALARMS2) + & 0x07) << 8); + data->vid = (data->vid_conf & 0xE0) ? + pc87360_read_value(data, LD_IN, + NO_BANK, PC87365_REG_VID) : 0x1F; + } + + /* Temperatures */ + for (i = 0; i < data->tempnr; i++) { + data->temp_status[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_STATUS); + /* Clear bits */ + pc87360_write_value(data, LD_TEMP, i, + PC87365_REG_TEMP_STATUS, + data->temp_status[i]); + if ((data->temp_status[i] & 0x81) == 0x81) { + data->temp[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP); + } + if (data->temp_status[i] & 0x01) { + data->temp_min[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_MIN); + data->temp_max[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_MAX); + data->temp_crit[i] = pc87360_read_value(data, + LD_TEMP, i, + PC87365_REG_TEMP_CRIT); + } + } + if (data->tempnr) { + data->temp_alarms = pc87360_read_value(data, LD_TEMP, + NO_BANK, PC87365_REG_TEMP_ALARMS) + & 0x3F; + } + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init pc87360_init(void) +{ + int i; + + if (pc87360_find(0x2e, &devid, extra_isa) + && pc87360_find(0x4e, &devid, extra_isa)) { + printk(KERN_WARNING "pc87360: PC8736x not detected, " + "module not inserted.\n"); + return -ENODEV; + } + + /* Arbitrarily pick one of the addresses */ + for (i = 0; i < 3; i++) { + if (extra_isa[i] != 0x0000) { + normal_isa[0] = extra_isa[i]; + break; + } + } + + if (normal_isa[0] == 0x0000) { + printk(KERN_WARNING "pc87360: No active logical device, " + "module not inserted.\n"); + return -ENODEV; + } + + return i2c_add_driver(&pc87360_driver); +} + +static void __exit pc87360_exit(void) +{ + i2c_del_driver(&pc87360_driver); +} + + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("PC8736x hardware monitor"); +MODULE_LICENSE("GPL"); + +module_init(pc87360_init); +module_exit(pc87360_exit); diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c new file mode 100644 index 00000000000..6bbfc8fb4f1 --- /dev/null +++ b/drivers/hwmon/sis5595.c @@ -0,0 +1,817 @@ +/* + sis5595.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Copyright (C) 1998 - 2001 Frodo Looijaard , + Kyösti Mälkki , and + Mark D. Studebaker + Ported to Linux 2.6 by Aurelien Jarno with + the help of Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + SiS southbridge has a LM78-like chip integrated on the same IC. + This driver is a customized copy of lm78.c + + Supports following revisions: + Version PCI ID PCI Revision + 1 1039/0008 AF or less + 2 1039/0008 B0 or greater + + Note: these chips contain a 0008 device which is incompatible with the + 5595. We recognize these by the presence of the listed + "blacklist" PCI ID and refuse to load. + + NOT SUPPORTED PCI ID BLACKLIST PCI ID + 540 0008 0540 + 550 0008 0550 + 5513 0008 5511 + 5581 0008 5597 + 5582 0008 5597 + 5597 0008 5597 + 5598 0008 5597/5598 + 630 0008 0630 + 645 0008 0645 + 730 0008 0730 + 735 0008 0735 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* If force_addr is set to anything different from 0, we forcibly enable + the device at the given address. */ +static u16 force_addr; +module_param(force_addr, ushort, 0); +MODULE_PARM_DESC(force_addr, + "Initialize the base address of the sensors"); + +/* Addresses to scan. + Note that we can't determine the ISA address until we have initialized + our module */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(sis5595); + +/* Many SIS5595 constants specified below */ + +/* Length of ISA address segment */ +#define SIS5595_EXTENT 8 +/* PCI Config Registers */ +#define SIS5595_REVISION_REG 0x08 +#define SIS5595_BASE_REG 0x68 +#define SIS5595_PIN_REG 0x7A +#define SIS5595_ENABLE_REG 0x7B + +/* Where are the ISA address/data registers relative to the base address */ +#define SIS5595_ADDR_REG_OFFSET 5 +#define SIS5595_DATA_REG_OFFSET 6 + +/* The SIS5595 registers */ +#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define SIS5595_REG_IN(nr) (0x20 + (nr)) + +#define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr)) +#define SIS5595_REG_FAN(nr) (0x28 + (nr)) + +/* On the first version of the chip, the temp registers are separate. + On the second version, + TEMP pin is shared with IN4, configured in PCI register 0x7A. + The registers are the same as well. + OVER and HYST are really MAX and MIN. */ + +#define REV2MIN 0xb0 +#define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN(4) : 0x27 +#define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN_MAX(4) : 0x39 +#define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN_MIN(4) : 0x3a + +#define SIS5595_REG_CONFIG 0x40 +#define SIS5595_REG_ALARM1 0x41 +#define SIS5595_REG_ALARM2 0x42 +#define SIS5595_REG_FANDIV 0x47 + +/* Conversions. Limit checking is only done on the TO_REG + variants. */ + +/* IN: mV, (0V to 4.08V) + REG: 16mV/bit */ +static inline u8 IN_TO_REG(unsigned long val) +{ + unsigned long nval = SENSORS_LIMIT(val, 0, 4080); + return (nval + 8) / 16; +} +#define IN_FROM_REG(val) ((val) * 16) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm <= 0) + return 255; + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +static inline int FAN_FROM_REG(u8 val, int div) +{ + return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); +} + +/* TEMP: mC (-54.12C to +157.53C) + REG: 0.83C/bit + 52.12, two's complement */ +static inline int TEMP_FROM_REG(s8 val) +{ + return val * 830 + 52120; +} +static inline s8 TEMP_TO_REG(int val) +{ + int nval = SENSORS_LIMIT(val, -54120, 157530) ; + return nval<0 ? (nval-5212-415)/830 : (nval-5212+415)/830; +} + +/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) + REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ +static inline u8 DIV_TO_REG(int val) +{ + return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; +} +#define DIV_FROM_REG(val) (1 << (val)) + +/* For the SIS5595, we need to keep some data in memory. That + data is pointed to by sis5595_list[NR]->data. The structure itself is + dynamically allocated, at the time when the new sis5595 client is + allocated. */ +struct sis5595_data { + struct i2c_client client; + struct semaphore lock; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + char maxins; /* == 3 if temp enabled, otherwise == 4 */ + u8 revision; /* Reg. value */ + + u8 in[5]; /* Register value */ + u8 in_max[5]; /* Register value */ + u8 in_min[5]; /* Register value */ + u8 fan[2]; /* Register value */ + u8 fan_min[2]; /* Register value */ + s8 temp; /* Register value */ + s8 temp_over; /* Register value */ + s8 temp_hyst; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u16 alarms; /* Register encoding, combined */ +}; + +static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ + +static int sis5595_attach_adapter(struct i2c_adapter *adapter); +static int sis5595_detect(struct i2c_adapter *adapter, int address, int kind); +static int sis5595_detach_client(struct i2c_client *client); + +static int sis5595_read_value(struct i2c_client *client, u8 register); +static int sis5595_write_value(struct i2c_client *client, u8 register, u8 value); +static struct sis5595_data *sis5595_update_device(struct device *dev); +static void sis5595_init_client(struct i2c_client *client); + +static struct i2c_driver sis5595_driver = { + .owner = THIS_MODULE, + .name = "sis5595", + .id = I2C_DRIVERID_SIS5595, + .flags = I2C_DF_NOTIFY, + .attach_adapter = sis5595_attach_adapter, + .detach_client = sis5595_detach_client, +}; + +/* 4 Voltages */ +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); + return count; +} + +#define show_in_offset(offset) \ +static ssize_t \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in##offset, NULL); \ +static ssize_t \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); + +/* Temperature */ +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); +} + +static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); +} + +static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_over = TEMP_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over); + up(&data->update_lock); + return count; +} + +static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); +} + +static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_hyst = TEMP_TO_REG(val); + sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, + show_temp_over, set_temp_over); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, + show_temp_hyst, set_temp_hyst); + +/* 2 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + unsigned long min; + unsigned long val = simple_strtoul(buf, NULL, 10); + int reg; + + down(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + reg = sis5595_read_value(client, SIS5595_REG_FANDIV); + + switch (val) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + dev_err(&client->dev, "fan_div value %ld not " + "supported. Choose one of 1, 2, 4 or 8!\n", val); + up(&data->update_lock); + return -EINVAL; + } + + switch (nr) { + case 0: + reg = (reg & 0xcf) | (data->fan_div[nr] << 4); + break; + case 1: + reg = (reg & 0x3f) | (data->fan_div[nr] << 6); + break; + } + sis5595_write_value(client, SIS5595_REG_FANDIV, reg); + data->fan_min[nr] = + FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); + +show_fan_offset(1); +show_fan_offset(2); + +static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 0) ; +} + +static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 1) ; +} +static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, + show_fan_1_div, set_fan_1_div); +static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, + show_fan_2_div, set_fan_2_div); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sis5595_data *data = sis5595_update_device(dev); + return sprintf(buf, "%d\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* This is called when the module is loaded */ +static int sis5595_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, sis5595_detect); +} + +int sis5595_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int err = 0; + int i; + struct i2c_client *new_client; + struct sis5595_data *data; + char val; + u16 a; + + /* Make sure we are probing the ISA bus!! */ + if (!i2c_is_isa_adapter(adapter)) + goto exit; + + if (force_addr) + address = force_addr & ~(SIS5595_EXTENT - 1); + /* Reserve the ISA region */ + if (!request_region(address, SIS5595_EXTENT, sis5595_driver.name)) { + err = -EBUSY; + goto exit; + } + if (force_addr) { + dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address); + if (PCIBIOS_SUCCESSFUL != + pci_write_config_word(s_bridge, SIS5595_BASE_REG, address)) + goto exit_release; + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a)) + goto exit_release; + if ((a & ~(SIS5595_EXTENT - 1)) != address) + /* doesn't work for some chips? */ + goto exit_release; + } + + if (PCIBIOS_SUCCESSFUL != + pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) { + goto exit_release; + } + if ((val & 0x80) == 0) { + if (PCIBIOS_SUCCESSFUL != + pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG, + val | 0x80)) + goto exit_release; + if (PCIBIOS_SUCCESSFUL != + pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) + goto exit_release; + if ((val & 0x80) == 0) + /* doesn't work for some chips! */ + goto exit_release; + } + + if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release; + } + memset(data, 0, sizeof(struct sis5595_data)); + + new_client = &data->client; + new_client->addr = address; + init_MUTEX(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->adapter = adapter; + new_client->driver = &sis5595_driver; + new_client->flags = 0; + + /* Check revision and pin registers to determine whether 4 or 5 voltages */ + pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision)); + /* 4 voltages, 1 temp */ + data->maxins = 3; + if (data->revision >= REV2MIN) { + pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val); + if (!(val & 0x80)) + /* 5 voltages, no temps */ + data->maxins = 4; + } + + /* Fill in the remaining client fields and put it into the global list */ + strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE); + + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* Initialize the SIS5595 chip */ + sis5595_init_client(new_client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 2; i++) { + data->fan_min[i] = sis5595_read_value(new_client, + SIS5595_REG_FAN_MIN(i)); + } + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in3_max); + if (data->maxins == 4) { + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in4_max); + } + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_alarms); + if (data->maxins == 3) { + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + } + return 0; + +exit_free: + kfree(data); +exit_release: + release_region(address, SIS5595_EXTENT); +exit: + return err; +} + +static int sis5595_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + if (i2c_is_isa_client(client)) + release_region(client->addr, SIS5595_EXTENT); + + kfree(i2c_get_clientdata(client)); + + return 0; +} + + +/* ISA access must be locked explicitly. */ +static int sis5595_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + struct sis5595_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); + res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET); + up(&data->lock); + return res; +} + +static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + struct sis5595_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); + outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET); + up(&data->lock); + return 0; +} + +/* Called when we have found a new SIS5595. */ +static void sis5595_init_client(struct i2c_client *client) +{ + u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG); + if (!(config & 0x01)) + sis5595_write_value(client, SIS5595_REG_CONFIG, + (config & 0xf7) | 0x01); +} + +static struct sis5595_data *sis5595_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sis5595_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + + for (i = 0; i <= data->maxins; i++) { + data->in[i] = + sis5595_read_value(client, SIS5595_REG_IN(i)); + data->in_min[i] = + sis5595_read_value(client, + SIS5595_REG_IN_MIN(i)); + data->in_max[i] = + sis5595_read_value(client, + SIS5595_REG_IN_MAX(i)); + } + for (i = 0; i < 2; i++) { + data->fan[i] = + sis5595_read_value(client, SIS5595_REG_FAN(i)); + data->fan_min[i] = + sis5595_read_value(client, + SIS5595_REG_FAN_MIN(i)); + } + if (data->maxins == 3) { + data->temp = + sis5595_read_value(client, SIS5595_REG_TEMP); + data->temp_over = + sis5595_read_value(client, SIS5595_REG_TEMP_OVER); + data->temp_hyst = + sis5595_read_value(client, SIS5595_REG_TEMP_HYST); + } + i = sis5595_read_value(client, SIS5595_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = + sis5595_read_value(client, SIS5595_REG_ALARM1) | + (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static struct pci_device_id sis5595_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, sis5595_pci_ids); + +static int blacklist[] __devinitdata = { + PCI_DEVICE_ID_SI_540, + PCI_DEVICE_ID_SI_550, + PCI_DEVICE_ID_SI_630, + PCI_DEVICE_ID_SI_645, + PCI_DEVICE_ID_SI_730, + PCI_DEVICE_ID_SI_735, + PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but + that ID shows up in other chips so we + use the 5511 ID for recognition */ + PCI_DEVICE_ID_SI_5597, + PCI_DEVICE_ID_SI_5598, + 0 }; + +static int __devinit sis5595_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + u16 val; + int *i; + int addr = 0; + + for (i = blacklist; *i != 0; i++) { + struct pci_dev *dev; + dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL); + if (dev) { + dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i); + pci_dev_put(dev); + return -ENODEV; + } + } + + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(dev, SIS5595_BASE_REG, &val)) + return -ENODEV; + + addr = val & ~(SIS5595_EXTENT - 1); + if (addr == 0 && force_addr == 0) { + dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n"); + return -ENODEV; + } + if (force_addr) + addr = force_addr; /* so detect will get called */ + + if (!addr) { + dev_err(&dev->dev,"No SiS 5595 sensors found.\n"); + return -ENODEV; + } + normal_isa[0] = addr; + + s_bridge = pci_dev_get(dev); + if (i2c_add_driver(&sis5595_driver)) { + pci_dev_put(s_bridge); + s_bridge = NULL; + } + + /* Always return failure here. This is to allow other drivers to bind + * to this pci device. We don't really want to have control over the + * pci device, we only wanted to read as few register values from it. + */ + return -ENODEV; +} + +static struct pci_driver sis5595_pci_driver = { + .name = "sis5595", + .id_table = sis5595_pci_ids, + .probe = sis5595_pci_probe, +}; + +static int __init sm_sis5595_init(void) +{ + return pci_register_driver(&sis5595_pci_driver); +} + +static void __exit sm_sis5595_exit(void) +{ + pci_unregister_driver(&sis5595_pci_driver); + if (s_bridge != NULL) { + i2c_del_driver(&sis5595_driver); + pci_dev_put(s_bridge); + s_bridge = NULL; + } +} + +MODULE_AUTHOR("Aurelien Jarno "); +MODULE_DESCRIPTION("SiS 5595 Sensor device"); +MODULE_LICENSE("GPL"); + +module_init(sm_sis5595_init); +module_exit(sm_sis5595_exit); diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c new file mode 100644 index 00000000000..251ac265955 --- /dev/null +++ b/drivers/hwmon/smsc47b397.c @@ -0,0 +1,352 @@ +/* + smsc47b397.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Supports the SMSC LPC47B397-NC Super-I/O chip. + + Author/Maintainer: Mark M. Hoffman + Copyright (C) 2004 Utilitek Systems, Inc. + + derived in part from smsc47m1.c: + Copyright (C) 2002 Mark D. Studebaker + Copyright (C) 2004 Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +/* Address is autodetected, there is no default value */ +static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; +static struct i2c_force_data forces[] = {{NULL}}; + +enum chips { any_chip, smsc47b397 }; +static struct i2c_address_data addr_data = { + .normal_i2c = normal_i2c, + .normal_isa = normal_isa, + .probe = normal_i2c, /* cheat */ + .ignore = normal_i2c, /* cheat */ + .forces = forces, +}; + +/* Super-I/0 registers and commands */ + +#define REG 0x2e /* The register to read/write */ +#define VAL 0x2f /* The value to read/write */ + +static inline void superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +/* select superio logical device */ +static inline void superio_select(int ld) +{ + superio_outb(0x07, ld); +} + +static inline void superio_enter(void) +{ + outb(0x55, REG); +} + +static inline void superio_exit(void) +{ + outb(0xAA, REG); +} + +#define SUPERIO_REG_DEVID 0x20 +#define SUPERIO_REG_DEVREV 0x21 +#define SUPERIO_REG_BASE_MSB 0x60 +#define SUPERIO_REG_BASE_LSB 0x61 +#define SUPERIO_REG_LD8 0x08 + +#define SMSC_EXTENT 0x02 + +/* 0 <= nr <= 3 */ +static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80}; +#define SMSC47B397_REG_TEMP(nr) (smsc47b397_reg_temp[(nr)]) + +/* 0 <= nr <= 3 */ +#define SMSC47B397_REG_FAN_LSB(nr) (0x28 + 2 * (nr)) +#define SMSC47B397_REG_FAN_MSB(nr) (0x29 + 2 * (nr)) + +struct smsc47b397_data { + struct i2c_client client; + struct semaphore lock; + + struct semaphore update_lock; + unsigned long last_updated; /* in jiffies */ + int valid; + + /* register values */ + u16 fan[4]; + u8 temp[4]; +}; + +static int smsc47b397_read_value(struct i2c_client *client, u8 reg) +{ + struct smsc47b397_data *data = i2c_get_clientdata(client); + int res; + + down(&data->lock); + outb(reg, client->addr); + res = inb_p(client->addr + 1); + up(&data->lock); + return res; +} + +static struct smsc47b397_data *smsc47b397_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47b397_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + dev_dbg(&client->dev, "starting device update...\n"); + + /* 4 temperature inputs, 4 fan inputs */ + for (i = 0; i < 4; i++) { + data->temp[i] = smsc47b397_read_value(client, + SMSC47B397_REG_TEMP(i)); + + /* must read LSB first */ + data->fan[i] = smsc47b397_read_value(client, + SMSC47B397_REG_FAN_LSB(i)); + data->fan[i] |= smsc47b397_read_value(client, + SMSC47B397_REG_FAN_MSB(i)) << 8; + } + + data->last_updated = jiffies; + data->valid = 1; + + dev_dbg(&client->dev, "... device update complete\n"); + } + + up(&data->update_lock); + + return data; +} + +/* TEMP: 0.001C/bit (-128C to +127C) + REG: 1C/bit, two's complement */ +static int temp_from_reg(u8 reg) +{ + return (s8)reg * 1000; +} + +/* 0 <= nr <= 3 */ +static ssize_t show_temp(struct device *dev, char *buf, int nr) +{ + struct smsc47b397_data *data = smsc47b397_update_device(dev); + return sprintf(buf, "%d\n", temp_from_reg(data->temp[nr])); +} + +#define sysfs_temp(num) \ +static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, num-1); \ +} \ +static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL) + +sysfs_temp(1); +sysfs_temp(2); +sysfs_temp(3); +sysfs_temp(4); + +#define device_create_file_temp(client, num) \ + device_create_file(&client->dev, &dev_attr_temp##num##_input) + +/* FAN: 1 RPM/bit + REG: count of 90kHz pulses / revolution */ +static int fan_from_reg(u16 reg) +{ + return 90000 * 60 / reg; +} + +/* 0 <= nr <= 3 */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct smsc47b397_data *data = smsc47b397_update_device(dev); + return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr])); +} + +#define sysfs_fan(num) \ +static ssize_t show_fan##num(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, num-1); \ +} \ +static DEVICE_ATTR(fan##num##_input, S_IRUGO, show_fan##num, NULL) + +sysfs_fan(1); +sysfs_fan(2); +sysfs_fan(3); +sysfs_fan(4); + +#define device_create_file_fan(client, num) \ + device_create_file(&client->dev, &dev_attr_fan##num##_input) + +static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind); + +static int smsc47b397_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, smsc47b397_detect); +} + +static int smsc47b397_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + release_region(client->addr, SMSC_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static struct i2c_driver smsc47b397_driver = { + .owner = THIS_MODULE, + .name = "smsc47b397", + .id = I2C_DRIVERID_SMSC47B397, + .flags = I2C_DF_NOTIFY, + .attach_adapter = smsc47b397_attach_adapter, + .detach_client = smsc47b397_detach_client, +}; + +static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind) +{ + struct i2c_client *new_client; + struct smsc47b397_data *data; + int err = 0; + + if (!i2c_is_isa_adapter(adapter)) { + return 0; + } + + if (!request_region(addr, SMSC_EXTENT, smsc47b397_driver.name)) { + dev_err(&adapter->dev, "Region 0x%x already in use!\n", addr); + return -EBUSY; + } + + if (!(data = kmalloc(sizeof(struct smsc47b397_data), GFP_KERNEL))) { + err = -ENOMEM; + goto error_release; + } + memset(data, 0x00, sizeof(struct smsc47b397_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = addr; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &smsc47b397_driver; + new_client->flags = 0; + + strlcpy(new_client->name, "smsc47b397", I2C_NAME_SIZE); + + init_MUTEX(&data->update_lock); + + if ((err = i2c_attach_client(new_client))) + goto error_free; + + device_create_file_temp(new_client, 1); + device_create_file_temp(new_client, 2); + device_create_file_temp(new_client, 3); + device_create_file_temp(new_client, 4); + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + device_create_file_fan(new_client, 3); + device_create_file_fan(new_client, 4); + + return 0; + +error_free: + kfree(new_client); +error_release: + release_region(addr, SMSC_EXTENT); + return err; +} + +static int __init smsc47b397_find(unsigned int *addr) +{ + u8 id, rev; + + superio_enter(); + id = superio_inb(SUPERIO_REG_DEVID); + + if (id != 0x6f) { + superio_exit(); + return -ENODEV; + } + + rev = superio_inb(SUPERIO_REG_DEVREV); + + superio_select(SUPERIO_REG_LD8); + *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8) + | superio_inb(SUPERIO_REG_BASE_LSB); + + printk(KERN_INFO "smsc47b397: found SMSC LPC47B397-NC " + "(base address 0x%04x, revision %u)\n", *addr, rev); + + superio_exit(); + return 0; +} + +static int __init smsc47b397_init(void) +{ + int ret; + + if ((ret = smsc47b397_find(normal_isa))) + return ret; + + return i2c_add_driver(&smsc47b397_driver); +} + +static void __exit smsc47b397_exit(void) +{ + i2c_del_driver(&smsc47b397_driver); +} + +MODULE_AUTHOR("Mark M. Hoffman "); +MODULE_DESCRIPTION("SMSC LPC47B397 driver"); +MODULE_LICENSE("GPL"); + +module_init(smsc47b397_init); +module_exit(smsc47b397_exit); diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c new file mode 100644 index 00000000000..897117a7213 --- /dev/null +++ b/drivers/hwmon/smsc47m1.c @@ -0,0 +1,593 @@ +/* + smsc47m1.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x + Super-I/O chips. + + Copyright (C) 2002 Mark D. Studebaker + Copyright (C) 2004 Jean Delvare + Ported to Linux 2.6 by Gabriele Gorla + and Jean Delvare + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +/* Address is autodetected, there is no default value */ +static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; +static struct i2c_force_data forces[] = {{NULL}}; + +enum chips { any_chip, smsc47m1 }; +static struct i2c_address_data addr_data = { + .normal_i2c = normal_i2c, + .normal_isa = normal_isa, + .forces = forces, +}; + +/* Super-I/0 registers and commands */ + +#define REG 0x2e /* The register to read/write */ +#define VAL 0x2f /* The value to read/write */ + +static inline void +superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +/* logical device for fans is 0x0A */ +#define superio_select() superio_outb(0x07, 0x0A) + +static inline void +superio_enter(void) +{ + outb(0x55, REG); +} + +static inline void +superio_exit(void) +{ + outb(0xAA, REG); +} + +#define SUPERIO_REG_ACT 0x30 +#define SUPERIO_REG_BASE 0x60 +#define SUPERIO_REG_DEVID 0x20 + +/* Logical device registers */ + +#define SMSC_EXTENT 0x80 + +/* nr is 0 or 1 in the macros below */ +#define SMSC47M1_REG_ALARM 0x04 +#define SMSC47M1_REG_TPIN(nr) (0x34 - (nr)) +#define SMSC47M1_REG_PPIN(nr) (0x36 - (nr)) +#define SMSC47M1_REG_PWM(nr) (0x56 + (nr)) +#define SMSC47M1_REG_FANDIV 0x58 +#define SMSC47M1_REG_FAN(nr) (0x59 + (nr)) +#define SMSC47M1_REG_FAN_PRELOAD(nr) (0x5B + (nr)) + +#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \ + 983040/((192-(reg))*(div))) +#define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \ + 983040/(((reg)-(preload))*(div))) +#define DIV_FROM_REG(reg) (1 << (reg)) +#define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1) +#define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01) +#define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E) + +struct smsc47m1_data { + struct i2c_client client; + struct semaphore lock; + + struct semaphore update_lock; + unsigned long last_updated; /* In jiffies */ + + u8 fan[2]; /* Register value */ + u8 fan_preload[2]; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u8 alarms; /* Register encoding */ + u8 pwm[2]; /* Register value (bit 7 is enable) */ +}; + + +static int smsc47m1_attach_adapter(struct i2c_adapter *adapter); +static int smsc47m1_find(int *address); +static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind); +static int smsc47m1_detach_client(struct i2c_client *client); + +static int smsc47m1_read_value(struct i2c_client *client, u8 reg); +static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value); + +static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, + int init); + + +static struct i2c_driver smsc47m1_driver = { + .owner = THIS_MODULE, + .name = "smsc47m1", + .id = I2C_DRIVERID_SMSC47M1, + .flags = I2C_DF_NOTIFY, + .attach_adapter = smsc47m1_attach_adapter, + .detach_client = smsc47m1_detach_client, +}; + +/* nr is 0 or 1 in the callback functions below */ + +static ssize_t get_fan(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + /* This chip (stupidly) stops monitoring fan speed if PWM is + enabled and duty cycle is 0%. This is fine if the monitoring + and control concern the same fan, but troublesome if they are + not (which could as well happen). */ + int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 : + FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr]), + data->fan_preload[nr]); + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t get_fan_min(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + int rpm = MIN_FROM_REG(data->fan_preload[nr], + DIV_FROM_REG(data->fan_div[nr])); + return sprintf(buf, "%d\n", rpm); +} + +static ssize_t get_fan_div(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); +} + +static ssize_t get_pwm(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); +} + +static ssize_t get_pwm_en(struct device *dev, char *buf, int nr) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr])); +} + +static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); + return sprintf(buf, "%d\n", data->alarms); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + long rpmdiv, val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]); + + if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) { + up(&data->update_lock); + return -EINVAL; + } + + data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv); + smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), + data->fan_preload[nr]); + up(&data->update_lock); + + return count; +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan clock divider. This follows the principle + of least suprise; the user doesn't expect the fan minimum to change just + because the divider changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long new_div = simple_strtol(buf, NULL, 10), tmp; + u8 old_div = DIV_FROM_REG(data->fan_div[nr]); + + if (new_div == old_div) /* No change */ + return count; + + down(&data->update_lock); + switch (new_div) { + case 1: data->fan_div[nr] = 0; break; + case 2: data->fan_div[nr] = 1; break; + case 4: data->fan_div[nr] = 2; break; + case 8: data->fan_div[nr] = 3; break; + default: + up(&data->update_lock); + return -EINVAL; + } + + tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F; + tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6); + smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp); + + /* Preserve fan min */ + tmp = 192 - (old_div * (192 - data->fan_preload[nr]) + + new_div / 2) / new_div; + data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191); + smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), + data->fan_preload[nr]); + up(&data->update_lock); + + return count; +} + +static ssize_t set_pwm(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long val = simple_strtol(buf, NULL, 10); + + if (val < 0 || val > 255) + return -EINVAL; + + down(&data->update_lock); + data->pwm[nr] &= 0x81; /* Preserve additional bits */ + data->pwm[nr] |= PWM_TO_REG(val); + smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), + data->pwm[nr]); + up(&data->update_lock); + + return count; +} + +static ssize_t set_pwm_en(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + long val = simple_strtol(buf, NULL, 10); + + if (val != 0 && val != 1) + return -EINVAL; + + down(&data->update_lock); + data->pwm[nr] &= 0xFE; /* preserve the other bits */ + data->pwm[nr] |= !val; + smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), + data->pwm[nr]); + up(&data->update_lock); + + return count; +} + +#define fan_present(offset) \ +static ssize_t get_fan##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return get_fan(dev, buf, offset - 1); \ +} \ +static ssize_t get_fan##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return get_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t get_fan##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return get_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan##offset##_div (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_div(dev, buf, count, offset - 1); \ +} \ +static ssize_t get_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return get_pwm(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm(dev, buf, count, offset - 1); \ +} \ +static ssize_t get_pwm##offset##_en (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return get_pwm_en(dev, buf, offset - 1); \ +} \ +static ssize_t set_pwm##offset##_en (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_pwm_en(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset, \ + NULL); \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + get_fan##offset##_min, set_fan##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + get_fan##offset##_div, set_fan##offset##_div); \ +static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + get_pwm##offset, set_pwm##offset); \ +static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ + get_pwm##offset##_en, set_pwm##offset##_en); + +fan_present(1); +fan_present(2); + +static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); + +static int smsc47m1_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, smsc47m1_detect); +} + +static int smsc47m1_find(int *address) +{ + u8 val; + + superio_enter(); + val = superio_inb(SUPERIO_REG_DEVID); + + /* + * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id + * 0x5F) and LPC47B27x (device id 0x51) have fan control. + * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" + * can do much more besides (device id 0x60). + */ + if (val == 0x51) + printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); + else if (val == 0x59) + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n"); + else if (val == 0x5F) + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); + else if (val == 0x60) + printk(KERN_INFO "smsc47m1: Found SMSC LPC47M15x/LPC47M192\n"); + else { + superio_exit(); + return -ENODEV; + } + + superio_select(); + *address = (superio_inb(SUPERIO_REG_BASE) << 8) + | superio_inb(SUPERIO_REG_BASE + 1); + val = superio_inb(SUPERIO_REG_ACT); + if (*address == 0 || (val & 0x01) == 0) { + printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n"); + superio_exit(); + return -ENODEV; + } + + superio_exit(); + return 0; +} + +static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct smsc47m1_data *data; + int err = 0; + int fan1, fan2, pwm1, pwm2; + + if (!i2c_is_isa_adapter(adapter)) { + return 0; + } + + if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.name)) { + dev_err(&adapter->dev, "Region 0x%x already in use!\n", address); + return -EBUSY; + } + + if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { + err = -ENOMEM; + goto error_release; + } + memset(data, 0x00, sizeof(struct smsc47m1_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &smsc47m1_driver; + new_client->flags = 0; + + strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE); + init_MUTEX(&data->update_lock); + + /* If no function is properly configured, there's no point in + actually registering the chip. */ + fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05) + == 0x05; + fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05) + == 0x05; + pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05) + == 0x04; + pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05) + == 0x04; + if (!(fan1 || fan2 || pwm1 || pwm2)) { + dev_warn(&new_client->dev, "Device is not configured, will not use\n"); + err = -ENODEV; + goto error_free; + } + + if ((err = i2c_attach_client(new_client))) + goto error_free; + + /* Some values (fan min, clock dividers, pwm registers) may be + needed before any update is triggered, so we better read them + at least once here. We don't usually do it that way, but in + this particular case, manually reading 5 registers out of 8 + doesn't make much sense and we're better using the existing + function. */ + smsc47m1_update_device(&new_client->dev, 1); + + if (fan1) { + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + } else + dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, " + "skipping\n"); + + if (fan2) { + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + } else + dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, " + "skipping\n"); + + if (pwm1) { + device_create_file(&new_client->dev, &dev_attr_pwm1); + device_create_file(&new_client->dev, &dev_attr_pwm1_enable); + } else + dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, " + "skipping\n"); + if (pwm2) { + device_create_file(&new_client->dev, &dev_attr_pwm2); + device_create_file(&new_client->dev, &dev_attr_pwm2_enable); + } else + dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, " + "skipping\n"); + + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +error_free: + kfree(new_client); +error_release: + release_region(address, SMSC_EXTENT); + return err; +} + +static int smsc47m1_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + release_region(client->addr, SMSC_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static int smsc47m1_read_value(struct i2c_client *client, u8 reg) +{ + int res; + + down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + res = inb_p(client->addr + reg); + up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + return res; +} + +static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); + outb_p(value, client->addr + reg); + up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); +} + +static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, + int init) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smsc47m1_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) { + int i; + + for (i = 0; i < 2; i++) { + data->fan[i] = smsc47m1_read_value(client, + SMSC47M1_REG_FAN(i)); + data->fan_preload[i] = smsc47m1_read_value(client, + SMSC47M1_REG_FAN_PRELOAD(i)); + data->pwm[i] = smsc47m1_read_value(client, + SMSC47M1_REG_PWM(i)); + } + + i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + + data->alarms = smsc47m1_read_value(client, + SMSC47M1_REG_ALARM) >> 6; + /* Clear alarms if needed */ + if (data->alarms) + smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0); + + data->last_updated = jiffies; + } + + up(&data->update_lock); + return data; +} + +static int __init sm_smsc47m1_init(void) +{ + if (smsc47m1_find(normal_isa)) { + return -ENODEV; + } + + return i2c_add_driver(&smsc47m1_driver); +} + +static void __exit sm_smsc47m1_exit(void) +{ + i2c_del_driver(&smsc47m1_driver); +} + +MODULE_AUTHOR("Mark D. Studebaker "); +MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver"); +MODULE_LICENSE("GPL"); + +module_init(sm_smsc47m1_init); +module_exit(sm_smsc47m1_exit); diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c new file mode 100644 index 00000000000..164d4794839 --- /dev/null +++ b/drivers/hwmon/via686a.c @@ -0,0 +1,875 @@ +/* + via686a.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Copyright (c) 1998 - 2002 Frodo Looijaard , + Kyösti Mälkki , + Mark Studebaker , + and Bob Dougherty + (Some conversion-factor data were contributed by Jonathan Teh Soon Yew + and Alex van Kaam .) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + Supports the Via VT82C686A, VT82C686B south bridges. + Reports all as a 686A. + Warning - only supports a single device. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* If force_addr is set to anything different from 0, we forcibly enable + the device at the given address. */ +static unsigned short force_addr = 0; +module_param(force_addr, ushort, 0); +MODULE_PARM_DESC(force_addr, + "Initialize the base address of the sensors"); + +/* Addresses to scan. + Note that we can't determine the ISA address until we have initialized + our module */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(via686a); + +/* + The Via 686a southbridge has a LM78-like chip integrated on the same IC. + This driver is a customized copy of lm78.c +*/ + +/* Many VIA686A constants specified below */ + +/* Length of ISA address segment */ +#define VIA686A_EXTENT 0x80 +#define VIA686A_BASE_REG 0x70 +#define VIA686A_ENABLE_REG 0x74 + +/* The VIA686A registers */ +/* ins numbered 0-4 */ +#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) +#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) +#define VIA686A_REG_IN(nr) (0x22 + (nr)) + +/* fans numbered 1-2 */ +#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) +#define VIA686A_REG_FAN(nr) (0x28 + (nr)) + +/* temps numbered 1-3 */ +static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f }; +static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d }; +static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e }; +/* bits 7-6 */ +#define VIA686A_REG_TEMP_LOW1 0x4b +/* 2 = bits 5-4, 3 = bits 7-6 */ +#define VIA686A_REG_TEMP_LOW23 0x49 + +#define VIA686A_REG_ALARM1 0x41 +#define VIA686A_REG_ALARM2 0x42 +#define VIA686A_REG_FANDIV 0x47 +#define VIA686A_REG_CONFIG 0x40 +/* The following register sets temp interrupt mode (bits 1-0 for temp1, + 3-2 for temp2, 5-4 for temp3). Modes are: + 00 interrupt stays as long as value is out-of-range + 01 interrupt is cleared once register is read (default) + 10 comparator mode- like 00, but ignores hysteresis + 11 same as 00 */ +#define VIA686A_REG_TEMP_MODE 0x4b +/* We'll just assume that you want to set all 3 simultaneously: */ +#define VIA686A_TEMP_MODE_MASK 0x3F +#define VIA686A_TEMP_MODE_CONTINUOUS 0x00 + +/* Conversions. Limit checking is only done on the TO_REG + variants. + +********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** + From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): + voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp + voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V + voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V + voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V + voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V + in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; + That is: + volts = (25*regVal+133)*factor + regVal = (volts/factor-133)/25 + (These conversions were contributed by Jonathan Teh Soon Yew + ) */ +static inline u8 IN_TO_REG(long val, int inNum) +{ + /* To avoid floating point, we multiply constants by 10 (100 for +12V). + Rounding is done (120500 is actually 133000 - 12500). + Remember that val is expressed in 0.001V/bit, which is why we divide + by an additional 10000 (100000 for +12V): 1000 for val and 10 (100) + for the constants. */ + if (inNum <= 1) + return (u8) + SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255); + else if (inNum == 2) + return (u8) + SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255); + else if (inNum == 3) + return (u8) + SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255); + else + return (u8) + SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255); +} + +static inline long IN_FROM_REG(u8 val, int inNum) +{ + /* To avoid floating point, we multiply constants by 10 (100 for +12V). + We also multiply them by 1000 because we want 0.001V/bit for the + output value. Rounding is done. */ + if (inNum <= 1) + return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024); + else if (inNum == 2) + return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737); + else if (inNum == 3) + return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108); + else + return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714); +} + +/********* FAN RPM CONVERSIONS ********/ +/* Higher register values = slower fans (the fan's strobe gates a counter). + But this chip saturates back at 0, not at 255 like all the other chips. + So, 0 means 0 RPM */ +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 0; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); +} + +#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div))) + +/******** TEMP CONVERSIONS (Bob Dougherty) *********/ +/* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) + if(temp<169) + return double(temp)*0.427-32.08; + else if(temp>=169 && temp<=202) + return double(temp)*0.582-58.16; + else + return double(temp)*0.924-127.33; + + A fifth-order polynomial fits the unofficial data (provided by Alex van + Kaam ) a bit better. It also give more reasonable + numbers on my machine (ie. they agree with what my BIOS tells me). + Here's the fifth-order fit to the 8-bit data: + temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - + 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. + + (2000-10-25- RFD: thanks to Uwe Andersen for + finding my typos in this formula!) + + Alas, none of the elegant function-fit solutions will work because we + aren't allowed to use floating point in the kernel and doing it with + integers doesn't provide enough precision. So we'll do boring old + look-up table stuff. The unofficial data (see below) have effectively + 7-bit resolution (they are rounded to the nearest degree). I'm assuming + that the transfer function of the device is monotonic and smooth, so a + smooth function fit to the data will allow us to get better precision. + I used the 5th-order poly fit described above and solved for + VIA register values 0-255. I *10 before rounding, so we get tenth-degree + precision. (I could have done all 1024 values for our 10-bit readings, + but the function is very linear in the useful range (0-80 deg C), so + we'll just use linear interpolation for 10-bit readings.) So, tempLUT + is the temp at via register values 0-255: */ +static const long tempLUT[] = +{ -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, + -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, + -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, + -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, + -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, + -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, + -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, + 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, + 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, + 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, + 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, + 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, + 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, + 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, + 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, + 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, + 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, + 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, + 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, + 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, + 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, + 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 +}; + +/* the original LUT values from Alex van Kaam + (for via register values 12-240): +{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, +-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, +-15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, +-3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12, +12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22, +22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33, +33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45, +45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60, +61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84, +85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; + + + Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed + an extra term for a good fit to these inverse data!) and then + solving for each temp value from -50 to 110 (the useable range for + this chip). Here's the fit: + viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 + - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) + Note that n=161: */ +static const u8 viaLUT[] = +{ 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, + 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, + 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, + 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, + 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, + 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, + 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, + 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, + 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, + 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, + 239, 240 +}; + +/* Converting temps to (8-bit) hyst and over registers + No interpolation here. + The +50 is because the temps start at -50 */ +static inline u8 TEMP_TO_REG(long val) +{ + return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : + (val < 0 ? val - 500 : val + 500) / 1000 + 50]; +} + +/* for 8-bit temperature hyst and over registers */ +#define TEMP_FROM_REG(val) (tempLUT[(val)] * 100) + +/* for 10-bit temperature readings */ +static inline long TEMP_FROM_REG10(u16 val) +{ + u16 eightBits = val >> 2; + u16 twoBits = val & 3; + + /* no interpolation for these */ + if (twoBits == 0 || eightBits == 255) + return TEMP_FROM_REG(eightBits); + + /* do some linear interpolation */ + return (tempLUT[eightBits] * (4 - twoBits) + + tempLUT[eightBits + 1] * twoBits) * 25; +} + +#define DIV_FROM_REG(val) (1 << (val)) +#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) + +/* For the VIA686A, we need to keep some data in memory. + The structure is dynamically allocated, at the same time when a new + via686a client is allocated. */ +struct via686a_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[5]; /* Register value */ + u8 in_max[5]; /* Register value */ + u8 in_min[5]; /* Register value */ + u8 fan[2]; /* Register value */ + u8 fan_min[2]; /* Register value */ + u16 temp[3]; /* Register value 10 bit */ + u8 temp_over[3]; /* Register value */ + u8 temp_hyst[3]; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u16 alarms; /* Register encoding, combined */ +}; + +static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ + +static int via686a_attach_adapter(struct i2c_adapter *adapter); +static int via686a_detect(struct i2c_adapter *adapter, int address, int kind); +static int via686a_detach_client(struct i2c_client *client); + +static inline int via686a_read_value(struct i2c_client *client, u8 reg) +{ + return (inb_p(client->addr + reg)); +} + +static inline void via686a_write_value(struct i2c_client *client, u8 reg, + u8 value) +{ + outb_p(value, client->addr + reg); +} + +static struct via686a_data *via686a_update_device(struct device *dev); +static void via686a_init_client(struct i2c_client *client); + +/* following are the sysfs callback functions */ + +/* 7 voltage sensors */ +static ssize_t show_in(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr)); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr)); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val, nr); + via686a_write_value(client, VIA686A_REG_IN_MIN(nr), + data->in_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val, nr); + via686a_write_value(client, VIA686A_REG_IN_MAX(nr), + data->in_max[nr]); + up(&data->update_lock); + return count; +} +#define show_in_offset(offset) \ +static ssize_t \ + show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static ssize_t \ + show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_min(dev, buf, offset); \ +} \ +static ssize_t \ + show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_max(dev, buf, offset); \ +} \ +static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, offset); \ +} \ +static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\ +static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min); \ +static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max); + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); + +/* 3 temperatures */ +static ssize_t show_temp(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr])); +} +static ssize_t show_temp_over(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr])); +} +static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])); +} +static ssize_t set_temp_over(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_over[nr] = TEMP_TO_REG(val); + via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr], + data->temp_over[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_temp_hyst(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->temp_hyst[nr] = TEMP_TO_REG(val); + via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr], + data->temp_hyst[nr]); + up(&data->update_lock); + return count; +} +#define show_temp_offset(offset) \ +static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, offset - 1); \ +} \ +static ssize_t \ +show_temp_##offset##_over (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_over(dev, buf, offset - 1); \ +} \ +static ssize_t \ +show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_hyst(dev, buf, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_over(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_temp_hyst(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\ +static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_over, set_temp_##offset##_over); \ +static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ + show_temp_##offset##_hyst, set_temp_##offset##_hyst); + +show_temp_offset(1); +show_temp_offset(2); +show_temp_offset(3); + +/* 2 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%d\n", + FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); +} +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); +} +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]); + up(&data->update_lock); + return count; +} +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) { + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + int old; + + down(&data->update_lock); + old = via686a_read_value(client, VIA686A_REG_FANDIV); + data->fan_div[nr] = DIV_TO_REG(val); + old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4); + via686a_write_value(client, VIA686A_REG_FANDIV, old); + up(&data->update_lock); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, offset - 1); \ +} \ +static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return set_fan_div(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min); \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_div, set_fan_##offset##_div); + +show_fan_offset(1); +show_fan_offset(2); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { + struct via686a_data *data = via686a_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* The driver. I choose to use type i2c_driver, as at is identical to both + smbus_driver and isa_driver, and clients could be of either kind */ +static struct i2c_driver via686a_driver = { + .owner = THIS_MODULE, + .name = "via686a", + .id = I2C_DRIVERID_VIA686A, + .flags = I2C_DF_NOTIFY, + .attach_adapter = via686a_attach_adapter, + .detach_client = via686a_detach_client, +}; + + +/* This is called when the module is loaded */ +static int via686a_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, via686a_detect); +} + +static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct via686a_data *data; + int err = 0; + const char client_name[] = "via686a"; + u16 val; + + /* Make sure we are probing the ISA bus!! */ + if (!i2c_is_isa_adapter(adapter)) { + dev_err(&adapter->dev, + "via686a_detect called for an I2C bus adapter?!?\n"); + return 0; + } + + /* 8231 requires multiple of 256, we enforce that on 686 as well */ + if (force_addr) + address = force_addr & 0xFF00; + + if (force_addr) { + dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", + address); + if (PCIBIOS_SUCCESSFUL != + pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) + return -ENODEV; + } + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) + return -ENODEV; + if (!(val & 0x0001)) { + dev_warn(&adapter->dev, "enabling sensors\n"); + if (PCIBIOS_SUCCESSFUL != + pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, + val | 0x0001)) + return -ENODEV; + } + + /* Reserve the ISA region */ + if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) { + dev_err(&adapter->dev, "region 0x%x already in use!\n", + address); + return -ENODEV; + } + + if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + memset(data, 0, sizeof(struct via686a_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &via686a_driver; + new_client->flags = 0; + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + + data->valid = 0; + init_MUTEX(&data->update_lock); + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR3; + + /* Initialize the VIA686A chip */ + via686a_init_client(new_client); + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in0_input); + device_create_file(&new_client->dev, &dev_attr_in1_input); + device_create_file(&new_client->dev, &dev_attr_in2_input); + device_create_file(&new_client->dev, &dev_attr_in3_input); + device_create_file(&new_client->dev, &dev_attr_in4_input); + device_create_file(&new_client->dev, &dev_attr_in0_min); + device_create_file(&new_client->dev, &dev_attr_in1_min); + device_create_file(&new_client->dev, &dev_attr_in2_min); + device_create_file(&new_client->dev, &dev_attr_in3_min); + device_create_file(&new_client->dev, &dev_attr_in4_min); + device_create_file(&new_client->dev, &dev_attr_in0_max); + device_create_file(&new_client->dev, &dev_attr_in1_max); + device_create_file(&new_client->dev, &dev_attr_in2_max); + device_create_file(&new_client->dev, &dev_attr_in3_max); + device_create_file(&new_client->dev, &dev_attr_in4_max); + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp2_input); + device_create_file(&new_client->dev, &dev_attr_temp3_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + device_create_file(&new_client->dev, &dev_attr_temp2_max); + device_create_file(&new_client->dev, &dev_attr_temp3_max); + device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst); + device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst); + device_create_file(&new_client->dev, &dev_attr_fan1_input); + device_create_file(&new_client->dev, &dev_attr_fan2_input); + device_create_file(&new_client->dev, &dev_attr_fan1_min); + device_create_file(&new_client->dev, &dev_attr_fan2_min); + device_create_file(&new_client->dev, &dev_attr_fan1_div); + device_create_file(&new_client->dev, &dev_attr_fan2_div); + device_create_file(&new_client->dev, &dev_attr_alarms); + + return 0; + +ERROR3: + kfree(data); +ERROR0: + release_region(address, VIA686A_EXTENT); + return err; +} + +static int via686a_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + release_region(client->addr, VIA686A_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +/* Called when we have found a new VIA686A. Set limits, etc. */ +static void via686a_init_client(struct i2c_client *client) +{ + u8 reg; + + /* Start monitoring */ + reg = via686a_read_value(client, VIA686A_REG_CONFIG); + via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); + + /* Configure temp interrupt mode for continuous-interrupt operation */ + via686a_write_value(client, VIA686A_REG_TEMP_MODE, + via686a_read_value(client, VIA686A_REG_TEMP_MODE) & + !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); +} + +static struct via686a_data *via686a_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct via686a_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + for (i = 0; i <= 4; i++) { + data->in[i] = + via686a_read_value(client, VIA686A_REG_IN(i)); + data->in_min[i] = via686a_read_value(client, + VIA686A_REG_IN_MIN + (i)); + data->in_max[i] = + via686a_read_value(client, VIA686A_REG_IN_MAX(i)); + } + for (i = 1; i <= 2; i++) { + data->fan[i - 1] = + via686a_read_value(client, VIA686A_REG_FAN(i)); + data->fan_min[i - 1] = via686a_read_value(client, + VIA686A_REG_FAN_MIN(i)); + } + for (i = 0; i <= 2; i++) { + data->temp[i] = via686a_read_value(client, + VIA686A_REG_TEMP[i]) << 2; + data->temp_over[i] = + via686a_read_value(client, + VIA686A_REG_TEMP_OVER[i]); + data->temp_hyst[i] = + via686a_read_value(client, + VIA686A_REG_TEMP_HYST[i]); + } + /* add in lower 2 bits + temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 + temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 + temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 + */ + data->temp[0] |= (via686a_read_value(client, + VIA686A_REG_TEMP_LOW1) + & 0xc0) >> 6; + data->temp[1] |= + (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & + 0x30) >> 4; + data->temp[2] |= + (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & + 0xc0) >> 6; + + i = via686a_read_value(client, VIA686A_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = + via686a_read_value(client, + VIA686A_REG_ALARM1) | + (via686a_read_value(client, VIA686A_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static struct pci_device_id via686a_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, via686a_pci_ids); + +static int __devinit via686a_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + u16 val; + int addr = 0; + + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(dev, VIA686A_BASE_REG, &val)) + return -ENODEV; + + addr = val & ~(VIA686A_EXTENT - 1); + if (addr == 0 && force_addr == 0) { + dev_err(&dev->dev, "base address not set - upgrade BIOS " + "or use force_addr=0xaddr\n"); + return -ENODEV; + } + if (force_addr) + addr = force_addr; /* so detect will get called */ + + if (!addr) { + dev_err(&dev->dev, "No Via 686A sensors found.\n"); + return -ENODEV; + } + normal_isa[0] = addr; + + s_bridge = pci_dev_get(dev); + if (i2c_add_driver(&via686a_driver)) { + pci_dev_put(s_bridge); + s_bridge = NULL; + } + + /* Always return failure here. This is to allow other drivers to bind + * to this pci device. We don't really want to have control over the + * pci device, we only wanted to read as few register values from it. + */ + return -ENODEV; +} + +static struct pci_driver via686a_pci_driver = { + .name = "via686a", + .id_table = via686a_pci_ids, + .probe = via686a_pci_probe, +}; + +static int __init sm_via686a_init(void) +{ + return pci_register_driver(&via686a_pci_driver); +} + +static void __exit sm_via686a_exit(void) +{ + pci_unregister_driver(&via686a_pci_driver); + if (s_bridge != NULL) { + i2c_del_driver(&via686a_driver); + pci_dev_put(s_bridge); + s_bridge = NULL; + } +} + +MODULE_AUTHOR("Kyösti Mälkki , " + "Mark Studebaker " + "and Bob Dougherty "); +MODULE_DESCRIPTION("VIA 686A Sensor device"); +MODULE_LICENSE("GPL"); + +module_init(sm_via686a_init); +module_exit(sm_via686a_exit); diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c new file mode 100644 index 00000000000..8a40b6976e1 --- /dev/null +++ b/drivers/hwmon/w83627ehf.c @@ -0,0 +1,846 @@ +/* + w83627ehf - Driver for the hardware monitoring functionality of + the Winbond W83627EHF Super-I/O chip + Copyright (C) 2005 Jean Delvare + + Shamelessly ripped from the w83627hf driver + Copyright (C) 2003 Mark Studebaker + + Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help + in testing and debugging this driver. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + + Supports the following chips: + + Chip #vin #fan #pwm #temp chip_id man_id + w83627ehf - 5 - 3 0x88 0x5ca3 + + This is a preliminary version of the driver, only supporting the + fan and temperature inputs. The chip does much more than that. +*/ + +#include +#include +#include +#include +#include +#include +#include "lm75.h" + +/* Addresses to scan + The actual ISA address is read from Super-I/O configuration space */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(w83627ehf); + +/* + * Super-I/O constants and functions + */ + +static int REG; /* The register to read/write */ +static int VAL; /* The value to read/write */ + +#define W83627EHF_LD_HWM 0x0b + +#define SIO_REG_LDSEL 0x07 /* Logical device select */ +#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_REG_ENABLE 0x30 /* Logical device enable */ +#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ + +#define SIO_W83627EHF_ID 0x8840 +#define SIO_ID_MASK 0xFFC0 + +static inline void +superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +static inline void +superio_select(int ld) +{ + outb(SIO_REG_LDSEL, REG); + outb(ld, VAL); +} + +static inline void +superio_enter(void) +{ + outb(0x87, REG); + outb(0x87, REG); +} + +static inline void +superio_exit(void) +{ + outb(0x02, REG); + outb(0x02, VAL); +} + +/* + * ISA constants + */ + +#define REGION_LENGTH 8 +#define ADDR_REG_OFFSET 5 +#define DATA_REG_OFFSET 6 + +#define W83627EHF_REG_BANK 0x4E +#define W83627EHF_REG_CONFIG 0x40 +#define W83627EHF_REG_CHIP_ID 0x49 +#define W83627EHF_REG_MAN_ID 0x4F + +static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; +static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; + +#define W83627EHF_REG_TEMP1 0x27 +#define W83627EHF_REG_TEMP1_HYST 0x3a +#define W83627EHF_REG_TEMP1_OVER 0x39 +static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 }; +static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 }; +static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 }; +static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; + +/* Fan clock dividers are spread over the following five registers */ +#define W83627EHF_REG_FANDIV1 0x47 +#define W83627EHF_REG_FANDIV2 0x4B +#define W83627EHF_REG_VBAT 0x5D +#define W83627EHF_REG_DIODE 0x59 +#define W83627EHF_REG_SMI_OVT 0x4C + +/* + * Conversions + */ + +static inline unsigned int +fan_from_reg(u8 reg, unsigned int div) +{ + if (reg == 0 || reg == 255) + return 0; + return 1350000U / (reg * div); +} + +static inline unsigned int +div_from_reg(u8 reg) +{ + return 1 << reg; +} + +static inline int +temp1_from_reg(s8 reg) +{ + return reg * 1000; +} + +static inline s8 +temp1_to_reg(int temp) +{ + if (temp <= -128000) + return -128; + if (temp >= 127000) + return 127; + if (temp < 0) + return (temp - 500) / 1000; + return (temp + 500) / 1000; +} + +/* + * Data structures and manipulation thereof + */ + +struct w83627ehf_data { + struct i2c_client client; + struct semaphore lock; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + /* Register values */ + u8 fan[5]; + u8 fan_min[5]; + u8 fan_div[5]; + u8 has_fan; /* some fan inputs can be disabled */ + s8 temp1; + s8 temp1_max; + s8 temp1_max_hyst; + s16 temp[2]; + s16 temp_max[2]; + s16 temp_max_hyst[2]; +}; + +static inline int is_word_sized(u16 reg) +{ + return (((reg & 0xff00) == 0x100 + || (reg & 0xff00) == 0x200) + && ((reg & 0x00ff) == 0x50 + || (reg & 0x00ff) == 0x53 + || (reg & 0x00ff) == 0x55)); +} + +/* We assume that the default bank is 0, thus the following two functions do + nothing for registers which live in bank 0. For others, they respectively + set the bank register to the correct value (before the register is + accessed), and back to 0 (afterwards). */ +static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg) +{ + if (reg & 0xff00) { + outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); + outb_p(reg >> 8, client->addr + DATA_REG_OFFSET); + } +} + +static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg) +{ + if (reg & 0xff00) { + outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); + outb_p(0, client->addr + DATA_REG_OFFSET); + } +} + +static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + int res, word_sized = is_word_sized(reg); + + down(&data->lock); + + w83627ehf_set_bank(client, reg); + outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); + res = inb_p(client->addr + DATA_REG_OFFSET); + if (word_sized) { + outb_p((reg & 0xff) + 1, + client->addr + ADDR_REG_OFFSET); + res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET); + } + w83627ehf_reset_bank(client, reg); + + up(&data->lock); + + return res; +} + +static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + int word_sized = is_word_sized(reg); + + down(&data->lock); + + w83627ehf_set_bank(client, reg); + outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); + if (word_sized) { + outb_p(value >> 8, client->addr + DATA_REG_OFFSET); + outb_p((reg & 0xff) + 1, + client->addr + ADDR_REG_OFFSET); + } + outb_p(value & 0xff, client->addr + DATA_REG_OFFSET); + w83627ehf_reset_bank(client, reg); + + up(&data->lock); + return 0; +} + +/* This function assumes that the caller holds data->update_lock */ +static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) +{ + struct w83627ehf_data *data = i2c_get_clientdata(client); + u8 reg; + + switch (nr) { + case 0: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf) + | ((data->fan_div[0] & 0x03) << 4); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf) + | ((data->fan_div[0] & 0x04) << 3); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 1: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f) + | ((data->fan_div[1] & 0x03) << 6); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf) + | ((data->fan_div[1] & 0x04) << 4); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 2: + reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f) + | ((data->fan_div[2] & 0x03) << 6); + w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f) + | ((data->fan_div[2] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); + break; + case 3: + reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc) + | (data->fan_div[3] & 0x03); + w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); + reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f) + | ((data->fan_div[3] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg); + break; + case 4: + reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73) + | ((data->fan_div[4] & 0x03) << 3) + | ((data->fan_div[4] & 0x04) << 5); + w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); + break; + } +} + +static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) + || !data->valid) { + /* Fan clock dividers */ + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2); + data->fan_div[2] = (i >> 6) & 0x03; + i = w83627ehf_read_value(client, W83627EHF_REG_VBAT); + data->fan_div[0] |= (i >> 3) & 0x04; + data->fan_div[1] |= (i >> 4) & 0x04; + data->fan_div[2] |= (i >> 5) & 0x04; + if (data->has_fan & ((1 << 3) | (1 << 4))) { + i = w83627ehf_read_value(client, W83627EHF_REG_DIODE); + data->fan_div[3] = i & 0x03; + data->fan_div[4] = ((i >> 2) & 0x03) + | ((i >> 5) & 0x04); + } + if (data->has_fan & (1 << 3)) { + i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT); + data->fan_div[3] |= (i >> 5) & 0x04; + } + + /* Measured fan speeds and limits */ + for (i = 0; i < 5; i++) { + if (!(data->has_fan & (1 << i))) + continue; + + data->fan[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN[i]); + data->fan_min[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN_MIN[i]); + + /* If we failed to measure the fan speed and clock + divider can be increased, let's try that for next + time */ + if (data->fan[i] == 0xff + && data->fan_div[i] < 0x07) { + dev_dbg(&client->dev, "Increasing fan %d " + "clock divider from %u to %u\n", + i, div_from_reg(data->fan_div[i]), + div_from_reg(data->fan_div[i] + 1)); + data->fan_div[i]++; + w83627ehf_write_fan_div(client, i); + /* Preserve min limit if possible */ + if (data->fan_min[i] >= 2 + && data->fan_min[i] != 255) + w83627ehf_write_value(client, + W83627EHF_REG_FAN_MIN[i], + (data->fan_min[i] /= 2)); + } + } + + /* Measured temperatures and limits */ + data->temp1 = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1); + data->temp1_max = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1_OVER); + data->temp1_max_hyst = w83627ehf_read_value(client, + W83627EHF_REG_TEMP1_HYST); + for (i = 0; i < 2; i++) { + data->temp[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP[i]); + data->temp_max[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_OVER[i]); + data->temp_max_hyst[i] = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_HYST[i]); + } + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + return data; +} + +/* + * Sysfs callback functions + */ + +#define show_fan_reg(reg) \ +static ssize_t \ +show_##reg(struct device *dev, char *buf, int nr) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", \ + fan_from_reg(data->reg[nr], \ + div_from_reg(data->fan_div[nr]))); \ +} +show_fan_reg(fan); +show_fan_reg(fan_min); + +static ssize_t +show_fan_div(struct device *dev, char *buf, int nr) +{ + struct w83627ehf_data *data = w83627ehf_update_device(dev); + return sprintf(buf, "%u\n", + div_from_reg(data->fan_div[nr])); +} + +static ssize_t +store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + unsigned int val = simple_strtoul(buf, NULL, 10); + unsigned int reg; + u8 new_div; + + down(&data->update_lock); + if (!val) { + /* No min limit, alarm disabled */ + data->fan_min[nr] = 255; + new_div = data->fan_div[nr]; /* No change */ + dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1); + } else if ((reg = 1350000U / val) >= 128 * 255) { + /* Speed below this value cannot possibly be represented, + even with the highest divider (128) */ + data->fan_min[nr] = 254; + new_div = 7; /* 128 == (1 << 7) */ + dev_warn(dev, "fan%u low limit %u below minimum %u, set to " + "minimum\n", nr + 1, val, fan_from_reg(254, 128)); + } else if (!reg) { + /* Speed above this value cannot possibly be represented, + even with the lowest divider (1) */ + data->fan_min[nr] = 1; + new_div = 0; /* 1 == (1 << 0) */ + dev_warn(dev, "fan%u low limit %u above maximum %u, set to " + "maximum\n", nr + 1, val, fan_from_reg(1, 1)); + } else { + /* Automatically pick the best divider, i.e. the one such + that the min limit will correspond to a register value + in the 96..192 range */ + new_div = 0; + while (reg > 192 && new_div < 7) { + reg >>= 1; + new_div++; + } + data->fan_min[nr] = reg; + } + + /* Write both the fan clock divider (if it changed) and the new + fan min (unconditionally) */ + if (new_div != data->fan_div[nr]) { + if (new_div > data->fan_div[nr]) + data->fan[nr] >>= (data->fan_div[nr] - new_div); + else + data->fan[nr] <<= (new_div - data->fan_div[nr]); + + dev_dbg(dev, "fan%u clock divider changed from %u to %u\n", + nr + 1, div_from_reg(data->fan_div[nr]), + div_from_reg(new_div)); + data->fan_div[nr] = new_div; + w83627ehf_write_fan_div(client, nr); + } + w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr], + data->fan_min[nr]); + up(&data->update_lock); + + return count; +} + +#define sysfs_fan_offset(offset) \ +static ssize_t \ +show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_fan(dev, buf, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_reg_fan_##offset, NULL); + +#define sysfs_fan_min_offset(offset) \ +static ssize_t \ +show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_fan_min(dev, buf, offset-1); \ +} \ +static ssize_t \ +store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_fan_min(dev, buf, count, offset-1); \ +} \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_reg_fan##offset##_min, \ + store_reg_fan##offset##_min); + +#define sysfs_fan_div_offset(offset) \ +static ssize_t \ +show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_fan_div(dev, buf, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ + show_reg_fan##offset##_div, NULL); + +sysfs_fan_offset(1); +sysfs_fan_min_offset(1); +sysfs_fan_div_offset(1); +sysfs_fan_offset(2); +sysfs_fan_min_offset(2); +sysfs_fan_div_offset(2); +sysfs_fan_offset(3); +sysfs_fan_min_offset(3); +sysfs_fan_div_offset(3); +sysfs_fan_offset(4); +sysfs_fan_min_offset(4); +sysfs_fan_div_offset(4); +sysfs_fan_offset(5); +sysfs_fan_min_offset(5); +sysfs_fan_div_offset(5); + +#define show_temp1_reg(reg) \ +static ssize_t \ +show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \ +} +show_temp1_reg(temp1); +show_temp1_reg(temp1_max); +show_temp1_reg(temp1_max_hyst); + +#define store_temp1_reg(REG, reg) \ +static ssize_t \ +store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627ehf_data *data = i2c_get_clientdata(client); \ + u32 val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->temp1_##reg = temp1_to_reg(val); \ + w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \ + data->temp1_##reg); \ + up(&data->update_lock); \ + return count; \ +} +store_temp1_reg(OVER, max); +store_temp1_reg(HYST, max_hyst); + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR, + show_temp1_max, store_temp1_max); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR, + show_temp1_max_hyst, store_temp1_max_hyst); + +#define show_temp_reg(reg) \ +static ssize_t \ +show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + return sprintf(buf, "%d\n", \ + LM75_TEMP_FROM_REG(data->reg[nr])); \ +} +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_max_hyst); + +#define store_temp_reg(REG, reg) \ +static ssize_t \ +store_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627ehf_data *data = i2c_get_clientdata(client); \ + u32 val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->reg[nr] = LM75_TEMP_TO_REG(val); \ + w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \ + data->reg[nr]); \ + up(&data->update_lock); \ + return count; \ +} +store_temp_reg(OVER, temp_max); +store_temp_reg(HYST, temp_max_hyst); + +#define sysfs_temp_offset(offset) \ +static ssize_t \ +show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp(dev, buf, offset - 2); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_reg_temp##offset, NULL); + +#define sysfs_temp_reg_offset(reg, offset) \ +static ssize_t \ +show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_temp_##reg(dev, buf, offset - 2); \ +} \ +static ssize_t \ +store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_temp_##reg(dev, buf, count, offset - 2); \ +} \ +static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ + show_reg_temp##offset##_##reg, \ + store_reg_temp##offset##_##reg); + +sysfs_temp_offset(2); +sysfs_temp_reg_offset(max, 2); +sysfs_temp_reg_offset(max_hyst, 2); +sysfs_temp_offset(3); +sysfs_temp_reg_offset(max, 3); +sysfs_temp_reg_offset(max_hyst, 3); + +/* + * Driver and client management + */ + +static struct i2c_driver w83627ehf_driver; + +static void w83627ehf_init_client(struct i2c_client *client) +{ + int i; + u8 tmp; + + /* Start monitoring is needed */ + tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG); + if (!(tmp & 0x01)) + w83627ehf_write_value(client, W83627EHF_REG_CONFIG, + tmp | 0x01); + + /* Enable temp2 and temp3 if needed */ + for (i = 0; i < 2; i++) { + tmp = w83627ehf_read_value(client, + W83627EHF_REG_TEMP_CONFIG[i]); + if (tmp & 0x01) + w83627ehf_write_value(client, + W83627EHF_REG_TEMP_CONFIG[i], + tmp & 0xfe); + } +} + +static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct w83627ehf_data *data; + int i, err = 0; + + if (!i2c_is_isa_adapter(adapter)) + return 0; + + if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) { + err = -EBUSY; + goto exit; + } + + if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release; + } + memset(data, 0, sizeof(struct w83627ehf_data)); + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + init_MUTEX(&data->lock); + client->adapter = adapter; + client->driver = &w83627ehf_driver; + client->flags = 0; + + strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the i2c layer a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto exit_free; + + /* Initialize the chip */ + w83627ehf_init_client(client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 5; i++) + data->fan_min[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN_MIN[i]); + + /* It looks like fan4 and fan5 pins can be alternatively used + as fan on/off switches */ + data->has_fan = 0x07; /* fan1, fan2 and fan3 */ + i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); + if (i & (1 << 2)) + data->has_fan |= (1 << 3); + if (i & (1 << 0)) + data->has_fan |= (1 << 4); + + /* Register sysfs hooks */ + device_create_file(&client->dev, &dev_attr_fan1_input); + device_create_file(&client->dev, &dev_attr_fan1_min); + device_create_file(&client->dev, &dev_attr_fan1_div); + device_create_file(&client->dev, &dev_attr_fan2_input); + device_create_file(&client->dev, &dev_attr_fan2_min); + device_create_file(&client->dev, &dev_attr_fan2_div); + device_create_file(&client->dev, &dev_attr_fan3_input); + device_create_file(&client->dev, &dev_attr_fan3_min); + device_create_file(&client->dev, &dev_attr_fan3_div); + + if (data->has_fan & (1 << 3)) { + device_create_file(&client->dev, &dev_attr_fan4_input); + device_create_file(&client->dev, &dev_attr_fan4_min); + device_create_file(&client->dev, &dev_attr_fan4_div); + } + if (data->has_fan & (1 << 4)) { + device_create_file(&client->dev, &dev_attr_fan5_input); + device_create_file(&client->dev, &dev_attr_fan5_min); + device_create_file(&client->dev, &dev_attr_fan5_div); + } + + device_create_file(&client->dev, &dev_attr_temp1_input); + device_create_file(&client->dev, &dev_attr_temp1_max); + device_create_file(&client->dev, &dev_attr_temp1_max_hyst); + device_create_file(&client->dev, &dev_attr_temp2_input); + device_create_file(&client->dev, &dev_attr_temp2_max); + device_create_file(&client->dev, &dev_attr_temp2_max_hyst); + device_create_file(&client->dev, &dev_attr_temp3_input); + device_create_file(&client->dev, &dev_attr_temp3_max); + device_create_file(&client->dev, &dev_attr_temp3_max_hyst); + + return 0; + +exit_free: + kfree(data); +exit_release: + release_region(address, REGION_LENGTH); +exit: + return err; +} + +static int w83627ehf_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, w83627ehf_detect); +} + +static int w83627ehf_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + release_region(client->addr, REGION_LENGTH); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static struct i2c_driver w83627ehf_driver = { + .owner = THIS_MODULE, + .name = "w83627ehf", + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83627ehf_attach_adapter, + .detach_client = w83627ehf_detach_client, +}; + +static int __init w83627ehf_find(int sioaddr, int *address) +{ + u16 val; + + REG = sioaddr; + VAL = sioaddr + 1; + superio_enter(); + + val = (superio_inb(SIO_REG_DEVID) << 8) + | superio_inb(SIO_REG_DEVID + 1); + if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) { + superio_exit(); + return -ENODEV; + } + + superio_select(W83627EHF_LD_HWM); + val = (superio_inb(SIO_REG_ADDR) << 8) + | superio_inb(SIO_REG_ADDR + 1); + *address = val & ~(REGION_LENGTH - 1); + if (*address == 0) { + superio_exit(); + return -ENODEV; + } + + /* Activate logical device if needed */ + val = superio_inb(SIO_REG_ENABLE); + if (!(val & 0x01)) + superio_outb(SIO_REG_ENABLE, val | 0x01); + + superio_exit(); + return 0; +} + +static int __init sensors_w83627ehf_init(void) +{ + if (w83627ehf_find(0x2e, &normal_isa[0]) + && w83627ehf_find(0x4e, &normal_isa[0])) + return -ENODEV; + + return i2c_add_driver(&w83627ehf_driver); +} + +static void __exit sensors_w83627ehf_exit(void) +{ + i2c_del_driver(&w83627ehf_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("W83627EHF driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83627ehf_init); +module_exit(sensors_w83627ehf_exit); diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c new file mode 100644 index 00000000000..bd87a42e068 --- /dev/null +++ b/drivers/hwmon/w83627hf.c @@ -0,0 +1,1511 @@ +/* + w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998 - 2003 Frodo Looijaard , + Philip Edelbrock , + and Mark Studebaker + Ported to 2.6 by Bernhard C. Schrenk + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + Supports following chips: + + Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) + w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) + w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) + w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) + + For other winbond chips, and for i2c support in the above chips, + use w83781d.c. + + Note: automatic ("cruise") fan control for 697, 637 & 627thf not + supported yet. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "lm75.h" + +static u16 force_addr; +module_param(force_addr, ushort, 0); +MODULE_PARM_DESC(force_addr, + "Initialize the base address of the sensors"); +static u8 force_i2c = 0x1f; +module_param(force_i2c, byte, 0); +MODULE_PARM_DESC(force_i2c, + "Initialize the i2c address of the sensors"); + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf); + +static int init = 1; +module_param(init, bool, 0); +MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); + +/* modified from kernel/include/traps.c */ +static int REG; /* The register to read/write */ +#define DEV 0x07 /* Register: Logical device select */ +static int VAL; /* The value to read/write */ + +/* logical device numbers for superio_select (below) */ +#define W83627HF_LD_FDC 0x00 +#define W83627HF_LD_PRT 0x01 +#define W83627HF_LD_UART1 0x02 +#define W83627HF_LD_UART2 0x03 +#define W83627HF_LD_KBC 0x05 +#define W83627HF_LD_CIR 0x06 /* w83627hf only */ +#define W83627HF_LD_GAME 0x07 +#define W83627HF_LD_MIDI 0x07 +#define W83627HF_LD_GPIO1 0x07 +#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */ +#define W83627HF_LD_GPIO2 0x08 +#define W83627HF_LD_GPIO3 0x09 +#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */ +#define W83627HF_LD_ACPI 0x0a +#define W83627HF_LD_HWM 0x0b + +#define DEVID 0x20 /* Register: Device ID */ + +#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */ +#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */ +#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */ + +static inline void +superio_outb(int reg, int val) +{ + outb(reg, REG); + outb(val, VAL); +} + +static inline int +superio_inb(int reg) +{ + outb(reg, REG); + return inb(VAL); +} + +static inline void +superio_select(int ld) +{ + outb(DEV, REG); + outb(ld, VAL); +} + +static inline void +superio_enter(void) +{ + outb(0x87, REG); + outb(0x87, REG); +} + +static inline void +superio_exit(void) +{ + outb(0xAA, REG); +} + +#define W627_DEVID 0x52 +#define W627THF_DEVID 0x82 +#define W697_DEVID 0x60 +#define W637_DEVID 0x70 +#define WINB_ACT_REG 0x30 +#define WINB_BASE_REG 0x60 +/* Constants specified below */ + +/* Length of ISA address segment */ +#define WINB_EXTENT 8 + +/* Where are the ISA address/data registers relative to the base address */ +#define W83781D_ADDR_REG_OFFSET 5 +#define W83781D_DATA_REG_OFFSET 6 + +/* The W83781D registers */ +/* The W83782D registers for nr=7,8 are in bank 5 */ +#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ + (0x554 + (((nr) - 7) * 2))) +#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ + (0x555 + (((nr) - 7) * 2))) +#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ + (0x550 + (nr) - 7)) + +#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) +#define W83781D_REG_FAN(nr) (0x27 + (nr)) + +#define W83781D_REG_TEMP2_CONFIG 0x152 +#define W83781D_REG_TEMP3_CONFIG 0x252 +#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ + ((nr == 2) ? (0x0150) : \ + (0x27))) +#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \ + ((nr == 2) ? (0x153) : \ + (0x3A))) +#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \ + ((nr == 2) ? (0x155) : \ + (0x39))) + +#define W83781D_REG_BANK 0x4E + +#define W83781D_REG_CONFIG 0x40 +#define W83781D_REG_ALARM1 0x41 +#define W83781D_REG_ALARM2 0x42 +#define W83781D_REG_ALARM3 0x450 + +#define W83781D_REG_IRQ 0x4C +#define W83781D_REG_BEEP_CONFIG 0x4D +#define W83781D_REG_BEEP_INTS1 0x56 +#define W83781D_REG_BEEP_INTS2 0x57 +#define W83781D_REG_BEEP_INTS3 0x453 + +#define W83781D_REG_VID_FANDIV 0x47 + +#define W83781D_REG_CHIPID 0x49 +#define W83781D_REG_WCHIPID 0x58 +#define W83781D_REG_CHIPMAN 0x4F +#define W83781D_REG_PIN 0x4B + +#define W83781D_REG_VBAT 0x5D + +#define W83627HF_REG_PWM1 0x5A +#define W83627HF_REG_PWM2 0x5B +#define W83627HF_REG_PWMCLK12 0x5C + +#define W83627THF_REG_PWM1 0x01 /* 697HF and 637HF too */ +#define W83627THF_REG_PWM2 0x03 /* 697HF and 637HF too */ +#define W83627THF_REG_PWM3 0x11 /* 637HF too */ + +#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF too */ + +static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; +static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, + W83627THF_REG_PWM3 }; +#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ + regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1]) + +#define W83781D_REG_I2C_ADDR 0x48 +#define W83781D_REG_I2C_SUBADDR 0x4A + +/* Sensor selection */ +#define W83781D_REG_SCFG1 0x5D +static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; +#define W83781D_REG_SCFG2 0x59 +static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; +#define W83781D_DEFAULT_BETA 3435 + +/* Conversions. Limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) +#define IN_FROM_REG(val) ((val) * 16) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, + 254); +} + +#define TEMP_MIN (-128000) +#define TEMP_MAX ( 127000) + +/* TEMP: 0.001C/bit (-128C to +127C) + REG: 1C/bit, two's complement */ +static u8 TEMP_TO_REG(int temp) +{ + int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); + ntemp += (ntemp<0 ? -500 : 500); + return (u8)(ntemp / 1000); +} + +static int TEMP_FROM_REG(u8 reg) +{ + return (s8)reg * 1000; +} + +#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) + +#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) + +#define BEEP_MASK_FROM_REG(val) (val) +#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff) +#define BEEP_ENABLE_TO_REG(val) ((val)?1:0) +#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0) + +#define DIV_FROM_REG(val) (1 << (val)) + +static inline u8 DIV_TO_REG(long val) +{ + int i; + val = SENSORS_LIMIT(val, 1, 128) >> 1; + for (i = 0; i < 7; i++) { + if (val == 0) + break; + val >>= 1; + } + return ((u8) i); +} + +/* For each registered chip, we need to keep some data in memory. That + data is pointed to by w83627hf_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new client is allocated. */ +struct w83627hf_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + struct i2c_client *lm75; /* for secondary I2C addresses */ + /* pointer to array of 2 subclients */ + + u8 in[9]; /* Register value */ + u8 in_max[9]; /* Register value */ + u8 in_min[9]; /* Register value */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u8 temp; + u8 temp_max; /* Register value */ + u8 temp_max_hyst; /* Register value */ + u16 temp_add[2]; /* Register value */ + u16 temp_max_add[2]; /* Register value */ + u16 temp_max_hyst_add[2]; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ + u8 vid; /* Register encoding, combined */ + u32 alarms; /* Register encoding, combined */ + u32 beep_mask; /* Register encoding, combined */ + u8 beep_enable; /* Boolean */ + u8 pwm[3]; /* Register value */ + u16 sens[3]; /* 782D/783S only. + 1 = pentium diode; 2 = 3904 diode; + 3000-5000 = thermistor beta. + Default = 3435. + Other Betas unimplemented */ + u8 vrm; + u8 vrm_ovt; /* Register value, 627thf & 637hf only */ +}; + + +static int w83627hf_attach_adapter(struct i2c_adapter *adapter); +static int w83627hf_detect(struct i2c_adapter *adapter, int address, + int kind); +static int w83627hf_detach_client(struct i2c_client *client); + +static int w83627hf_read_value(struct i2c_client *client, u16 register); +static int w83627hf_write_value(struct i2c_client *client, u16 register, + u16 value); +static struct w83627hf_data *w83627hf_update_device(struct device *dev); +static void w83627hf_init_client(struct i2c_client *client); + +static struct i2c_driver w83627hf_driver = { + .owner = THIS_MODULE, + .name = "w83627hf", + .id = I2C_DRIVERID_W83627HF, + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83627hf_attach_adapter, + .detach_client = w83627hf_detach_client, +}; + +/* following are the sysfs callback functions */ +#define show_in_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83627hf_data *data = w83627hf_update_device(dev); \ + return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \ +} +show_in_reg(in) +show_in_reg(in_min) +show_in_reg(in_max) + +#define store_in_reg(REG, reg) \ +static ssize_t \ +store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627hf_data *data = i2c_get_clientdata(client); \ + u32 val; \ + \ + val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + data->in_##reg[nr] = IN_TO_REG(val); \ + w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \ + data->in_##reg[nr]); \ + \ + up(&data->update_lock); \ + return count; \ +} +store_in_reg(MIN, min) +store_in_reg(MAX, max) + +#define sysfs_in_offset(offset) \ +static ssize_t \ +show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); + +#define sysfs_in_reg_offset(reg, offset) \ +static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_##reg (dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_in_##reg (dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \ + show_regs_in_##reg##offset, store_regs_in_##reg##offset); + +#define sysfs_in_offsets(offset) \ +sysfs_in_offset(offset) \ +sysfs_in_reg_offset(min, offset) \ +sysfs_in_reg_offset(max, offset) + +sysfs_in_offsets(1); +sysfs_in_offsets(2); +sysfs_in_offsets(3); +sysfs_in_offsets(4); +sysfs_in_offsets(5); +sysfs_in_offsets(6); +sysfs_in_offsets(7); +sysfs_in_offsets(8); + +/* use a different set of functions for in0 */ +static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) +{ + long in0; + + if ((data->vrm_ovt & 0x01) && + (w83627thf == data->type || w83637hf == data->type)) + + /* use VRM9 calculation */ + in0 = (long)((reg * 488 + 70000 + 50) / 100); + else + /* use VRM8 (standard) calculation */ + in0 = (long)IN_FROM_REG(reg); + + return sprintf(buf,"%ld\n", in0); +} + +static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return show_in_0(data, buf, data->in[0]); +} + +static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return show_in_0(data, buf, data->in_min[0]); +} + +static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return show_in_0(data, buf, data->in_max[0]); +} + +static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + if ((data->vrm_ovt & 0x01) && + (w83627thf == data->type || w83637hf == data->type)) + + /* use VRM9 calculation */ + data->in_min[0] = (u8)(((val * 100) - 70000 + 244) / 488); + else + /* use VRM8 (standard) calculation */ + data->in_min[0] = IN_TO_REG(val); + + w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]); + up(&data->update_lock); + return count; +} + +static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + if ((data->vrm_ovt & 0x01) && + (w83627thf == data->type || w83637hf == data->type)) + + /* use VRM9 calculation */ + data->in_max[0] = (u8)(((val * 100) - 70000 + 244) / 488); + else + /* use VRM8 (standard) calculation */ + data->in_max[0] = IN_TO_REG(val); + + w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]); + up(&data->update_lock); + return count; +} + +static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL); +static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, + show_regs_in_min0, store_regs_in_min0); +static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, + show_regs_in_max0, store_regs_in_max0); + +#define device_create_file_in(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_in##offset##_input); \ +device_create_file(&client->dev, &dev_attr_in##offset##_min); \ +device_create_file(&client->dev, &dev_attr_in##offset##_max); \ +} while (0) + +#define show_fan_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83627hf_data *data = w83627hf_update_device(dev); \ + return sprintf(buf,"%ld\n", \ + FAN_FROM_REG(data->reg[nr-1], \ + (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ +} +show_fan_reg(fan); +show_fan_reg(fan_min); + +static ssize_t +store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr - 1] = + FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); + w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr), + data->fan_min[nr - 1]); + + up(&data->update_lock); + return count; +} + +#define sysfs_fan_offset(offset) \ +static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); + +#define sysfs_fan_min_offset(offset) \ +static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_fan_min(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_regs_fan_min##offset, store_regs_fan_min##offset); + +sysfs_fan_offset(1); +sysfs_fan_min_offset(1); +sysfs_fan_offset(2); +sysfs_fan_min_offset(2); +sysfs_fan_offset(3); +sysfs_fan_min_offset(3); + +#define device_create_file_fan(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ +device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ +} while (0) + +#define show_temp_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83627hf_data *data = w83627hf_update_device(dev); \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + return sprintf(buf,"%ld\n", \ + (long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ + } else { /* TEMP1 */ \ + return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ + } \ +} +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_max_hyst); + +#define store_temp_reg(REG, reg) \ +static ssize_t \ +store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627hf_data *data = i2c_get_clientdata(client); \ + u32 val; \ + \ + val = simple_strtoul(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ + w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + data->temp_##reg##_add[nr-2]); \ + } else { /* TEMP1 */ \ + data->temp_##reg = TEMP_TO_REG(val); \ + w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + data->temp_##reg); \ + } \ + \ + up(&data->update_lock); \ + return count; \ +} +store_temp_reg(OVER, max); +store_temp_reg(HYST, max_hyst); + +#define sysfs_temp_offset(offset) \ +static ssize_t \ +show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); + +#define sysfs_temp_reg_offset(reg, offset) \ +static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_##reg (dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_temp_##reg (dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ + show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); + +#define sysfs_temp_offsets(offset) \ +sysfs_temp_offset(offset) \ +sysfs_temp_reg_offset(max, offset) \ +sysfs_temp_reg_offset(max_hyst, offset) + +sysfs_temp_offsets(1); +sysfs_temp_offsets(2); +sysfs_temp_offsets(3); + +#define device_create_file_temp(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ +device_create_file(&client->dev, &dev_attr_temp##offset##_max); \ +device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ +} while (0) + +static ssize_t +show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +#define device_create_file_vid(client) \ +device_create_file(&client->dev, &dev_attr_cpu0_vid) + +static ssize_t +show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->vrm); +} +static ssize_t +store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +#define device_create_file_vrm(client) \ +device_create_file(&client->dev, &dev_attr_vrm) + +static ssize_t +show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->alarms); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +#define device_create_file_alarms(client) \ +device_create_file(&client->dev, &dev_attr_alarms) + +#define show_beep_reg(REG, reg) \ +static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct w83627hf_data *data = w83627hf_update_device(dev); \ + return sprintf(buf,"%ld\n", \ + (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \ +} +show_beep_reg(ENABLE, enable) +show_beep_reg(MASK, mask) + +#define BEEP_ENABLE 0 /* Store beep_enable */ +#define BEEP_MASK 1 /* Store beep_mask */ + +static ssize_t +store_beep_reg(struct device *dev, const char *buf, size_t count, + int update_mask) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val, val2; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ + data->beep_mask = BEEP_MASK_TO_REG(val); + w83627hf_write_value(client, W83781D_REG_BEEP_INTS1, + data->beep_mask & 0xff); + w83627hf_write_value(client, W83781D_REG_BEEP_INTS3, + ((data->beep_mask) >> 16) & 0xff); + val2 = (data->beep_mask >> 8) & 0x7f; + } else { /* We are storing beep_enable */ + val2 = + w83627hf_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; + data->beep_enable = BEEP_ENABLE_TO_REG(val); + } + + w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, + val2 | data->beep_enable << 7); + + up(&data->update_lock); + return count; +} + +#define sysfs_beep(REG, reg) \ +static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_beep_##reg(dev, attr, buf); \ +} \ +static ssize_t \ +store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_beep_reg(dev, buf, count, BEEP_##REG); \ +} \ +static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \ + show_regs_beep_##reg, store_regs_beep_##reg); + +sysfs_beep(ENABLE, enable); +sysfs_beep(MASK, mask); + +#define device_create_file_beep(client) \ +do { \ +device_create_file(&client->dev, &dev_attr_beep_enable); \ +device_create_file(&client->dev, &dev_attr_beep_mask); \ +} while (0) + +static ssize_t +show_fan_div_reg(struct device *dev, char *buf, int nr) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", + (long) DIV_FROM_REG(data->fan_div[nr - 1])); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t +store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + unsigned long min; + u8 reg; + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + /* Save fan_min */ + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + + data->fan_div[nr] = DIV_TO_REG(val); + + reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) + & (nr==0 ? 0xcf : 0x3f)) + | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); + w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); + + reg = (w83627hf_read_value(client, W83781D_REG_VBAT) + & ~(1 << (5 + nr))) + | ((data->fan_div[nr] & 0x04) << (3 + nr)); + w83627hf_write_value(client, W83781D_REG_VBAT, reg); + + /* Restore fan_min */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); + + up(&data->update_lock); + return count; +} + +#define sysfs_fan_div(offset) \ +static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div_reg(dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_fan_div_reg(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_regs_fan_div_##offset, store_regs_fan_div_##offset); + +sysfs_fan_div(1); +sysfs_fan_div(2); +sysfs_fan_div(3); + +#define device_create_file_fan_div(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ +} while (0) + +static ssize_t +show_pwm_reg(struct device *dev, char *buf, int nr) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]); +} + +static ssize_t +store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + if (data->type == w83627thf) { + /* bits 0-3 are reserved in 627THF */ + data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0; + w83627hf_write_value(client, + W836X7HF_REG_PWM(data->type, nr), + data->pwm[nr - 1] | + (w83627hf_read_value(client, + W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); + } else { + data->pwm[nr - 1] = PWM_TO_REG(val); + w83627hf_write_value(client, + W836X7HF_REG_PWM(data->type, nr), + data->pwm[nr - 1]); + } + + up(&data->update_lock); + return count; +} + +#define sysfs_pwm(offset) \ +static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwm_reg(dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_pwm_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_regs_pwm_##offset, store_regs_pwm_##offset); + +sysfs_pwm(1); +sysfs_pwm(2); +sysfs_pwm(3); + +#define device_create_file_pwm(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_pwm##offset); \ +} while (0) + +static ssize_t +show_sensor_reg(struct device *dev, char *buf, int nr) +{ + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); +} + +static ssize_t +store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + u32 val, tmp; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + switch (val) { + case 1: /* PII/Celeron diode */ + tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); + w83627hf_write_value(client, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr - 1]); + tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); + w83627hf_write_value(client, W83781D_REG_SCFG2, + tmp | BIT_SCFG2[nr - 1]); + data->sens[nr - 1] = val; + break; + case 2: /* 3904 */ + tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); + w83627hf_write_value(client, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr - 1]); + tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); + w83627hf_write_value(client, W83781D_REG_SCFG2, + tmp & ~BIT_SCFG2[nr - 1]); + data->sens[nr - 1] = val; + break; + case W83781D_DEFAULT_BETA: /* thermistor */ + tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); + w83627hf_write_value(client, W83781D_REG_SCFG1, + tmp & ~BIT_SCFG1[nr - 1]); + data->sens[nr - 1] = val; + break; + default: + dev_err(&client->dev, + "Invalid sensor type %ld; must be 1, 2, or %d\n", + (long) val, W83781D_DEFAULT_BETA); + break; + } + + up(&data->update_lock); + return count; +} + +#define sysfs_sensor(offset) \ +static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_sensor_reg(dev, buf, offset); \ +} \ +static ssize_t \ +store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_sensor_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ + show_regs_sensor_##offset, store_regs_sensor_##offset); + +sysfs_sensor(1); +sysfs_sensor(2); +sysfs_sensor(3); + +#define device_create_file_sensor(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_temp##offset##_type); \ +} while (0) + + +/* This function is called when: + * w83627hf_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and w83627hf_driver is still present) */ +static int w83627hf_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, w83627hf_detect); +} + +static int w83627hf_find(int sioaddr, int *address) +{ + u16 val; + + REG = sioaddr; + VAL = sioaddr + 1; + + superio_enter(); + val= superio_inb(DEVID); + if(val != W627_DEVID && + val != W627THF_DEVID && + val != W697_DEVID && + val != W637_DEVID) { + superio_exit(); + return -ENODEV; + } + + superio_select(W83627HF_LD_HWM); + val = (superio_inb(WINB_BASE_REG) << 8) | + superio_inb(WINB_BASE_REG + 1); + *address = val & ~(WINB_EXTENT - 1); + if (*address == 0 && force_addr == 0) { + superio_exit(); + return -ENODEV; + } + if (force_addr) + *address = force_addr; /* so detect will get called */ + + superio_exit(); + return 0; +} + +int w83627hf_detect(struct i2c_adapter *adapter, int address, + int kind) +{ + int val; + struct i2c_client *new_client; + struct w83627hf_data *data; + int err = 0; + const char *client_name = ""; + + if (!i2c_is_isa_adapter(adapter)) { + err = -ENODEV; + goto ERROR0; + } + + if(force_addr) + address = force_addr & ~(WINB_EXTENT - 1); + + if (!request_region(address, WINB_EXTENT, w83627hf_driver.name)) { + err = -EBUSY; + goto ERROR0; + } + + if(force_addr) { + printk("w83627hf.o: forcing ISA address 0x%04X\n", address); + superio_enter(); + superio_select(W83627HF_LD_HWM); + superio_outb(WINB_BASE_REG, address >> 8); + superio_outb(WINB_BASE_REG+1, address & 0xff); + superio_exit(); + } + + superio_enter(); + val= superio_inb(DEVID); + if(val == W627_DEVID) + kind = w83627hf; + else if(val == W697_DEVID) + kind = w83697hf; + else if(val == W627THF_DEVID) + kind = w83627thf; + else if(val == W637_DEVID) + kind = w83637hf; + else { + dev_info(&adapter->dev, + "Unsupported chip (dev_id=0x%02X).\n", val); + goto ERROR1; + } + + superio_select(W83627HF_LD_HWM); + if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0) + superio_outb(WINB_ACT_REG, 1); + superio_exit(); + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access w83627hf_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR1; + } + memset(data, 0, sizeof(struct w83627hf_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &w83627hf_driver; + new_client->flags = 0; + + + if (kind == w83627hf) { + client_name = "w83627hf"; + } else if (kind == w83627thf) { + client_name = "w83627thf"; + } else if (kind == w83697hf) { + client_name = "w83697hf"; + } else if (kind == w83637hf) { + client_name = "w83637hf"; + } + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + data->type = kind; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR2; + + data->lm75 = NULL; + + /* Initialize the chip */ + w83627hf_init_client(new_client); + + /* A few vars need to be filled upon startup */ + data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1)); + data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2)); + data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3)); + + /* Register sysfs hooks */ + device_create_file_in(new_client, 0); + if (kind != w83697hf) + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + device_create_file_in(new_client, 3); + device_create_file_in(new_client, 4); + if (kind != w83627thf && kind != w83637hf) { + device_create_file_in(new_client, 5); + device_create_file_in(new_client, 6); + } + device_create_file_in(new_client, 7); + device_create_file_in(new_client, 8); + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + if (kind != w83697hf) + device_create_file_fan(new_client, 3); + + device_create_file_temp(new_client, 1); + device_create_file_temp(new_client, 2); + if (kind != w83697hf) + device_create_file_temp(new_client, 3); + + if (kind != w83697hf) + device_create_file_vid(new_client); + + if (kind != w83697hf) + device_create_file_vrm(new_client); + + device_create_file_fan_div(new_client, 1); + device_create_file_fan_div(new_client, 2); + if (kind != w83697hf) + device_create_file_fan_div(new_client, 3); + + device_create_file_alarms(new_client); + + device_create_file_beep(new_client); + + device_create_file_pwm(new_client, 1); + device_create_file_pwm(new_client, 2); + if (kind == w83627thf || kind == w83637hf) + device_create_file_pwm(new_client, 3); + + device_create_file_sensor(new_client, 1); + device_create_file_sensor(new_client, 2); + if (kind != w83697hf) + device_create_file_sensor(new_client, 3); + + return 0; + + ERROR2: + kfree(data); + ERROR1: + release_region(address, WINB_EXTENT); + ERROR0: + return err; +} + +static int w83627hf_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + release_region(client->addr, WINB_EXTENT); + kfree(i2c_get_clientdata(client)); + + return 0; +} + + +/* + ISA access must always be locked explicitly! + We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, + would slow down the W83781D access and should not be necessary. + There are some ugly typecasts here, but the good news is - they should + nowhere else be necessary! */ +static int w83627hf_read_value(struct i2c_client *client, u16 reg) +{ + struct w83627hf_data *data = i2c_get_clientdata(client); + int res, word_sized; + + down(&data->lock); + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x50) + || ((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + } + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); + res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); + if (word_sized) { + outb_p((reg & 0xff) + 1, + client->addr + W83781D_ADDR_REG_OFFSET); + res = + (res << 8) + inb_p(client->addr + + W83781D_DATA_REG_OFFSET); + } + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } + up(&data->lock); + return res; +} + +static int w83627thf_read_gpio5(struct i2c_client *client) +{ + int res = 0xff, sel; + + superio_enter(); + superio_select(W83627HF_LD_GPIO5); + + /* Make sure these GPIO pins are enabled */ + if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) { + dev_dbg(&client->dev, "GPIO5 disabled, no VID function\n"); + goto exit; + } + + /* Make sure the pins are configured for input + There must be at least five (VRM 9), and possibly 6 (VRM 10) */ + sel = superio_inb(W83627THF_GPIO5_IOSR); + if ((sel & 0x1f) != 0x1f) { + dev_dbg(&client->dev, "GPIO5 not configured for VID " + "function\n"); + goto exit; + } + + dev_info(&client->dev, "Reading VID from GPIO5\n"); + res = superio_inb(W83627THF_GPIO5_DR) & sel; + +exit: + superio_exit(); + return res; +} + +static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) +{ + struct w83627hf_data *data = i2c_get_clientdata(client); + int word_sized; + + down(&data->lock); + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + } + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); + if (word_sized) { + outb_p(value >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + outb_p((reg & 0xff) + 1, + client->addr + W83781D_ADDR_REG_OFFSET); + } + outb_p(value & 0xff, + client->addr + W83781D_DATA_REG_OFFSET); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } + up(&data->lock); + return 0; +} + +/* Called when we have found a new W83781D. It should set limits, etc. */ +static void w83627hf_init_client(struct i2c_client *client) +{ + struct w83627hf_data *data = i2c_get_clientdata(client); + int i; + int type = data->type; + u8 tmp; + + if(init) { + /* save this register */ + i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG); + /* Reset all except Watchdog values and last conversion values + This sets fan-divs to 2, among others */ + w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80); + /* Restore the register and disable power-on abnormal beep. + This saves FAN 1/2/3 input/output values set by BIOS. */ + w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); + /* Disable master beep-enable (reset turns it on). + Individual beeps should be reset to off but for some reason + disabling this bit helps some people not get beeped */ + w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0); + } + + /* Minimize conflicts with other winbond i2c-only clients... */ + /* disable i2c subclients... how to disable main i2c client?? */ + /* force i2c address to relatively uncommon address */ + w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89); + w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c); + + /* Read VID only once */ + if (w83627hf == data->type || w83637hf == data->type) { + int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); + int hi = w83627hf_read_value(client, W83781D_REG_CHIPID); + data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); + } else if (w83627thf == data->type) { + data->vid = w83627thf_read_gpio5(client) & 0x3f; + } + + /* Read VRM & OVT Config only once */ + if (w83627thf == data->type || w83637hf == data->type) { + data->vrm_ovt = + w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); + data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82; + } else { + /* Convert VID to voltage based on default VRM */ + data->vrm = i2c_which_vrm(); + } + + tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); + for (i = 1; i <= 3; i++) { + if (!(tmp & BIT_SCFG1[i - 1])) { + data->sens[i - 1] = W83781D_DEFAULT_BETA; + } else { + if (w83627hf_read_value + (client, + W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) + data->sens[i - 1] = 1; + else + data->sens[i - 1] = 2; + } + if ((type == w83697hf) && (i == 2)) + break; + } + + if(init) { + /* Enable temp2 */ + tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp2, readings " + "might not make sense\n"); + w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG, + tmp & 0xfe); + } + + /* Enable temp3 */ + if (type != w83697hf) { + tmp = w83627hf_read_value(client, + W83781D_REG_TEMP3_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp3, " + "readings might not make sense\n"); + w83627hf_write_value(client, + W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); + } + } + + if (type == w83627hf) { + /* enable PWM2 control (can't hurt since PWM reg + should have been reset to 0xff) */ + w83627hf_write_value(client, W83627HF_REG_PWMCLK12, + 0x19); + } + /* enable comparator mode for temp2 and temp3 so + alarm indication will work correctly */ + i = w83627hf_read_value(client, W83781D_REG_IRQ); + if (!(i & 0x40)) + w83627hf_write_value(client, W83781D_REG_IRQ, + i | 0x40); + } + + /* Start monitoring */ + w83627hf_write_value(client, W83781D_REG_CONFIG, + (w83627hf_read_value(client, + W83781D_REG_CONFIG) & 0xf7) + | 0x01); +} + +static struct w83627hf_data *w83627hf_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627hf_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + for (i = 0; i <= 8; i++) { + /* skip missing sensors */ + if (((data->type == w83697hf) && (i == 1)) || + ((data->type == w83627thf || data->type == w83637hf) + && (i == 4 || i == 5))) + continue; + data->in[i] = + w83627hf_read_value(client, W83781D_REG_IN(i)); + data->in_min[i] = + w83627hf_read_value(client, + W83781D_REG_IN_MIN(i)); + data->in_max[i] = + w83627hf_read_value(client, + W83781D_REG_IN_MAX(i)); + } + for (i = 1; i <= 3; i++) { + data->fan[i - 1] = + w83627hf_read_value(client, W83781D_REG_FAN(i)); + data->fan_min[i - 1] = + w83627hf_read_value(client, + W83781D_REG_FAN_MIN(i)); + } + for (i = 1; i <= 3; i++) { + u8 tmp = w83627hf_read_value(client, + W836X7HF_REG_PWM(data->type, i)); + /* bits 0-3 are reserved in 627THF */ + if (data->type == w83627thf) + tmp &= 0xf0; + data->pwm[i - 1] = tmp; + if(i == 2 && + (data->type == w83627hf || data->type == w83697hf)) + break; + } + + data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1)); + data->temp_max = + w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1)); + data->temp_max_hyst = + w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1)); + data->temp_add[0] = + w83627hf_read_value(client, W83781D_REG_TEMP(2)); + data->temp_max_add[0] = + w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2)); + data->temp_max_hyst_add[0] = + w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2)); + if (data->type != w83697hf) { + data->temp_add[1] = + w83627hf_read_value(client, W83781D_REG_TEMP(3)); + data->temp_max_add[1] = + w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3)); + data->temp_max_hyst_add[1] = + w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3)); + } + + i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + if (data->type != w83697hf) { + data->fan_div[2] = (w83627hf_read_value(client, + W83781D_REG_PIN) >> 6) & 0x03; + } + i = w83627hf_read_value(client, W83781D_REG_VBAT); + data->fan_div[0] |= (i >> 3) & 0x04; + data->fan_div[1] |= (i >> 4) & 0x04; + if (data->type != w83697hf) + data->fan_div[2] |= (i >> 5) & 0x04; + data->alarms = + w83627hf_read_value(client, W83781D_REG_ALARM1) | + (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) | + (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16); + i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2); + data->beep_enable = i >> 7; + data->beep_mask = ((i & 0x7f) << 8) | + w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) | + w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16; + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_w83627hf_init(void) +{ + int addr; + + if (w83627hf_find(0x2e, &addr) + && w83627hf_find(0x4e, &addr)) { + return -ENODEV; + } + normal_isa[0] = addr; + + return i2c_add_driver(&w83627hf_driver); +} + +static void __exit sensors_w83627hf_exit(void) +{ + i2c_del_driver(&w83627hf_driver); +} + +MODULE_AUTHOR("Frodo Looijaard , " + "Philip Edelbrock , " + "and Mark Studebaker "); +MODULE_DESCRIPTION("W83627HF driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83627hf_init); +module_exit(sensors_w83627hf_exit); diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c new file mode 100644 index 00000000000..0bb131ce09e --- /dev/null +++ b/drivers/hwmon/w83781d.c @@ -0,0 +1,1632 @@ +/* + w83781d.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998 - 2001 Frodo Looijaard , + Philip Edelbrock , + and Mark Studebaker + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + Supports following chips: + + Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + as99127f 7 3 0 3 0x31 0x12c3 yes no + as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no + w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes + w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) + w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes + w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "lm75.h" + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f); +I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " + "{bus, clientaddr, subclientaddr1, subclientaddr2}"); + +static int init = 1; +module_param(init, bool, 0); +MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); + +/* Constants specified below */ + +/* Length of ISA address segment */ +#define W83781D_EXTENT 8 + +/* Where are the ISA address/data registers relative to the base address */ +#define W83781D_ADDR_REG_OFFSET 5 +#define W83781D_DATA_REG_OFFSET 6 + +/* The W83781D registers */ +/* The W83782D registers for nr=7,8 are in bank 5 */ +#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ + (0x554 + (((nr) - 7) * 2))) +#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ + (0x555 + (((nr) - 7) * 2))) +#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ + (0x550 + (nr) - 7)) + +#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) +#define W83781D_REG_FAN(nr) (0x27 + (nr)) + +#define W83781D_REG_BANK 0x4E +#define W83781D_REG_TEMP2_CONFIG 0x152 +#define W83781D_REG_TEMP3_CONFIG 0x252 +#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ + ((nr == 2) ? (0x0150) : \ + (0x27))) +#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \ + ((nr == 2) ? (0x153) : \ + (0x3A))) +#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \ + ((nr == 2) ? (0x155) : \ + (0x39))) + +#define W83781D_REG_CONFIG 0x40 +#define W83781D_REG_ALARM1 0x41 +#define W83781D_REG_ALARM2 0x42 +#define W83781D_REG_ALARM3 0x450 /* not on W83781D */ + +#define W83781D_REG_IRQ 0x4C +#define W83781D_REG_BEEP_CONFIG 0x4D +#define W83781D_REG_BEEP_INTS1 0x56 +#define W83781D_REG_BEEP_INTS2 0x57 +#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */ + +#define W83781D_REG_VID_FANDIV 0x47 + +#define W83781D_REG_CHIPID 0x49 +#define W83781D_REG_WCHIPID 0x58 +#define W83781D_REG_CHIPMAN 0x4F +#define W83781D_REG_PIN 0x4B + +/* 782D/783S only */ +#define W83781D_REG_VBAT 0x5D + +/* PWM 782D (1-4) and 783S (1-2) only */ +#define W83781D_REG_PWM1 0x5B /* 782d and 783s/627hf datasheets disagree */ + /* on which is which; */ +#define W83781D_REG_PWM2 0x5A /* We follow the 782d convention here, */ + /* However 782d is probably wrong. */ +#define W83781D_REG_PWM3 0x5E +#define W83781D_REG_PWM4 0x5F +#define W83781D_REG_PWMCLK12 0x5C +#define W83781D_REG_PWMCLK34 0x45C +static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2, + W83781D_REG_PWM3, W83781D_REG_PWM4 +}; + +#define W83781D_REG_PWM(nr) (regpwm[(nr) - 1]) + +#define W83781D_REG_I2C_ADDR 0x48 +#define W83781D_REG_I2C_SUBADDR 0x4A + +/* The following are undocumented in the data sheets however we + received the information in an email from Winbond tech support */ +/* Sensor selection - not on 781d */ +#define W83781D_REG_SCFG1 0x5D +static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; + +#define W83781D_REG_SCFG2 0x59 +static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; + +#define W83781D_DEFAULT_BETA 3435 + +/* RT Table registers */ +#define W83781D_REG_RT_IDX 0x50 +#define W83781D_REG_RT_VAL 0x51 + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) +#define IN_FROM_REG(val) (((val) * 16) / 10) + +static inline u8 +FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ + ((val) == 255 ? 0 : \ + 1350000 / ((val) * (div)))) + +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ + : (val)) / 1000, 0, 0xff)) +#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) + +#define PWM_FROM_REG(val) (val) +#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) +#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \ + (val) ^ 0x7fff : (val)) +#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \ + (~(val)) & 0x7fff : (val) & 0xffffff) + +#define BEEP_ENABLE_TO_REG(val) ((val) ? 1 : 0) +#define BEEP_ENABLE_FROM_REG(val) ((val) ? 1 : 0) + +#define DIV_FROM_REG(val) (1 << (val)) + +static inline u8 +DIV_TO_REG(long val, enum chips type) +{ + int i; + val = SENSORS_LIMIT(val, 1, + ((type == w83781d + || type == as99127f) ? 8 : 128)) >> 1; + for (i = 0; i < 7; i++) { + if (val == 0) + break; + val >>= 1; + } + return ((u8) i); +} + +/* There are some complications in a module like this. First off, W83781D chips + may be both present on the SMBus and the ISA bus, and we have to handle + those cases separately at some places. Second, there might be several + W83781D chips available (well, actually, that is probably never done; but + it is a clean illustration of how to handle a case like that). Finally, + a specific chip may be attached to *both* ISA and SMBus, and we would + not like to detect it double. Fortunately, in the case of the W83781D at + least, a register tells us what SMBus address we are on, so that helps + a bit - except if there could be more than one SMBus. Groan. No solution + for this yet. */ + +/* This module may seem overly long and complicated. In fact, it is not so + bad. Quite a lot of bookkeeping is done. A real driver can often cut + some corners. */ + +/* For each registered W83781D, we need to keep some data in memory. That + data is pointed to by w83781d_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new w83781d client is + allocated. */ +struct w83781d_data { + struct i2c_client client; + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + struct i2c_client *lm75[2]; /* for secondary I2C addresses */ + /* array of 2 pointers to subclients */ + + u8 in[9]; /* Register value - 8 & 9 for 782D only */ + u8 in_max[9]; /* Register value - 8 & 9 for 782D only */ + u8 in_min[9]; /* Register value - 8 & 9 for 782D only */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u8 temp; + u8 temp_max; /* Register value */ + u8 temp_max_hyst; /* Register value */ + u16 temp_add[2]; /* Register value */ + u16 temp_max_add[2]; /* Register value */ + u16 temp_max_hyst_add[2]; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ + u8 vid; /* Register encoding, combined */ + u32 alarms; /* Register encoding, combined */ + u32 beep_mask; /* Register encoding, combined */ + u8 beep_enable; /* Boolean */ + u8 pwm[4]; /* Register value */ + u8 pwmenable[4]; /* Boolean */ + u16 sens[3]; /* 782D/783S only. + 1 = pentium diode; 2 = 3904 diode; + 3000-5000 = thermistor beta. + Default = 3435. + Other Betas unimplemented */ + u8 vrm; +}; + +static int w83781d_attach_adapter(struct i2c_adapter *adapter); +static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind); +static int w83781d_detach_client(struct i2c_client *client); + +static int w83781d_read_value(struct i2c_client *client, u16 register); +static int w83781d_write_value(struct i2c_client *client, u16 register, + u16 value); +static struct w83781d_data *w83781d_update_device(struct device *dev); +static void w83781d_init_client(struct i2c_client *client); + +static struct i2c_driver w83781d_driver = { + .owner = THIS_MODULE, + .name = "w83781d", + .id = I2C_DRIVERID_W83781D, + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83781d_attach_adapter, + .detach_client = w83781d_detach_client, +}; + +/* following are the sysfs callback functions */ +#define show_in_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83781d_data *data = w83781d_update_device(dev); \ + return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr] * 10)); \ +} +show_in_reg(in); +show_in_reg(in_min); +show_in_reg(in_max); + +#define store_in_reg(REG, reg) \ +static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83781d_data *data = i2c_get_clientdata(client); \ + u32 val; \ + \ + val = simple_strtoul(buf, NULL, 10) / 10; \ + \ + down(&data->update_lock); \ + data->in_##reg[nr] = IN_TO_REG(val); \ + w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \ + \ + up(&data->update_lock); \ + return count; \ +} +store_in_reg(MIN, min); +store_in_reg(MAX, max); + +#define sysfs_in_offset(offset) \ +static ssize_t \ +show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in(dev, buf, offset); \ +} \ +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); + +#define sysfs_in_reg_offset(reg, offset) \ +static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_in_##reg (dev, buf, offset); \ +} \ +static ssize_t store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_in_##reg (dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset); + +#define sysfs_in_offsets(offset) \ +sysfs_in_offset(offset); \ +sysfs_in_reg_offset(min, offset); \ +sysfs_in_reg_offset(max, offset); + +sysfs_in_offsets(0); +sysfs_in_offsets(1); +sysfs_in_offsets(2); +sysfs_in_offsets(3); +sysfs_in_offsets(4); +sysfs_in_offsets(5); +sysfs_in_offsets(6); +sysfs_in_offsets(7); +sysfs_in_offsets(8); + +#define device_create_file_in(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_in##offset##_input); \ +device_create_file(&client->dev, &dev_attr_in##offset##_min); \ +device_create_file(&client->dev, &dev_attr_in##offset##_max); \ +} while (0) + +#define show_fan_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83781d_data *data = w83781d_update_device(dev); \ + return sprintf(buf,"%ld\n", \ + FAN_FROM_REG(data->reg[nr-1], (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ +} +show_fan_reg(fan); +show_fan_reg(fan_min); + +static ssize_t +store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->fan_min[nr - 1] = + FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); + w83781d_write_value(client, W83781D_REG_FAN_MIN(nr), + data->fan_min[nr - 1]); + + up(&data->update_lock); + return count; +} + +#define sysfs_fan_offset(offset) \ +static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan(dev, buf, offset); \ +} \ +static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); + +#define sysfs_fan_min_offset(offset) \ +static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_min(dev, buf, offset); \ +} \ +static ssize_t store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_fan_min(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset); + +sysfs_fan_offset(1); +sysfs_fan_min_offset(1); +sysfs_fan_offset(2); +sysfs_fan_min_offset(2); +sysfs_fan_offset(3); +sysfs_fan_min_offset(3); + +#define device_create_file_fan(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ +device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ +} while (0) + +#define show_temp_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct w83781d_data *data = w83781d_update_device(dev); \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + return sprintf(buf,"%d\n", \ + LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ + } else { /* TEMP1 */ \ + return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ + } \ +} +show_temp_reg(temp); +show_temp_reg(temp_max); +show_temp_reg(temp_max_hyst); + +#define store_temp_reg(REG, reg) \ +static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83781d_data *data = i2c_get_clientdata(client); \ + s32 val; \ + \ + val = simple_strtol(buf, NULL, 10); \ + \ + down(&data->update_lock); \ + \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ + w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + data->temp_##reg##_add[nr-2]); \ + } else { /* TEMP1 */ \ + data->temp_##reg = TEMP_TO_REG(val); \ + w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + data->temp_##reg); \ + } \ + \ + up(&data->update_lock); \ + return count; \ +} +store_temp_reg(OVER, max); +store_temp_reg(HYST, max_hyst); + +#define sysfs_temp_offset(offset) \ +static ssize_t \ +show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp(dev, buf, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); + +#define sysfs_temp_reg_offset(reg, offset) \ +static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_temp_##reg (dev, buf, offset); \ +} \ +static ssize_t store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_temp_##reg (dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); + +#define sysfs_temp_offsets(offset) \ +sysfs_temp_offset(offset); \ +sysfs_temp_reg_offset(max, offset); \ +sysfs_temp_reg_offset(max_hyst, offset); + +sysfs_temp_offsets(1); +sysfs_temp_offsets(2); +sysfs_temp_offsets(3); + +#define device_create_file_temp(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ +device_create_file(&client->dev, &dev_attr_temp##offset##_max); \ +device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ +} while (0) + +static ssize_t +show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); +} + +static +DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +#define device_create_file_vid(client) \ +device_create_file(&client->dev, &dev_attr_cpu0_vid); +static ssize_t +show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->vrm); +} + +static ssize_t +store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + + return count; +} + +static +DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +#define device_create_file_vrm(client) \ +device_create_file(&client->dev, &dev_attr_vrm); +static ssize_t +show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); +} + +static +DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +#define device_create_file_alarms(client) \ +device_create_file(&client->dev, &dev_attr_alarms); +static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", + (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type)); +} +static ssize_t show_beep_enable (struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", + (long)BEEP_ENABLE_FROM_REG(data->beep_enable)); +} + +#define BEEP_ENABLE 0 /* Store beep_enable */ +#define BEEP_MASK 1 /* Store beep_mask */ + +static ssize_t +store_beep_reg(struct device *dev, const char *buf, size_t count, + int update_mask) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val, val2; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ + data->beep_mask = BEEP_MASK_TO_REG(val, data->type); + w83781d_write_value(client, W83781D_REG_BEEP_INTS1, + data->beep_mask & 0xff); + + if ((data->type != w83781d) && (data->type != as99127f)) { + w83781d_write_value(client, W83781D_REG_BEEP_INTS3, + ((data->beep_mask) >> 16) & 0xff); + } + + val2 = (data->beep_mask >> 8) & 0x7f; + } else { /* We are storing beep_enable */ + val2 = w83781d_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; + data->beep_enable = BEEP_ENABLE_TO_REG(val); + } + + w83781d_write_value(client, W83781D_REG_BEEP_INTS2, + val2 | data->beep_enable << 7); + + up(&data->update_lock); + return count; +} + +#define sysfs_beep(REG, reg) \ +static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_beep_##reg(dev, attr, buf); \ +} \ +static ssize_t store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_beep_reg(dev, buf, count, BEEP_##REG); \ +} \ +static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg); + +sysfs_beep(ENABLE, enable); +sysfs_beep(MASK, mask); + +#define device_create_file_beep(client) \ +do { \ +device_create_file(&client->dev, &dev_attr_beep_enable); \ +device_create_file(&client->dev, &dev_attr_beep_mask); \ +} while (0) + +static ssize_t +show_fan_div_reg(struct device *dev, char *buf, int nr) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", + (long) DIV_FROM_REG(data->fan_div[nr - 1])); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t +store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + unsigned long min; + u8 reg; + unsigned long val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + /* Save fan_min */ + min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + + data->fan_div[nr] = DIV_TO_REG(val, data->type); + + reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) + & (nr==0 ? 0xcf : 0x3f)) + | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); + w83781d_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); + + /* w83781d and as99127f don't have extended divisor bits */ + if (data->type != w83781d && data->type != as99127f) { + reg = (w83781d_read_value(client, W83781D_REG_VBAT) + & ~(1 << (5 + nr))) + | ((data->fan_div[nr] & 0x04) << (3 + nr)); + w83781d_write_value(client, W83781D_REG_VBAT, reg); + } + + /* Restore fan_min */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); + + up(&data->update_lock); + return count; +} + +#define sysfs_fan_div(offset) \ +static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_fan_div_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_fan_div_reg(dev, buf, count, offset - 1); \ +} \ +static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset); + +sysfs_fan_div(1); +sysfs_fan_div(2); +sysfs_fan_div(3); + +#define device_create_file_fan_div(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ +} while (0) + +static ssize_t +show_pwm_reg(struct device *dev, char *buf, int nr) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr - 1])); +} + +static ssize_t +show_pwmenable_reg(struct device *dev, char *buf, int nr) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->pwmenable[nr - 1]); +} + +static ssize_t +store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + data->pwm[nr - 1] = PWM_TO_REG(val); + w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]); + up(&data->update_lock); + return count; +} + +static ssize_t +store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val, reg; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + switch (val) { + case 0: + case 1: + reg = w83781d_read_value(client, W83781D_REG_PWMCLK12); + w83781d_write_value(client, W83781D_REG_PWMCLK12, + (reg & 0xf7) | (val << 3)); + + reg = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); + w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, + (reg & 0xef) | (!val << 4)); + + data->pwmenable[nr - 1] = val; + break; + + default: + up(&data->update_lock); + return -EINVAL; + } + + up(&data->update_lock); + return count; +} + +#define sysfs_pwm(offset) \ +static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwm_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_pwm_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_regs_pwm_##offset, store_regs_pwm_##offset); + +#define sysfs_pwmenable(offset) \ +static ssize_t show_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_pwmenable_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + return store_pwmenable_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ + show_regs_pwmenable_##offset, store_regs_pwmenable_##offset); + +sysfs_pwm(1); +sysfs_pwm(2); +sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */ +sysfs_pwm(3); +sysfs_pwm(4); + +#define device_create_file_pwm(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_pwm##offset); \ +} while (0) + +#define device_create_file_pwmenable(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_pwm##offset##_enable); \ +} while (0) + +static ssize_t +show_sensor_reg(struct device *dev, char *buf, int nr) +{ + struct w83781d_data *data = w83781d_update_device(dev); + return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); +} + +static ssize_t +store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val, tmp; + + val = simple_strtoul(buf, NULL, 10); + + down(&data->update_lock); + + switch (val) { + case 1: /* PII/Celeron diode */ + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + w83781d_write_value(client, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr - 1]); + tmp = w83781d_read_value(client, W83781D_REG_SCFG2); + w83781d_write_value(client, W83781D_REG_SCFG2, + tmp | BIT_SCFG2[nr - 1]); + data->sens[nr - 1] = val; + break; + case 2: /* 3904 */ + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + w83781d_write_value(client, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr - 1]); + tmp = w83781d_read_value(client, W83781D_REG_SCFG2); + w83781d_write_value(client, W83781D_REG_SCFG2, + tmp & ~BIT_SCFG2[nr - 1]); + data->sens[nr - 1] = val; + break; + case W83781D_DEFAULT_BETA: /* thermistor */ + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + w83781d_write_value(client, W83781D_REG_SCFG1, + tmp & ~BIT_SCFG1[nr - 1]); + data->sens[nr - 1] = val; + break; + default: + dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n", + (long) val, W83781D_DEFAULT_BETA); + break; + } + + up(&data->update_lock); + return count; +} + +#define sysfs_sensor(offset) \ +static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return show_sensor_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + return store_sensor_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset); + +sysfs_sensor(1); +sysfs_sensor(2); +sysfs_sensor(3); + +#define device_create_file_sensor(client, offset) \ +do { \ +device_create_file(&client->dev, &dev_attr_temp##offset##_type); \ +} while (0) + +/* This function is called when: + * w83781d_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and w83781d_driver is still present) */ +static int +w83781d_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, w83781d_detect); +} + +/* Assumes that adapter is of I2C, not ISA variety. + * OTHERWISE DON'T CALL THIS + */ +static int +w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, + struct i2c_client *new_client) +{ + int i, val1 = 0, id; + int err; + const char *client_name = ""; + struct w83781d_data *data = i2c_get_clientdata(new_client); + + data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[0])) { + err = -ENOMEM; + goto ERROR_SC_0; + } + memset(data->lm75[0], 0x00, sizeof (struct i2c_client)); + + id = i2c_adapter_id(adapter); + + if (force_subclients[0] == id && force_subclients[1] == address) { + for (i = 2; i <= 3; i++) { + if (force_subclients[i] < 0x48 || + force_subclients[i] > 0x4f) { + dev_err(&new_client->dev, "Invalid subclient " + "address %d; must be 0x48-0x4f\n", + force_subclients[i]); + err = -EINVAL; + goto ERROR_SC_1; + } + } + w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR, + (force_subclients[2] & 0x07) | + ((force_subclients[3] & 0x07) << 4)); + data->lm75[0]->addr = force_subclients[2]; + } else { + val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR); + data->lm75[0]->addr = 0x48 + (val1 & 0x07); + } + + if (kind != w83783s) { + + data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[1])) { + err = -ENOMEM; + goto ERROR_SC_1; + } + memset(data->lm75[1], 0x0, sizeof(struct i2c_client)); + + if (force_subclients[0] == id && + force_subclients[1] == address) { + data->lm75[1]->addr = force_subclients[3]; + } else { + data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07); + } + if (data->lm75[0]->addr == data->lm75[1]->addr) { + dev_err(&new_client->dev, + "Duplicate addresses 0x%x for subclients.\n", + data->lm75[0]->addr); + err = -EBUSY; + goto ERROR_SC_2; + } + } + + if (kind == w83781d) + client_name = "w83781d subclient"; + else if (kind == w83782d) + client_name = "w83782d subclient"; + else if (kind == w83783s) + client_name = "w83783s subclient"; + else if (kind == w83627hf) + client_name = "w83627hf subclient"; + else if (kind == as99127f) + client_name = "as99127f subclient"; + + for (i = 0; i <= 1; i++) { + /* store all data in w83781d */ + i2c_set_clientdata(data->lm75[i], NULL); + data->lm75[i]->adapter = adapter; + data->lm75[i]->driver = &w83781d_driver; + data->lm75[i]->flags = 0; + strlcpy(data->lm75[i]->name, client_name, + I2C_NAME_SIZE); + if ((err = i2c_attach_client(data->lm75[i]))) { + dev_err(&new_client->dev, "Subclient %d " + "registration at address 0x%x " + "failed.\n", i, data->lm75[i]->addr); + if (i == 1) + goto ERROR_SC_3; + goto ERROR_SC_2; + } + if (kind == w83783s) + break; + } + + return 0; + +/* Undo inits in case of errors */ +ERROR_SC_3: + i2c_detach_client(data->lm75[0]); +ERROR_SC_2: + if (NULL != data->lm75[1]) + kfree(data->lm75[1]); +ERROR_SC_1: + if (NULL != data->lm75[0]) + kfree(data->lm75[0]); +ERROR_SC_0: + return err; +} + +static int +w83781d_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i = 0, val1 = 0, val2; + struct i2c_client *new_client; + struct w83781d_data *data; + int err; + const char *client_name = ""; + int is_isa = i2c_is_isa_adapter(adapter); + enum vendor { winbond, asus } vendid; + + if (!is_isa + && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + err = -EINVAL; + goto ERROR0; + } + + /* Prevent users from forcing a kind for a bus it isn't supposed + to possibly be on */ + if (is_isa && (kind == as99127f || kind == w83783s)) { + dev_err(&adapter->dev, + "Cannot force I2C-only chip for ISA address 0x%02x.\n", + address); + err = -EINVAL; + goto ERROR0; + } + + if (is_isa) + if (!request_region(address, W83781D_EXTENT, + w83781d_driver.name)) { + dev_dbg(&adapter->dev, "Request of region " + "0x%x-0x%x for w83781d failed\n", address, + address + W83781D_EXTENT - 1); + err = -EBUSY; + goto ERROR0; + } + + /* Probe whether there is anything available on this address. Already + done for SMBus clients */ + if (kind < 0) { + if (is_isa) { + +#define REALLY_SLOW_IO + /* We need the timeouts for at least some LM78-like + chips. But only if we read 'undefined' registers. */ + i = inb_p(address + 1); + if (inb_p(address + 2) != i + || inb_p(address + 3) != i + || inb_p(address + 7) != i) { + dev_dbg(&adapter->dev, "Detection of w83781d " + "chip failed at step 1\n"); + err = -ENODEV; + goto ERROR1; + } +#undef REALLY_SLOW_IO + + /* Let's just hope nothing breaks here */ + i = inb_p(address + 5) & 0x7f; + outb_p(~i & 0x7f, address + 5); + val2 = inb_p(address + 5) & 0x7f; + if (val2 != (~i & 0x7f)) { + outb_p(i, address + 5); + dev_dbg(&adapter->dev, "Detection of w83781d " + "chip failed at step 2 (0x%x != " + "0x%x at 0x%x)\n", val2, ~i & 0x7f, + address + 5); + err = -ENODEV; + goto ERROR1; + } + } + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access w83781d_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR1; + } + memset(data, 0, sizeof(struct w83781d_data)); + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &w83781d_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + /* The w8378?d may be stuck in some other bank than bank 0. This may + make reading other information impossible. Specify a force=... or + force_*=... parameter, and the Winbond will be reset to the right + bank. */ + if (kind < 0) { + if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) { + dev_dbg(&new_client->dev, "Detection failed at step " + "3\n"); + err = -ENODEV; + goto ERROR2; + } + val1 = w83781d_read_value(new_client, W83781D_REG_BANK); + val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); + /* Check for Winbond or Asus ID if in bank 0 */ + if ((!(val1 & 0x07)) && + (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)) + || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) { + dev_dbg(&new_client->dev, "Detection failed at step " + "4\n"); + err = -ENODEV; + goto ERROR2; + } + /* If Winbond SMBus, check address at 0x48. + Asus doesn't support, except for as99127f rev.2 */ + if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || + ((val1 & 0x80) && (val2 == 0x5c)))) { + if (w83781d_read_value + (new_client, W83781D_REG_I2C_ADDR) != address) { + dev_dbg(&new_client->dev, "Detection failed " + "at step 5\n"); + err = -ENODEV; + goto ERROR2; + } + } + } + + /* We have either had a force parameter, or we have already detected the + Winbond. Put it now into bank 0 and Vendor ID High Byte */ + w83781d_write_value(new_client, W83781D_REG_BANK, + (w83781d_read_value(new_client, + W83781D_REG_BANK) & 0x78) | + 0x80); + + /* Determine the chip type. */ + if (kind <= 0) { + /* get vendor ID */ + val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); + if (val2 == 0x5c) + vendid = winbond; + else if (val2 == 0x12) + vendid = asus; + else { + dev_dbg(&new_client->dev, "Chip was made by neither " + "Winbond nor Asus?\n"); + err = -ENODEV; + goto ERROR2; + } + + val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID); + if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond) + kind = w83781d; + else if (val1 == 0x30 && vendid == winbond) + kind = w83782d; + else if (val1 == 0x40 && vendid == winbond && !is_isa + && address == 0x2d) + kind = w83783s; + else if (val1 == 0x21 && vendid == winbond) + kind = w83627hf; + else if (val1 == 0x31 && !is_isa && address >= 0x28) + kind = as99127f; + else { + if (kind == 0) + dev_warn(&new_client->dev, "Ignoring 'force' " + "parameter for unknown chip at " + "adapter %d, address 0x%02x\n", + i2c_adapter_id(adapter), address); + err = -EINVAL; + goto ERROR2; + } + } + + if (kind == w83781d) { + client_name = "w83781d"; + } else if (kind == w83782d) { + client_name = "w83782d"; + } else if (kind == w83783s) { + client_name = "w83783s"; + } else if (kind == w83627hf) { + client_name = "w83627hf"; + } else if (kind == as99127f) { + client_name = "as99127f"; + } + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + data->type = kind; + + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR2; + + /* attach secondary i2c lm75-like clients */ + if (!is_isa) { + if ((err = w83781d_detect_subclients(adapter, address, + kind, new_client))) + goto ERROR3; + } else { + data->lm75[0] = NULL; + data->lm75[1] = NULL; + } + + /* Initialize the chip */ + w83781d_init_client(new_client); + + /* A few vars need to be filled upon startup */ + for (i = 1; i <= 3; i++) { + data->fan_min[i - 1] = w83781d_read_value(new_client, + W83781D_REG_FAN_MIN(i)); + } + if (kind != w83781d && kind != as99127f) + for (i = 0; i < 4; i++) + data->pwmenable[i] = 1; + + /* Register sysfs hooks */ + device_create_file_in(new_client, 0); + if (kind != w83783s) + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + device_create_file_in(new_client, 3); + device_create_file_in(new_client, 4); + device_create_file_in(new_client, 5); + device_create_file_in(new_client, 6); + if (kind != as99127f && kind != w83781d && kind != w83783s) { + device_create_file_in(new_client, 7); + device_create_file_in(new_client, 8); + } + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + device_create_file_fan(new_client, 3); + + device_create_file_temp(new_client, 1); + device_create_file_temp(new_client, 2); + if (kind != w83783s) + device_create_file_temp(new_client, 3); + + device_create_file_vid(new_client); + device_create_file_vrm(new_client); + + device_create_file_fan_div(new_client, 1); + device_create_file_fan_div(new_client, 2); + device_create_file_fan_div(new_client, 3); + + device_create_file_alarms(new_client); + + device_create_file_beep(new_client); + + if (kind != w83781d && kind != as99127f) { + device_create_file_pwm(new_client, 1); + device_create_file_pwm(new_client, 2); + device_create_file_pwmenable(new_client, 2); + } + if (kind == w83782d && !is_isa) { + device_create_file_pwm(new_client, 3); + device_create_file_pwm(new_client, 4); + } + + if (kind != as99127f && kind != w83781d) { + device_create_file_sensor(new_client, 1); + device_create_file_sensor(new_client, 2); + if (kind != w83783s) + device_create_file_sensor(new_client, 3); + } + + return 0; + +ERROR3: + i2c_detach_client(new_client); +ERROR2: + kfree(data); +ERROR1: + if (is_isa) + release_region(address, W83781D_EXTENT); +ERROR0: + return err; +} + +static int +w83781d_detach_client(struct i2c_client *client) +{ + int err; + + if (i2c_is_isa_client(client)) + release_region(client->addr, W83781D_EXTENT); + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + if (i2c_get_clientdata(client)==NULL) { + /* subclients */ + kfree(client); + } else { + /* main client */ + kfree(i2c_get_clientdata(client)); + } + + return 0; +} + +/* The SMBus locks itself, usually, but nothing may access the Winbond between + bank switches. ISA access must always be locked explicitly! + We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, + would slow down the W83781D access and should not be necessary. + There are some ugly typecasts here, but the good news is - they should + nowhere else be necessary! */ +static int +w83781d_read_value(struct i2c_client *client, u16 reg) +{ + struct w83781d_data *data = i2c_get_clientdata(client); + int res, word_sized, bank; + struct i2c_client *cl; + + down(&data->lock); + if (i2c_is_isa_client(client)) { + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x50) + || ((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + } + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); + res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); + if (word_sized) { + outb_p((reg & 0xff) + 1, + client->addr + W83781D_ADDR_REG_OFFSET); + res = + (res << 8) + inb_p(client->addr + + W83781D_DATA_REG_OFFSET); + } + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } + } else { + bank = (reg >> 8) & 0x0f; + if (bank > 2) + /* switch banks */ + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, + bank); + if (bank == 0 || bank > 2) { + res = i2c_smbus_read_byte_data(client, reg & 0xff); + } else { + /* switch to subclient */ + cl = data->lm75[bank - 1]; + /* convert from ISA to LM75 I2C addresses */ + switch (reg & 0xff) { + case 0x50: /* TEMP */ + res = swab16(i2c_smbus_read_word_data(cl, 0)); + break; + case 0x52: /* CONFIG */ + res = i2c_smbus_read_byte_data(cl, 1); + break; + case 0x53: /* HYST */ + res = swab16(i2c_smbus_read_word_data(cl, 2)); + break; + case 0x55: /* OVER */ + default: + res = swab16(i2c_smbus_read_word_data(cl, 3)); + break; + } + } + if (bank > 2) + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); + } + up(&data->lock); + return res; +} + +static int +w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) +{ + struct w83781d_data *data = i2c_get_clientdata(client); + int word_sized, bank; + struct i2c_client *cl; + + down(&data->lock); + if (i2c_is_isa_client(client)) { + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + } + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); + if (word_sized) { + outb_p(value >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + outb_p((reg & 0xff) + 1, + client->addr + W83781D_ADDR_REG_OFFSET); + } + outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } + } else { + bank = (reg >> 8) & 0x0f; + if (bank > 2) + /* switch banks */ + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, + bank); + if (bank == 0 || bank > 2) { + i2c_smbus_write_byte_data(client, reg & 0xff, + value & 0xff); + } else { + /* switch to subclient */ + cl = data->lm75[bank - 1]; + /* convert from ISA to LM75 I2C addresses */ + switch (reg & 0xff) { + case 0x52: /* CONFIG */ + i2c_smbus_write_byte_data(cl, 1, value & 0xff); + break; + case 0x53: /* HYST */ + i2c_smbus_write_word_data(cl, 2, swab16(value)); + break; + case 0x55: /* OVER */ + i2c_smbus_write_word_data(cl, 3, swab16(value)); + break; + } + } + if (bank > 2) + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); + } + up(&data->lock); + return 0; +} + +/* Called when we have found a new W83781D. It should set limits, etc. */ +static void +w83781d_init_client(struct i2c_client *client) +{ + struct w83781d_data *data = i2c_get_clientdata(client); + int i, p; + int type = data->type; + u8 tmp; + + if (init && type != as99127f) { /* this resets registers we don't have + documentation for on the as99127f */ + /* save these registers */ + i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); + p = w83781d_read_value(client, W83781D_REG_PWMCLK12); + /* Reset all except Watchdog values and last conversion values + This sets fan-divs to 2, among others */ + w83781d_write_value(client, W83781D_REG_CONFIG, 0x80); + /* Restore the registers and disable power-on abnormal beep. + This saves FAN 1/2/3 input/output values set by BIOS. */ + w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); + w83781d_write_value(client, W83781D_REG_PWMCLK12, p); + /* Disable master beep-enable (reset turns it on). + Individual beep_mask should be reset to off but for some reason + disabling this bit helps some people not get beeped */ + w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); + } + + data->vrm = i2c_which_vrm(); + + if ((type != w83781d) && (type != as99127f)) { + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + for (i = 1; i <= 3; i++) { + if (!(tmp & BIT_SCFG1[i - 1])) { + data->sens[i - 1] = W83781D_DEFAULT_BETA; + } else { + if (w83781d_read_value + (client, + W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) + data->sens[i - 1] = 1; + else + data->sens[i - 1] = 2; + } + if (type == w83783s && i == 2) + break; + } + } + + if (init && type != as99127f) { + /* Enable temp2 */ + tmp = w83781d_read_value(client, W83781D_REG_TEMP2_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp2, readings " + "might not make sense\n"); + w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG, + tmp & 0xfe); + } + + /* Enable temp3 */ + if (type != w83783s) { + tmp = w83781d_read_value(client, + W83781D_REG_TEMP3_CONFIG); + if (tmp & 0x01) { + dev_warn(&client->dev, "Enabling temp3, " + "readings might not make sense\n"); + w83781d_write_value(client, + W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); + } + } + + if (type != w83781d) { + /* enable comparator mode for temp2 and temp3 so + alarm indication will work correctly */ + i = w83781d_read_value(client, W83781D_REG_IRQ); + if (!(i & 0x40)) + w83781d_write_value(client, W83781D_REG_IRQ, + i | 0x40); + } + } + + /* Start monitoring */ + w83781d_write_value(client, W83781D_REG_CONFIG, + (w83781d_read_value(client, + W83781D_REG_CONFIG) & 0xf7) + | 0x01); +} + +static struct w83781d_data *w83781d_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(dev, "Starting device update\n"); + + for (i = 0; i <= 8; i++) { + if (data->type == w83783s && i == 1) + continue; /* 783S has no in1 */ + data->in[i] = + w83781d_read_value(client, W83781D_REG_IN(i)); + data->in_min[i] = + w83781d_read_value(client, W83781D_REG_IN_MIN(i)); + data->in_max[i] = + w83781d_read_value(client, W83781D_REG_IN_MAX(i)); + if ((data->type != w83782d) + && (data->type != w83627hf) && (i == 6)) + break; + } + for (i = 1; i <= 3; i++) { + data->fan[i - 1] = + w83781d_read_value(client, W83781D_REG_FAN(i)); + data->fan_min[i - 1] = + w83781d_read_value(client, W83781D_REG_FAN_MIN(i)); + } + if (data->type != w83781d && data->type != as99127f) { + for (i = 1; i <= 4; i++) { + data->pwm[i - 1] = + w83781d_read_value(client, + W83781D_REG_PWM(i)); + if ((data->type != w83782d + || i2c_is_isa_client(client)) + && i == 2) + break; + } + /* Only PWM2 can be disabled */ + data->pwmenable[1] = (w83781d_read_value(client, + W83781D_REG_PWMCLK12) & 0x08) >> 3; + } + + data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1)); + data->temp_max = + w83781d_read_value(client, W83781D_REG_TEMP_OVER(1)); + data->temp_max_hyst = + w83781d_read_value(client, W83781D_REG_TEMP_HYST(1)); + data->temp_add[0] = + w83781d_read_value(client, W83781D_REG_TEMP(2)); + data->temp_max_add[0] = + w83781d_read_value(client, W83781D_REG_TEMP_OVER(2)); + data->temp_max_hyst_add[0] = + w83781d_read_value(client, W83781D_REG_TEMP_HYST(2)); + if (data->type != w83783s) { + data->temp_add[1] = + w83781d_read_value(client, W83781D_REG_TEMP(3)); + data->temp_max_add[1] = + w83781d_read_value(client, + W83781D_REG_TEMP_OVER(3)); + data->temp_max_hyst_add[1] = + w83781d_read_value(client, + W83781D_REG_TEMP_HYST(3)); + } + i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); + data->vid = i & 0x0f; + data->vid |= (w83781d_read_value(client, + W83781D_REG_CHIPID) & 0x01) << 4; + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + data->fan_div[2] = (w83781d_read_value(client, + W83781D_REG_PIN) >> 6) & 0x03; + if ((data->type != w83781d) && (data->type != as99127f)) { + i = w83781d_read_value(client, W83781D_REG_VBAT); + data->fan_div[0] |= (i >> 3) & 0x04; + data->fan_div[1] |= (i >> 4) & 0x04; + data->fan_div[2] |= (i >> 5) & 0x04; + } + data->alarms = + w83781d_read_value(client, + W83781D_REG_ALARM1) + + (w83781d_read_value(client, W83781D_REG_ALARM2) << 8); + if ((data->type == w83782d) || (data->type == w83627hf)) { + data->alarms |= + w83781d_read_value(client, + W83781D_REG_ALARM3) << 16; + } + i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2); + data->beep_enable = i >> 7; + data->beep_mask = ((i & 0x7f) << 8) + + w83781d_read_value(client, W83781D_REG_BEEP_INTS1); + if ((data->type != w83781d) && (data->type != as99127f)) { + data->beep_mask |= + w83781d_read_value(client, + W83781D_REG_BEEP_INTS3) << 16; + } + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init +sensors_w83781d_init(void) +{ + return i2c_add_driver(&w83781d_driver); +} + +static void __exit +sensors_w83781d_exit(void) +{ + i2c_del_driver(&w83781d_driver); +} + +MODULE_AUTHOR("Frodo Looijaard , " + "Philip Edelbrock , " + "and Mark Studebaker "); +MODULE_DESCRIPTION("W83781D driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83781d_init); +module_exit(sensors_w83781d_exit); diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c new file mode 100644 index 00000000000..4469d52aba4 --- /dev/null +++ b/drivers/hwmon/w83l785ts.c @@ -0,0 +1,328 @@ +/* + * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2003-2004 Jean Delvare + * + * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made + * by Winbond. It reports a single external temperature with a 1 deg + * resolution and a 3 deg accuracy. Datasheet can be obtained from + * Winbond's website at: + * http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf + * + * Ported to Linux 2.6 by Wolfgang Ziegler and Jean Delvare + * . + * + * Thanks to James Bolt for benchmarking the read + * error handling mechanism. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* How many retries on register read error */ +#define MAX_RETRIES 5 + +/* + * Address to scan + * Address is fully defined internally and cannot be changed. + */ + +static unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; + +/* + * Insmod parameters + */ + +SENSORS_INSMOD_1(w83l785ts); + +/* + * The W83L785TS-S registers + * Manufacturer ID is 0x5CA3 for Winbond. + */ + +#define W83L785TS_REG_MAN_ID1 0x4D +#define W83L785TS_REG_MAN_ID2 0x4C +#define W83L785TS_REG_CHIP_ID 0x4E +#define W83L785TS_REG_CONFIG 0x40 +#define W83L785TS_REG_TYPE 0x52 +#define W83L785TS_REG_TEMP 0x27 +#define W83L785TS_REG_TEMP_OVER 0x53 /* not sure about this one */ + +/* + * Conversions + * The W83L785TS-S uses signed 8-bit values. + */ + +#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000) + +/* + * Functions declaration + */ + +static int w83l785ts_attach_adapter(struct i2c_adapter *adapter); +static int w83l785ts_detect(struct i2c_adapter *adapter, int address, + int kind); +static int w83l785ts_detach_client(struct i2c_client *client); +static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval); +static struct w83l785ts_data *w83l785ts_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver w83l785ts_driver = { + .owner = THIS_MODULE, + .name = "w83l785ts", + .id = I2C_DRIVERID_W83L785TS, + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83l785ts_attach_adapter, + .detach_client = w83l785ts_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct w83l785ts_data { + struct i2c_client client; + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + u8 temp, temp_over; +}; + +/* + * Sysfs stuff + */ + +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83l785ts_data *data = w83l785ts_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); +} + +static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83l785ts_data *data = w83l785ts_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); +} + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_over, NULL); + +/* + * Real code + */ + +static int w83l785ts_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_detect(adapter, &addr_data, w83l785ts_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct w83l785ts_data *data; + int err = 0; + + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kmalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + memset(data, 0, sizeof(struct w83l785ts_data)); + + + /* The common I2C client data is placed right before the + * W83L785TS-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &w83l785ts_driver; + new_client->flags = 0; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip (actually there is only + * one possible kind of chip for now, W83L785TS-S). A zero kind means + * that the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + if (kind < 0) { /* detection */ + if (((w83l785ts_read_value(new_client, + W83L785TS_REG_CONFIG, 0) & 0x80) != 0x00) + || ((w83l785ts_read_value(new_client, + W83L785TS_REG_TYPE, 0) & 0xFC) != 0x00)) { + dev_dbg(&adapter->dev, + "W83L785TS-S detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + u16 man_id; + u8 chip_id; + + man_id = (w83l785ts_read_value(new_client, + W83L785TS_REG_MAN_ID1, 0) << 8) + + w83l785ts_read_value(new_client, + W83L785TS_REG_MAN_ID2, 0); + chip_id = w83l785ts_read_value(new_client, + W83L785TS_REG_CHIP_ID, 0); + + if (man_id == 0x5CA3) { /* Winbond */ + if (chip_id == 0x70) { /* W83L785TS-S */ + kind = w83l785ts; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%04X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + } + + /* We can fill in the remaining client fields. */ + strlcpy(new_client->name, "w83l785ts", I2C_NAME_SIZE); + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Default values in case the first read fails (unlikely). */ + data->temp_over = data->temp = 0; + + /* Tell the I2C layer a new client has arrived. */ + if ((err = i2c_attach_client(new_client))) + goto exit_free; + + /* + * Initialize the W83L785TS chip + * Nothing yet, assume it is already started. + */ + + /* Register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_temp1_input); + device_create_file(&new_client->dev, &dev_attr_temp1_max); + + return 0; + +exit_free: + kfree(data); +exit: + return err; +} + +static int w83l785ts_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval) +{ + int value, i; + + /* Frequent read errors have been reported on Asus boards, so we + * retry on read errors. If it still fails (unlikely), return the + * default value requested by the caller. */ + for (i = 1; i <= MAX_RETRIES; i++) { + value = i2c_smbus_read_byte_data(client, reg); + if (value >= 0) { + dev_dbg(&client->dev, "Read 0x%02x from register " + "0x%02x.\n", value, reg); + return value; + } + dev_dbg(&client->dev, "Read failed, will retry in %d.\n", i); + msleep(i); + } + + dev_err(&client->dev, "Couldn't read value from register 0x%02x. " + "Please report.\n", reg); + return defval; +} + +static struct w83l785ts_data *w83l785ts_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83l785ts_data *data = i2c_get_clientdata(client); + + down(&data->update_lock); + + if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) { + dev_dbg(&client->dev, "Updating w83l785ts data.\n"); + data->temp = w83l785ts_read_value(client, + W83L785TS_REG_TEMP, data->temp); + data->temp_over = w83l785ts_read_value(client, + W83L785TS_REG_TEMP_OVER, data->temp_over); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); + + return data; +} + +static int __init sensors_w83l785ts_init(void) +{ + return i2c_add_driver(&w83l785ts_driver); +} + +static void __exit sensors_w83l785ts_exit(void) +{ + i2c_del_driver(&w83l785ts_driver); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("W83L785TS-S driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83l785ts_init); +module_exit(sensors_w83l785ts_exit); diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c deleted file mode 100644 index d2c774c32f4..00000000000 --- a/drivers/i2c/chips/adm1021.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - adm1021.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard and - Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include - - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, - 0x29, 0x2a, 0x2b, - 0x4c, 0x4d, 0x4e, - I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066); - -/* adm1021 constants specified below */ - -/* The adm1021 registers */ -/* Read-only */ -#define ADM1021_REG_TEMP 0x00 -#define ADM1021_REG_REMOTE_TEMP 0x01 -#define ADM1021_REG_STATUS 0x02 -#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ -#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */ -#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ -/* These use different addresses for reading/writing */ -#define ADM1021_REG_CONFIG_R 0x03 -#define ADM1021_REG_CONFIG_W 0x09 -#define ADM1021_REG_CONV_RATE_R 0x04 -#define ADM1021_REG_CONV_RATE_W 0x0A -/* These are for the ADM1023's additional precision on the remote temp sensor */ -#define ADM1021_REG_REM_TEMP_PREC 0x010 -#define ADM1021_REG_REM_OFFSET 0x011 -#define ADM1021_REG_REM_OFFSET_PREC 0x012 -#define ADM1021_REG_REM_TOS_PREC 0x013 -#define ADM1021_REG_REM_THYST_PREC 0x014 -/* limits */ -#define ADM1021_REG_TOS_R 0x05 -#define ADM1021_REG_TOS_W 0x0B -#define ADM1021_REG_REMOTE_TOS_R 0x07 -#define ADM1021_REG_REMOTE_TOS_W 0x0D -#define ADM1021_REG_THYST_R 0x06 -#define ADM1021_REG_THYST_W 0x0C -#define ADM1021_REG_REMOTE_THYST_R 0x08 -#define ADM1021_REG_REMOTE_THYST_W 0x0E -/* write-only */ -#define ADM1021_REG_ONESHOT 0x0F - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -/* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? (val-256)*1000 : val*1000) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255)) - -/* Initial values */ - -/* Note: Even though I left the low and high limits named os and hyst, -they don't quite work like a thermostat the way the LM75 does. I.e., -a lower temp than THYST actually triggers an alarm instead of -clearing it. Weird, ey? --Phil */ - -/* Each client has this additional data */ -struct adm1021_data { - struct i2c_client client; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 temp_max; /* Register values */ - u8 temp_hyst; - u8 temp_input; - u8 remote_temp_max; - u8 remote_temp_hyst; - u8 remote_temp_input; - u8 alarms; - /* Special values for ADM1023 only */ - u8 remote_temp_prec; - u8 remote_temp_os_prec; - u8 remote_temp_hyst_prec; - u8 remote_temp_offset; - u8 remote_temp_offset_prec; -}; - -static int adm1021_attach_adapter(struct i2c_adapter *adapter); -static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind); -static void adm1021_init_client(struct i2c_client *client); -static int adm1021_detach_client(struct i2c_client *client); -static int adm1021_read_value(struct i2c_client *client, u8 reg); -static int adm1021_write_value(struct i2c_client *client, u8 reg, - u16 value); -static struct adm1021_data *adm1021_update_device(struct device *dev); - -/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ -static int read_only = 0; - - -/* This is the driver that will be inserted */ -static struct i2c_driver adm1021_driver = { - .owner = THIS_MODULE, - .name = "adm1021", - .id = I2C_DRIVERID_ADM1021, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1021_attach_adapter, - .detach_client = adm1021_detach_client, -}; - -#define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1021_data *data = adm1021_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ -} -show(temp_max); -show(temp_hyst); -show(temp_input); -show(remote_temp_max); -show(remote_temp_hyst); -show(remote_temp_input); - -#define show2(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1021_data *data = adm1021_update_device(dev); \ - return sprintf(buf, "%d\n", data->value); \ -} -show2(alarms); - -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1021_data *data = i2c_get_clientdata(client); \ - int temp = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(temp); \ - adm1021_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} -set(temp_max, ADM1021_REG_TOS_W); -set(temp_hyst, ADM1021_REG_THYST_W); -set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W); -set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W); - -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - - -static int adm1021_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, adm1021_detect); -} - -static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i; - struct i2c_client *new_client; - struct adm1021_data *data; - int err = 0; - const char *type_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - dev_dbg(&adapter->dev, "adm1021_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto error0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1021_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error0; - } - memset(data, 0, sizeof(struct adm1021_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1021_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - if (kind < 0) { - if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) { - err = -ENODEV; - goto error1; - } - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID); - if (i == 0x41) - if ((adm1021_read_value(new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030) - kind = adm1023; - else - kind = adm1021; - else if (i == 0x49) - kind = thmc10; - else if (i == 0x23) - kind = gl523sm; - else if ((i == 0x4d) && - (adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01)) - kind = max1617a; - else if (i == 0x54) - kind = mc1066; - /* LM84 Mfr ID in a different place, and it has more unused bits */ - else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00 - && (kind == 0 /* skip extra detection */ - || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00 - && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00))) - kind = lm84; - else - kind = max1617; - } - - if (kind == max1617) { - type_name = "max1617"; - } else if (kind == max1617a) { - type_name = "max1617a"; - } else if (kind == adm1021) { - type_name = "adm1021"; - } else if (kind == adm1023) { - type_name = "adm1023"; - } else if (kind == thmc10) { - type_name = "thmc10"; - } else if (kind == lm84) { - type_name = "lm84"; - } else if (kind == gl523sm) { - type_name = "gl523sm"; - } else if (kind == mc1066) { - type_name = "mc1066"; - } - - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, type_name, I2C_NAME_SIZE); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto error1; - - /* Initialize the ADM1021 chip */ - if (kind != lm84) - adm1021_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -error1: - kfree(data); -error0: - return err; -} - -static void adm1021_init_client(struct i2c_client *client) -{ - /* Enable ADC and disable suspend mode */ - adm1021_write_value(client, ADM1021_REG_CONFIG_W, - adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF); - /* Set Conversion rate to 1/sec (this can be tinkered with) */ - adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); -} - -static int adm1021_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - -/* All registers are byte-sized */ -static int adm1021_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (!read_only) - return i2c_smbus_write_byte_data(client, reg, value); - return 0; -} - -static struct adm1021_data *adm1021_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1021_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting adm1021 update\n"); - - data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP); - data->temp_max = adm1021_read_value(client, ADM1021_REG_TOS_R); - data->temp_hyst = adm1021_read_value(client, ADM1021_REG_THYST_R); - data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP); - data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); - data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); - data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c; - if (data->type == adm1023) { - data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); - data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); - data->remote_temp_hyst_prec = adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC); - data->remote_temp_offset = adm1021_read_value(client, ADM1021_REG_REM_OFFSET); - data->remote_temp_offset_prec = adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC); - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_adm1021_init(void) -{ - return i2c_add_driver(&adm1021_driver); -} - -static void __exit sensors_adm1021_exit(void) -{ - i2c_del_driver(&adm1021_driver); -} - -MODULE_AUTHOR ("Frodo Looijaard and " - "Philip Edelbrock "); -MODULE_DESCRIPTION("adm1021 driver"); -MODULE_LICENSE("GPL"); - -module_param(read_only, bool, 0); -MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); - -module_init(sensors_adm1021_init) -module_exit(sensors_adm1021_exit) diff --git a/drivers/i2c/chips/adm1025.c b/drivers/i2c/chips/adm1025.c deleted file mode 100644 index e452d0daf90..00000000000 --- a/drivers/i2c/chips/adm1025.c +++ /dev/null @@ -1,577 +0,0 @@ -/* - * adm1025.c - * - * Copyright (C) 2000 Chen-Yuan Wu - * Copyright (C) 2003-2004 Jean Delvare - * - * The ADM1025 is a sensor chip made by Analog Devices. It reports up to 6 - * voltages (including its own power source) and up to two temperatures - * (its own plus up to one external one). Voltages are scaled internally - * (which is not the common way) with ratios such that the nominal value - * of each voltage correspond to a register value of 192 (which means a - * resolution of about 0.5% of the nominal value). Temperature values are - * reported with a 1 deg resolution and a 3 deg accuracy. Complete - * datasheet can be obtained from Analog's website at: - * http://www.analog.com/Analog_Root/productPage/productHome/0,2121,ADM1025,00.html - * - * This driver also supports the ADM1025A, which differs from the ADM1025 - * only in that it has "open-drain VID inputs while the ADM1025 has - * on-chip 100k pull-ups on the VID inputs". It doesn't make any - * difference for us. - * - * This driver also supports the NE1619, a sensor chip made by Philips. - * That chip is similar to the ADM1025A, with a few differences. The only - * difference that matters to us is that the NE1619 has only two possible - * addresses while the ADM1025A has a third one. Complete datasheet can be - * obtained from Philips's website at: - * http://www.semiconductors.philips.com/pip/NE1619DS.html - * - * Since the ADM1025 was the first chipset supported by this driver, most - * comments will refer to this chipset, but are actually general and - * concern all supported chipsets, unless mentioned otherwise. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Addresses to scan - * ADM1025 and ADM1025A have three possible addresses: 0x2c, 0x2d and 0x2e. - * NE1619 has two possible addresses: 0x2c and 0x2d. - */ - -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_2(adm1025, ne1619); - -/* - * The ADM1025 registers - */ - -#define ADM1025_REG_MAN_ID 0x3E -#define ADM1025_REG_CHIP_ID 0x3F -#define ADM1025_REG_CONFIG 0x40 -#define ADM1025_REG_STATUS1 0x41 -#define ADM1025_REG_STATUS2 0x42 -#define ADM1025_REG_IN(nr) (0x20 + (nr)) -#define ADM1025_REG_IN_MAX(nr) (0x2B + (nr) * 2) -#define ADM1025_REG_IN_MIN(nr) (0x2C + (nr) * 2) -#define ADM1025_REG_TEMP(nr) (0x26 + (nr)) -#define ADM1025_REG_TEMP_HIGH(nr) (0x37 + (nr) * 2) -#define ADM1025_REG_TEMP_LOW(nr) (0x38 + (nr) * 2) -#define ADM1025_REG_VID 0x47 -#define ADM1025_REG_VID4 0x49 - -/* - * Conversions and various macros - * The ADM1025 uses signed 8-bit values for temperatures. - */ - -static int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 }; - -#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) -#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ - (val) * 192 >= (scale) * 255 ? 255 : \ - ((val) * 192 + (scale)/2) / (scale)) - -#define TEMP_FROM_REG(reg) ((reg) * 1000) -#define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \ - (val) >= 126500 ? 127 : \ - (((val) < 0 ? (val)-500 : (val)+500) / 1000)) - -/* - * Functions declaration - */ - -static int adm1025_attach_adapter(struct i2c_adapter *adapter); -static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind); -static void adm1025_init_client(struct i2c_client *client); -static int adm1025_detach_client(struct i2c_client *client); -static struct adm1025_data *adm1025_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver adm1025_driver = { - .owner = THIS_MODULE, - .name = "adm1025", - .id = I2C_DRIVERID_ADM1025, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1025_attach_adapter, - .detach_client = adm1025_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct adm1025_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - u8 in[6]; /* register value */ - u8 in_max[6]; /* register value */ - u8 in_min[6]; /* register value */ - s8 temp[2]; /* register value */ - s8 temp_min[2]; /* register value */ - s8 temp_max[2]; /* register value */ - u16 alarms; /* register values, combined */ - u8 vid; /* register values, combined */ - u8 vrm; -}; - -/* - * Sysfs stuff - */ - -#define show_in(offset) \ -static ssize_t show_in##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ - in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ - in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ - in_scale[offset])); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); -show_in(0); -show_in(1); -show_in(2); -show_in(3); -show_in(4); -show_in(5); - -#define show_temp(offset) \ -static ssize_t show_temp##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ -} \ -static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ -} \ -static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ -}\ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp##offset, NULL); -show_temp(1); -show_temp(2); - -#define set_in(offset) \ -static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_min[offset] = IN_TO_REG(val, in_scale[offset]); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \ - data->in_min[offset]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_max[offset] = IN_TO_REG(val, in_scale[offset]); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \ - data->in_max[offset]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ - show_in##offset##_max, set_in##offset##_max); -set_in(0); -set_in(1); -set_in(2); -set_in(3); -set_in(4); -set_in(5); - -#define set_temp(offset) \ -static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp_min[offset-1] = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \ - data->temp_min[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp_max[offset-1] = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \ - data->temp_max[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ - show_temp##offset##_min, set_temp##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ - show_temp##offset##_max, set_temp##offset##_max); -set_temp(1); -set_temp(2); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1025_data *data = adm1025_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1025_data *data = adm1025_update_device(dev); - return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); -} -/* in1_ref is deprecated in favour of cpu0_vid, remove after 2005-11-11 */ -static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL); -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1025_data *data = adm1025_update_device(dev); - return sprintf(buf, "%u\n", data->vrm); -} -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1025_data *data = i2c_get_clientdata(client); - data->vrm = simple_strtoul(buf, NULL, 10); - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); - -/* - * Real code - */ - -static int adm1025_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, adm1025_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct adm1025_data *data; - int err = 0; - const char *name = ""; - u8 config; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct adm1025_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct adm1025_data)); - - /* The common I2C client data is placed right before the - ADM1025-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1025_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - config = i2c_smbus_read_byte_data(new_client, ADM1025_REG_CONFIG); - if (kind < 0) { /* detection */ - if ((config & 0x80) != 0x00 - || (i2c_smbus_read_byte_data(new_client, - ADM1025_REG_STATUS1) & 0xC0) != 0x00 - || (i2c_smbus_read_byte_data(new_client, - ADM1025_REG_STATUS2) & 0xBC) != 0x00) { - dev_dbg(&adapter->dev, - "ADM1025 detection failed at 0x%02x.\n", - address); - goto exit_free; - } - } - - if (kind <= 0) { /* identification */ - u8 man_id, chip_id; - - man_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_CHIP_ID); - - if (man_id == 0x41) { /* Analog Devices */ - if ((chip_id & 0xF0) == 0x20) { /* ADM1025/ADM1025A */ - kind = adm1025; - } - } else - if (man_id == 0xA1) { /* Philips */ - if (address != 0x2E - && (chip_id & 0xF0) == 0x20) { /* NE1619 */ - kind = ne1619; - } - } - - if (kind <= 0) { /* identification failed */ - dev_info(&adapter->dev, - "Unsupported chip (man_id=0x%02X, " - "chip_id=0x%02X).\n", man_id, chip_id); - goto exit_free; - } - } - - if (kind == adm1025) { - name = "adm1025"; - } else if (kind == ne1619) { - name = "ne1619"; - } - - /* We can fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the ADM1025 chip */ - adm1025_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_alarms); - /* in1_ref is deprecated, remove after 2005-11-11 */ - device_create_file(&new_client->dev, &dev_attr_in1_ref); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_vrm); - - /* Pin 11 is either in4 (+12V) or VID4 */ - if (!(config & 0x20)) { - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - } - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static void adm1025_init_client(struct i2c_client *client) -{ - u8 reg; - struct adm1025_data *data = i2c_get_clientdata(client); - int i; - - data->vrm = i2c_which_vrm(); - - /* - * Set high limits - * Usually we avoid setting limits on driver init, but it happens - * that the ADM1025 comes with stupid default limits (all registers - * set to 0). In case the chip has not gone through any limit - * setting yet, we better set the high limits to the max so that - * no alarm triggers. - */ - for (i=0; i<6; i++) { - reg = i2c_smbus_read_byte_data(client, - ADM1025_REG_IN_MAX(i)); - if (reg == 0) - i2c_smbus_write_byte_data(client, - ADM1025_REG_IN_MAX(i), - 0xFF); - } - for (i=0; i<2; i++) { - reg = i2c_smbus_read_byte_data(client, - ADM1025_REG_TEMP_HIGH(i)); - if (reg == 0) - i2c_smbus_write_byte_data(client, - ADM1025_REG_TEMP_HIGH(i), - 0x7F); - } - - /* - * Start the conversions - */ - reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); - if (!(reg & 0x01)) - i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG, - (reg&0x7E)|0x01); -} - -static int adm1025_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - -static struct adm1025_data *adm1025_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1025_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - int i; - - dev_dbg(&client->dev, "Updating data.\n"); - for (i=0; i<6; i++) { - data->in[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_IN(i)); - data->in_min[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_IN_MIN(i)); - data->in_max[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_IN_MAX(i)); - } - for (i=0; i<2; i++) { - data->temp[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_TEMP(i)); - data->temp_min[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_TEMP_LOW(i)); - data->temp_max[i] = i2c_smbus_read_byte_data(client, - ADM1025_REG_TEMP_HIGH(i)); - } - data->alarms = i2c_smbus_read_byte_data(client, - ADM1025_REG_STATUS1) - | (i2c_smbus_read_byte_data(client, - ADM1025_REG_STATUS2) << 8); - data->vid = (i2c_smbus_read_byte_data(client, - ADM1025_REG_VID) & 0x0f) - | ((i2c_smbus_read_byte_data(client, - ADM1025_REG_VID4) & 0x01) << 4); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_adm1025_init(void) -{ - return i2c_add_driver(&adm1025_driver); -} - -static void __exit sensors_adm1025_exit(void) -{ - i2c_del_driver(&adm1025_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("ADM1025 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_adm1025_init); -module_exit(sensors_adm1025_exit); diff --git a/drivers/i2c/chips/adm1026.c b/drivers/i2c/chips/adm1026.c deleted file mode 100644 index 3c85fe150cd..00000000000 --- a/drivers/i2c/chips/adm1026.c +++ /dev/null @@ -1,1714 +0,0 @@ -/* - adm1026.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 2002, 2003 Philip Pokorny - Copyright (C) 2004 Justin Thiessen - - Chip details at: - - - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(adm1026); - -static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; -module_param_array(gpio_input,int,NULL,0); -MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs"); -module_param_array(gpio_output,int,NULL,0); -MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as " - "outputs"); -module_param_array(gpio_inverted,int,NULL,0); -MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as " - "inverted"); -module_param_array(gpio_normal,int,NULL,0); -MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as " - "normal/non-inverted"); -module_param_array(gpio_fan,int,NULL,0); -MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs"); - -/* Many ADM1026 constants specified below */ - -/* The ADM1026 registers */ -#define ADM1026_REG_CONFIG1 0x00 -#define CFG1_MONITOR 0x01 -#define CFG1_INT_ENABLE 0x02 -#define CFG1_INT_CLEAR 0x04 -#define CFG1_AIN8_9 0x08 -#define CFG1_THERM_HOT 0x10 -#define CFG1_DAC_AFC 0x20 -#define CFG1_PWM_AFC 0x40 -#define CFG1_RESET 0x80 -#define ADM1026_REG_CONFIG2 0x01 -/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */ -#define ADM1026_REG_CONFIG3 0x07 -#define CFG3_GPIO16_ENABLE 0x01 -#define CFG3_CI_CLEAR 0x02 -#define CFG3_VREF_250 0x04 -#define CFG3_GPIO16_DIR 0x40 -#define CFG3_GPIO16_POL 0x80 -#define ADM1026_REG_E2CONFIG 0x13 -#define E2CFG_READ 0x01 -#define E2CFG_WRITE 0x02 -#define E2CFG_ERASE 0x04 -#define E2CFG_ROM 0x08 -#define E2CFG_CLK_EXT 0x80 - -/* There are 10 general analog inputs and 7 dedicated inputs - * They are: - * 0 - 9 = AIN0 - AIN9 - * 10 = Vbat - * 11 = 3.3V Standby - * 12 = 3.3V Main - * 13 = +5V - * 14 = Vccp (CPU core voltage) - * 15 = +12V - * 16 = -12V - */ -static u16 ADM1026_REG_IN[] = { - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x27, 0x29, 0x26, 0x2a, - 0x2b, 0x2c, 0x2d, 0x2e, 0x2f - }; -static u16 ADM1026_REG_IN_MIN[] = { - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, - 0x5e, 0x5f, 0x6d, 0x49, 0x6b, 0x4a, - 0x4b, 0x4c, 0x4d, 0x4e, 0x4f - }; -static u16 ADM1026_REG_IN_MAX[] = { - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, - 0x56, 0x57, 0x6c, 0x41, 0x6a, 0x42, - 0x43, 0x44, 0x45, 0x46, 0x47 - }; - -/* Temperatures are: - * 0 - Internal - * 1 - External 1 - * 2 - External 2 - */ -static u16 ADM1026_REG_TEMP[] = { 0x1f, 0x28, 0x29 }; -static u16 ADM1026_REG_TEMP_MIN[] = { 0x69, 0x48, 0x49 }; -static u16 ADM1026_REG_TEMP_MAX[] = { 0x68, 0x40, 0x41 }; -static u16 ADM1026_REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 }; -static u16 ADM1026_REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f }; -static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f }; - -#define ADM1026_REG_FAN(nr) (0x38 + (nr)) -#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr)) -#define ADM1026_REG_FAN_DIV_0_3 0x02 -#define ADM1026_REG_FAN_DIV_4_7 0x03 - -#define ADM1026_REG_DAC 0x04 -#define ADM1026_REG_PWM 0x05 - -#define ADM1026_REG_GPIO_CFG_0_3 0x08 -#define ADM1026_REG_GPIO_CFG_4_7 0x09 -#define ADM1026_REG_GPIO_CFG_8_11 0x0a -#define ADM1026_REG_GPIO_CFG_12_15 0x0b -/* CFG_16 in REG_CFG3 */ -#define ADM1026_REG_GPIO_STATUS_0_7 0x24 -#define ADM1026_REG_GPIO_STATUS_8_15 0x25 -/* STATUS_16 in REG_STATUS4 */ -#define ADM1026_REG_GPIO_MASK_0_7 0x1c -#define ADM1026_REG_GPIO_MASK_8_15 0x1d -/* MASK_16 in REG_MASK4 */ - -#define ADM1026_REG_COMPANY 0x16 -#define ADM1026_REG_VERSTEP 0x17 -/* These are the recognized values for the above regs */ -#define ADM1026_COMPANY_ANALOG_DEV 0x41 -#define ADM1026_VERSTEP_GENERIC 0x40 -#define ADM1026_VERSTEP_ADM1026 0x44 - -#define ADM1026_REG_MASK1 0x18 -#define ADM1026_REG_MASK2 0x19 -#define ADM1026_REG_MASK3 0x1a -#define ADM1026_REG_MASK4 0x1b - -#define ADM1026_REG_STATUS1 0x20 -#define ADM1026_REG_STATUS2 0x21 -#define ADM1026_REG_STATUS3 0x22 -#define ADM1026_REG_STATUS4 0x23 - -#define ADM1026_FAN_ACTIVATION_TEMP_HYST -6 -#define ADM1026_FAN_CONTROL_TEMP_RANGE 20 -#define ADM1026_PWM_MAX 255 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - * variants. Note that you should be a bit careful with which arguments - * these macros are called: arguments may be evaluated more than once. - */ - -/* IN are scaled acording to built-in resistors. These are the - * voltages corresponding to 3/4 of full scale (192 or 0xc0) - * NOTE: The -12V input needs an additional factor to account - * for the Vref pullup resistor. - * NEG12_OFFSET = SCALE * Vref / V-192 - Vref - * = 13875 * 2.50 / 1.875 - 2500 - * = 16000 - * - * The values in this table are based on Table II, page 15 of the - * datasheet. - */ -static int adm1026_scaling[] = { /* .001 Volts */ - 2250, 2250, 2250, 2250, 2250, 2250, - 1875, 1875, 1875, 1875, 3000, 3330, - 3330, 4995, 2250, 12000, 13875 - }; -#define NEG12_OFFSET 16000 -#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) -#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),\ - 0,255)) -#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n])) - -/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses - * and we assume a 2 pulse-per-rev fan tach signal - * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000 - */ -#define FAN_TO_REG(val,div) ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*\ - (div)),1,254)) -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*\ - (div))) -#define DIV_FROM_REG(val) (1<<(val)) -#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0) - -/* Temperature is reported in 1 degC increments */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ - -127,127)) -#define TEMP_FROM_REG(val) ((val) * 1000) -#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ - -127,127)) -#define OFFSET_FROM_REG(val) ((val) * 1000) - -#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) -#define PWM_FROM_REG(val) (val) - -#define PWM_MIN_TO_REG(val) ((val) & 0xf0) -#define PWM_MIN_FROM_REG(val) (((val) & 0xf0) + ((val) >> 4)) - -/* Analog output is a voltage, and scaled to millivolts. The datasheet - * indicates that the DAC could be used to drive the fans, but in our - * example board (Arima HDAMA) it isn't connected to the fans at all. - */ -#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val)*255)+500)/2500),0,255)) -#define DAC_FROM_REG(val) (((val)*2500)/255) - -/* Typically used with systems using a v9.1 VRM spec ? */ -#define ADM1026_INIT_VRM 91 - -/* Chip sampling rates - * - * Some sensors are not updated more frequently than once per second - * so it doesn't make sense to read them more often than that. - * We cache the results and return the saved data if the driver - * is called again before a second has elapsed. - * - * Also, there is significant configuration data for this chip - * So, we keep the config data up to date in the cache - * when it is written and only sample it once every 5 *minutes* - */ -#define ADM1026_DATA_INTERVAL (1 * HZ) -#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ) - -/* We allow for multiple chips in a single system. - * - * For each registered ADM1026, we need to keep state information - * at client->data. The adm1026_data structure is dynamically - * allocated, when a new client structure is allocated. */ - -struct pwm_data { - u8 pwm; - u8 enable; - u8 auto_pwm_min; -}; - -struct adm1026_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - int valid; /* !=0 if following fields are valid */ - unsigned long last_reading; /* In jiffies */ - unsigned long last_config; /* In jiffies */ - - u8 in[17]; /* Register value */ - u8 in_max[17]; /* Register value */ - u8 in_min[17]; /* Register value */ - s8 temp[3]; /* Register value */ - s8 temp_min[3]; /* Register value */ - s8 temp_max[3]; /* Register value */ - s8 temp_tmin[3]; /* Register value */ - s8 temp_crit[3]; /* Register value */ - s8 temp_offset[3]; /* Register value */ - u8 fan[8]; /* Register value */ - u8 fan_min[8]; /* Register value */ - u8 fan_div[8]; /* Decoded value */ - struct pwm_data pwm1; /* Pwm control values */ - int vid; /* Decoded value */ - u8 vrm; /* VRM version */ - u8 analog_out; /* Register value (DAC) */ - long alarms; /* Register encoding, combined */ - long alarm_mask; /* Register encoding, combined */ - long gpio; /* Register encoding, combined */ - long gpio_mask; /* Register encoding, combined */ - u8 gpio_config[17]; /* Decoded value */ - u8 config1; /* Register value */ - u8 config2; /* Register value */ - u8 config3; /* Register value */ -}; - -static int adm1026_attach_adapter(struct i2c_adapter *adapter); -static int adm1026_detect(struct i2c_adapter *adapter, int address, - int kind); -static int adm1026_detach_client(struct i2c_client *client); -static int adm1026_read_value(struct i2c_client *client, u8 register); -static int adm1026_write_value(struct i2c_client *client, u8 register, - int value); -static void adm1026_print_gpio(struct i2c_client *client); -static void adm1026_fixup_gpio(struct i2c_client *client); -static struct adm1026_data *adm1026_update_device(struct device *dev); -static void adm1026_init_client(struct i2c_client *client); - - -static struct i2c_driver adm1026_driver = { - .owner = THIS_MODULE, - .name = "adm1026", - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1026_attach_adapter, - .detach_client = adm1026_detach_client, -}; - -int adm1026_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) { - return 0; - } - return i2c_detect(adapter, &addr_data, adm1026_detect); -} - -int adm1026_detach_client(struct i2c_client *client) -{ - i2c_detach_client(client); - kfree(client); - return 0; -} - -int adm1026_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - if (reg < 0x80) { - /* "RAM" locations */ - res = i2c_smbus_read_byte_data(client, reg) & 0xff; - } else { - /* EEPROM, do nothing */ - res = 0; - } - return res; -} - -int adm1026_write_value(struct i2c_client *client, u8 reg, int value) -{ - int res; - - if (reg < 0x80) { - /* "RAM" locations */ - res = i2c_smbus_write_byte_data(client, reg, value); - } else { - /* EEPROM, do nothing */ - res = 0; - } - return res; -} - -void adm1026_init_client(struct i2c_client *client) -{ - int value, i; - struct adm1026_data *data = i2c_get_clientdata(client); - - dev_dbg(&client->dev, "Initializing device\n"); - /* Read chip config */ - data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1); - data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2); - data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3); - - /* Inform user of chip config */ - dev_dbg(&client->dev, "ADM1026_REG_CONFIG1 is: 0x%02x\n", - data->config1); - if ((data->config1 & CFG1_MONITOR) == 0) { - dev_dbg(&client->dev, "Monitoring not currently " - "enabled.\n"); - } - if (data->config1 & CFG1_INT_ENABLE) { - dev_dbg(&client->dev, "SMBALERT interrupts are " - "enabled.\n"); - } - if (data->config1 & CFG1_AIN8_9) { - dev_dbg(&client->dev, "in8 and in9 enabled. " - "temp3 disabled.\n"); - } else { - dev_dbg(&client->dev, "temp3 enabled. in8 and " - "in9 disabled.\n"); - } - if (data->config1 & CFG1_THERM_HOT) { - dev_dbg(&client->dev, "Automatic THERM, PWM, " - "and temp limits enabled.\n"); - } - - value = data->config3; - if (data->config3 & CFG3_GPIO16_ENABLE) { - dev_dbg(&client->dev, "GPIO16 enabled. THERM" - "pin disabled.\n"); - } else { - dev_dbg(&client->dev, "THERM pin enabled. " - "GPIO16 disabled.\n"); - } - if (data->config3 & CFG3_VREF_250) { - dev_dbg(&client->dev, "Vref is 2.50 Volts.\n"); - } else { - dev_dbg(&client->dev, "Vref is 1.82 Volts.\n"); - } - /* Read and pick apart the existing GPIO configuration */ - value = 0; - for (i = 0;i <= 15;++i) { - if ((i & 0x03) == 0) { - value = adm1026_read_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4); - } - data->gpio_config[i] = value & 0x03; - value >>= 2; - } - data->gpio_config[16] = (data->config3 >> 6) & 0x03; - - /* ... and then print it */ - adm1026_print_gpio(client); - - /* If the user asks us to reprogram the GPIO config, then - * do it now. - */ - if (gpio_input[0] != -1 || gpio_output[0] != -1 - || gpio_inverted[0] != -1 || gpio_normal[0] != -1 - || gpio_fan[0] != -1) { - adm1026_fixup_gpio(client); - } - - /* WE INTENTIONALLY make no changes to the limits, - * offsets, pwms, fans and zones. If they were - * configured, we don't want to mess with them. - * If they weren't, the default is 100% PWM, no - * control and will suffice until 'sensors -s' - * can be run by the user. We DO set the default - * value for pwm1.auto_pwm_min to its maximum - * so that enabling automatic pwm fan control - * without first setting a value for pwm1.auto_pwm_min - * will not result in potentially dangerous fan speed decrease. - */ - data->pwm1.auto_pwm_min=255; - /* Start monitoring */ - value = adm1026_read_value(client, ADM1026_REG_CONFIG1); - /* Set MONITOR, clear interrupt acknowledge and s/w reset */ - value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET); - dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value); - data->config1 = value; - adm1026_write_value(client, ADM1026_REG_CONFIG1, value); - - /* initialize fan_div[] to hardware defaults */ - value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) | - (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8); - for (i = 0;i <= 7;++i) { - data->fan_div[i] = DIV_FROM_REG(value & 0x03); - value >>= 2; - } -} - -void adm1026_print_gpio(struct i2c_client *client) -{ - struct adm1026_data *data = i2c_get_clientdata(client); - int i; - - dev_dbg(&client->dev, "GPIO config is:"); - for (i = 0;i <= 7;++i) { - if (data->config2 & (1 << i)) { - dev_dbg(&client->dev, "\t%sGP%s%d\n", - data->gpio_config[i] & 0x02 ? "" : "!", - data->gpio_config[i] & 0x01 ? "OUT" : "IN", - i); - } else { - dev_dbg(&client->dev, "\tFAN%d\n", i); - } - } - for (i = 8;i <= 15;++i) { - dev_dbg(&client->dev, "\t%sGP%s%d\n", - data->gpio_config[i] & 0x02 ? "" : "!", - data->gpio_config[i] & 0x01 ? "OUT" : "IN", - i); - } - if (data->config3 & CFG3_GPIO16_ENABLE) { - dev_dbg(&client->dev, "\t%sGP%s16\n", - data->gpio_config[16] & 0x02 ? "" : "!", - data->gpio_config[16] & 0x01 ? "OUT" : "IN"); - } else { - /* GPIO16 is THERM */ - dev_dbg(&client->dev, "\tTHERM\n"); - } -} - -void adm1026_fixup_gpio(struct i2c_client *client) -{ - struct adm1026_data *data = i2c_get_clientdata(client); - int i; - int value; - - /* Make the changes requested. */ - /* We may need to unlock/stop monitoring or soft-reset the - * chip before we can make changes. This hasn't been - * tested much. FIXME - */ - - /* Make outputs */ - for (i = 0;i <= 16;++i) { - if (gpio_output[i] >= 0 && gpio_output[i] <= 16) { - data->gpio_config[gpio_output[i]] |= 0x01; - } - /* if GPIO0-7 is output, it isn't a FAN tach */ - if (gpio_output[i] >= 0 && gpio_output[i] <= 7) { - data->config2 |= 1 << gpio_output[i]; - } - } - - /* Input overrides output */ - for (i = 0;i <= 16;++i) { - if (gpio_input[i] >= 0 && gpio_input[i] <= 16) { - data->gpio_config[gpio_input[i]] &= ~ 0x01; - } - /* if GPIO0-7 is input, it isn't a FAN tach */ - if (gpio_input[i] >= 0 && gpio_input[i] <= 7) { - data->config2 |= 1 << gpio_input[i]; - } - } - - /* Inverted */ - for (i = 0;i <= 16;++i) { - if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16) { - data->gpio_config[gpio_inverted[i]] &= ~ 0x02; - } - } - - /* Normal overrides inverted */ - for (i = 0;i <= 16;++i) { - if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16) { - data->gpio_config[gpio_normal[i]] |= 0x02; - } - } - - /* Fan overrides input and output */ - for (i = 0;i <= 7;++i) { - if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7) { - data->config2 &= ~(1 << gpio_fan[i]); - } - } - - /* Write new configs to registers */ - adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2); - data->config3 = (data->config3 & 0x3f) - | ((data->gpio_config[16] & 0x03) << 6); - adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3); - for (i = 15, value = 0;i >= 0;--i) { - value <<= 2; - value |= data->gpio_config[i] & 0x03; - if ((i & 0x03) == 0) { - adm1026_write_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4, - value); - value = 0; - } - } - - /* Print the new config */ - adm1026_print_gpio(client); -} - - -static struct adm1026_data *adm1026_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int i; - long value, alarms, gpio; - - down(&data->update_lock); - if (!data->valid - || time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) { - /* Things that change quickly */ - dev_dbg(&client->dev,"Reading sensor values\n"); - for (i = 0;i <= 16;++i) { - data->in[i] = - adm1026_read_value(client, ADM1026_REG_IN[i]); - } - - for (i = 0;i <= 7;++i) { - data->fan[i] = - adm1026_read_value(client, ADM1026_REG_FAN(i)); - } - - for (i = 0;i <= 2;++i) { - /* NOTE: temp[] is s8 and we assume 2's complement - * "conversion" in the assignment */ - data->temp[i] = - adm1026_read_value(client, ADM1026_REG_TEMP[i]); - } - - data->pwm1.pwm = adm1026_read_value(client, - ADM1026_REG_PWM); - data->analog_out = adm1026_read_value(client, - ADM1026_REG_DAC); - /* GPIO16 is MSbit of alarms, move it to gpio */ - alarms = adm1026_read_value(client, ADM1026_REG_STATUS4); - gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ - alarms &= 0x7f; - alarms <<= 8; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3); - alarms <<= 8; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS2); - alarms <<= 8; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS1); - data->alarms = alarms; - - /* Read the GPIO values */ - gpio |= adm1026_read_value(client, - ADM1026_REG_GPIO_STATUS_8_15); - gpio <<= 8; - gpio |= adm1026_read_value(client, - ADM1026_REG_GPIO_STATUS_0_7); - data->gpio = gpio; - - data->last_reading = jiffies; - }; /* last_reading */ - - if (!data->valid || - time_after(jiffies, data->last_config + ADM1026_CONFIG_INTERVAL)) { - /* Things that don't change often */ - dev_dbg(&client->dev, "Reading config values\n"); - for (i = 0;i <= 16;++i) { - data->in_min[i] = adm1026_read_value(client, - ADM1026_REG_IN_MIN[i]); - data->in_max[i] = adm1026_read_value(client, - ADM1026_REG_IN_MAX[i]); - } - - value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) - | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) - << 8); - for (i = 0;i <= 7;++i) { - data->fan_min[i] = adm1026_read_value(client, - ADM1026_REG_FAN_MIN(i)); - data->fan_div[i] = DIV_FROM_REG(value & 0x03); - value >>= 2; - } - - for (i = 0; i <= 2; ++i) { - /* NOTE: temp_xxx[] are s8 and we assume 2's - * complement "conversion" in the assignment - */ - data->temp_min[i] = adm1026_read_value(client, - ADM1026_REG_TEMP_MIN[i]); - data->temp_max[i] = adm1026_read_value(client, - ADM1026_REG_TEMP_MAX[i]); - data->temp_tmin[i] = adm1026_read_value(client, - ADM1026_REG_TEMP_TMIN[i]); - data->temp_crit[i] = adm1026_read_value(client, - ADM1026_REG_TEMP_THERM[i]); - data->temp_offset[i] = adm1026_read_value(client, - ADM1026_REG_TEMP_OFFSET[i]); - } - - /* Read the STATUS/alarm masks */ - alarms = adm1026_read_value(client, ADM1026_REG_MASK4); - gpio = alarms & 0x80 ? 0x0100 : 0; /* GPIO16 */ - alarms = (alarms & 0x7f) << 8; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK3); - alarms <<= 8; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK2); - alarms <<= 8; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK1); - data->alarm_mask = alarms; - - /* Read the GPIO values */ - gpio |= adm1026_read_value(client, - ADM1026_REG_GPIO_MASK_8_15); - gpio <<= 8; - gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7); - data->gpio_mask = gpio; - - /* Read various values from CONFIG1 */ - data->config1 = adm1026_read_value(client, - ADM1026_REG_CONFIG1); - if (data->config1 & CFG1_PWM_AFC) { - data->pwm1.enable = 2; - data->pwm1.auto_pwm_min = - PWM_MIN_FROM_REG(data->pwm1.pwm); - } - /* Read the GPIO config */ - data->config2 = adm1026_read_value(client, - ADM1026_REG_CONFIG2); - data->config3 = adm1026_read_value(client, - ADM1026_REG_CONFIG3); - data->gpio_config[16] = (data->config3 >> 6) & 0x03; - - value = 0; - for (i = 0;i <= 15;++i) { - if ((i & 0x03) == 0) { - value = adm1026_read_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4); - } - data->gpio_config[i] = value & 0x03; - value >>= 2; - } - - data->last_config = jiffies; - }; /* last_config */ - - dev_dbg(&client->dev, "Setting VID from GPIO11-15.\n"); - data->vid = (data->gpio >> 11) & 0x1f; - data->valid = 1; - up(&data->update_lock); - return data; -} - -static ssize_t show_in(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr])); -} -static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr])); -} -static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = INS_TO_REG(nr, val); - adm1026_write_value(client, ADM1026_REG_IN_MIN[nr], data->in_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr])); -} -static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = INS_TO_REG(nr, val); - adm1026_write_value(client, ADM1026_REG_IN_MAX[nr], data->in_max[nr]); - up(&data->update_lock); - return count; -} - -#define in_reg(offset) \ -static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in, \ - NULL, offset); \ -static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in_min, set_in_min, offset); \ -static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in_max, set_in_max, offset); - - -in_reg(0); -in_reg(1); -in_reg(2); -in_reg(3); -in_reg(4); -in_reg(5); -in_reg(6); -in_reg(7); -in_reg(8); -in_reg(9); -in_reg(10); -in_reg(11); -in_reg(12); -in_reg(13); -in_reg(14); -in_reg(15); - -static ssize_t show_in16(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in[16]) - - NEG12_OFFSET); -} -static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_min[16]) - - NEG12_OFFSET); -} -static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET); - adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]); - up(&data->update_lock); - return count; -} -static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(16, data->in_max[16]) - - NEG12_OFFSET); -} -static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET); - adm1026_write_value(client, ADM1026_REG_IN_MAX[16], data->in_max[16]); - up(&data->update_lock); - return count; -} - -static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in16, NULL, 16); -static SENSOR_DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min, set_in16_min, 16); -static SENSOR_DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max, set_in16_max, 16); - - - - -/* Now add fan read/write functions */ - -static ssize_t show_fan(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], - data->fan_div[nr])); -} -static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], - data->fan_div[nr])); -} -static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, data->fan_div[nr]); - adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr), - data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -#define fan_offset(offset) \ -static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan, NULL, \ - offset - 1); \ -static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_min, set_fan_min, offset - 1); - -fan_offset(1); -fan_offset(2); -fan_offset(3); -fan_offset(4); -fan_offset(5); -fan_offset(6); -fan_offset(7); -fan_offset(8); - -/* Adjust fan_min to account for new fan divisor */ -static void fixup_fan_min(struct device *dev, int fan, int old_div) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int new_min; - int new_div = data->fan_div[fan]; - - /* 0 and 0xff are special. Don't adjust them */ - if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff) { - return; - } - - new_min = data->fan_min[fan] * old_div / new_div; - new_min = SENSORS_LIMIT(new_min, 1, 254); - data->fan_min[fan] = new_min; - adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min); -} - -/* Now add fan_div read/write functions */ -static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", data->fan_div[nr]); -} -static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val,orig_div,new_div,shift; - - val = simple_strtol(buf, NULL, 10); - new_div = DIV_TO_REG(val); - if (new_div == 0) { - return -EINVAL; - } - down(&data->update_lock); - orig_div = data->fan_div[nr]; - data->fan_div[nr] = DIV_FROM_REG(new_div); - - if (nr < 4) { /* 0 <= nr < 4 */ - shift = 2 * nr; - adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3, - ((DIV_TO_REG(orig_div) & (~(0x03 << shift))) | - (new_div << shift))); - } else { /* 3 < nr < 8 */ - shift = 2 * (nr - 4); - adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7, - ((DIV_TO_REG(orig_div) & (~(0x03 << (2 * shift)))) | - (new_div << shift))); - } - - if (data->fan_div[nr] != orig_div) { - fixup_fan_min(dev,nr,orig_div); - } - up(&data->update_lock); - return count; -} - -#define fan_offset_div(offset) \ -static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_div, set_fan_div, offset - 1); - -fan_offset_div(1); -fan_offset_div(2); -fan_offset_div(3); -fan_offset_div(4); -fan_offset_div(5); -fan_offset_div(6); -fan_offset_div(7); -fan_offset_div(8); - -/* Temps */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr])); -} -static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr])); -} -static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_min[nr] = TEMP_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_TEMP_MIN[nr], - data->temp_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr])); -} -static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_max[nr] = TEMP_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_TEMP_MAX[nr], - data->temp_max[nr]); - up(&data->update_lock); - return count; -} - -#define temp_reg(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ - NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_min, set_temp_min, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_max, set_temp_max, offset - 1); - - -temp_reg(1); -temp_reg(2); -temp_reg(3); - -static ssize_t show_temp_offset(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_offset[nr])); -} -static ssize_t set_temp_offset(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_offset[nr] = TEMP_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET[nr], - data->temp_offset[nr]); - up(&data->update_lock); - return count; -} - -#define temp_offset_reg(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR, \ - show_temp_offset, set_temp_offset, offset - 1); - -temp_offset_reg(1); -temp_offset_reg(2); -temp_offset_reg(3); - -static ssize_t show_temp_auto_point1_temp_hyst(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG( - ADM1026_FAN_ACTIVATION_TEMP_HYST + data->temp_tmin[nr])); -} -static ssize_t show_temp_auto_point2_temp(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr] + - ADM1026_FAN_CONTROL_TEMP_RANGE)); -} -static ssize_t show_temp_auto_point1_temp(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_tmin[nr])); -} -static ssize_t set_temp_auto_point1_temp(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_tmin[nr] = TEMP_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_TEMP_TMIN[nr], - data->temp_tmin[nr]); - up(&data->update_lock); - return count; -} - -#define temp_auto_point(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp, S_IRUGO | S_IWUSR, \ - show_temp_auto_point1_temp, set_temp_auto_point1_temp, \ - offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_auto_point1_temp_hyst, S_IRUGO, \ - show_temp_auto_point1_temp_hyst, NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_auto_point2_temp, S_IRUGO, \ - show_temp_auto_point2_temp, NULL, offset - 1); - -temp_auto_point(1); -temp_auto_point(2); -temp_auto_point(3); - -static ssize_t show_temp_crit_enable(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", (data->config1 & CFG1_THERM_HOT) >> 4); -} -static ssize_t set_temp_crit_enable(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - if ((val == 1) || (val==0)) { - down(&data->update_lock); - data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4); - adm1026_write_value(client, ADM1026_REG_CONFIG1, - data->config1); - up(&data->update_lock); - } - return count; -} - -#define temp_crit_enable(offset) \ -static DEVICE_ATTR(temp##offset##_crit_enable, S_IRUGO | S_IWUSR, \ - show_temp_crit_enable, set_temp_crit_enable); - -temp_crit_enable(1); -temp_crit_enable(2); -temp_crit_enable(3); - -static ssize_t show_temp_crit(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_crit[nr])); -} -static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_crit[nr] = TEMP_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_TEMP_THERM[nr], - data->temp_crit[nr]); - up(&data->update_lock); - return count; -} - -#define temp_crit_reg(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ - show_temp_crit, set_temp_crit, offset - 1); - -temp_crit_reg(1); -temp_crit_reg(2); -temp_crit_reg(3); - -static ssize_t show_analog_out_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", DAC_FROM_REG(data->analog_out)); -} -static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->analog_out = DAC_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_DAC, data->analog_out); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg, - set_analog_out_reg); - -static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm)); -} -/* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ -static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL); -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); - -static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", data->vrm); -} -static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - - data->vrm = simple_strtol(buf, NULL, 10); - return count; -} - -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); - -static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf, "%ld\n", (long) (data->alarms)); -} - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); - -static ssize_t show_alarm_mask(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%ld\n", data->alarm_mask); -} -static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - unsigned long mask; - - down(&data->update_lock); - data->alarm_mask = val & 0x7fffffff; - mask = data->alarm_mask - | (data->gpio_mask & 0x10000 ? 0x80000000 : 0); - adm1026_write_value(client, ADM1026_REG_MASK1, - mask & 0xff); - mask >>= 8; - adm1026_write_value(client, ADM1026_REG_MASK2, - mask & 0xff); - mask >>= 8; - adm1026_write_value(client, ADM1026_REG_MASK3, - mask & 0xff); - mask >>= 8; - adm1026_write_value(client, ADM1026_REG_MASK4, - mask & 0xff); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask, - set_alarm_mask); - - -static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%ld\n", data->gpio); -} -static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - long gpio; - - down(&data->update_lock); - data->gpio = val & 0x1ffff; - gpio = data->gpio; - adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_0_7,gpio & 0xff); - gpio >>= 8; - adm1026_write_value(client, ADM1026_REG_GPIO_STATUS_8_15,gpio & 0xff); - gpio = ((gpio >> 1) & 0x80) | (data->alarms >> 24 & 0x7f); - adm1026_write_value(client, ADM1026_REG_STATUS4,gpio & 0xff); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio); - - -static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%ld\n", data->gpio_mask); -} -static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - long mask; - - down(&data->update_lock); - data->gpio_mask = val & 0x1ffff; - mask = data->gpio_mask; - adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7,mask & 0xff); - mask >>= 8; - adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15,mask & 0xff); - mask = ((mask >> 1) & 0x80) | (data->alarm_mask >> 24 & 0x7f); - adm1026_write_value(client, ADM1026_REG_MASK1,mask & 0xff); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask); - -static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm1.pwm)); -} -static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - - if (data->pwm1.enable == 1) { - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->pwm1.pwm = PWM_TO_REG(val); - adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); - up(&data->update_lock); - } - return count; -} -static ssize_t show_auto_pwm_min(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", data->pwm1.auto_pwm_min); -} -static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->pwm1.auto_pwm_min = SENSORS_LIMIT(val,0,255); - if (data->pwm1.enable == 2) { /* apply immediately */ - data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | - PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); - adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); - } - up(&data->update_lock); - return count; -} -static ssize_t show_auto_pwm_max(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%d\n", ADM1026_PWM_MAX); -} -static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf,"%d\n", data->pwm1.enable); -} -static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - int old_enable; - - if ((val >= 0) && (val < 3)) { - down(&data->update_lock); - old_enable = data->pwm1.enable; - data->pwm1.enable = val; - data->config1 = (data->config1 & ~CFG1_PWM_AFC) - | ((val == 2) ? CFG1_PWM_AFC : 0); - adm1026_write_value(client, ADM1026_REG_CONFIG1, - data->config1); - if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */ - data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | - PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); - adm1026_write_value(client, ADM1026_REG_PWM, - data->pwm1.pwm); - } else if (!((old_enable == 1) && (val == 1))) { - /* set pwm to safe value */ - data->pwm1.pwm = 255; - adm1026_write_value(client, ADM1026_REG_PWM, - data->pwm1.pwm); - } - up(&data->update_lock); - } - return count; -} - -/* enable PWM fan control */ -static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, - set_pwm_enable); -static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable, - set_pwm_enable); -static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable, - set_pwm_enable); -static DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO | S_IWUSR, - show_auto_pwm_min, set_auto_pwm_min); -static DEVICE_ATTR(temp2_auto_point1_pwm, S_IRUGO | S_IWUSR, - show_auto_pwm_min, set_auto_pwm_min); -static DEVICE_ATTR(temp3_auto_point1_pwm, S_IRUGO | S_IWUSR, - show_auto_pwm_min, set_auto_pwm_min); - -static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); -static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); -static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); - -int adm1026_detect(struct i2c_adapter *adapter, int address, - int kind) -{ - int company, verstep; - struct i2c_client *new_client; - struct adm1026_data *data; - int err = 0; - const char *type_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - /* We need to be able to do byte I/O */ - goto exit; - }; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1026_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1026_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - - memset(data, 0, sizeof(struct adm1026_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1026_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - company = adm1026_read_value(new_client, ADM1026_REG_COMPANY); - verstep = adm1026_read_value(new_client, ADM1026_REG_VERSTEP); - - dev_dbg(&new_client->dev, "Detecting device at %d,0x%02x with" - " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", - i2c_adapter_id(new_client->adapter), new_client->addr, - company, verstep); - - /* If auto-detecting, Determine the chip type. */ - if (kind <= 0) { - dev_dbg(&new_client->dev, "Autodetecting device at %d,0x%02x " - "...\n", i2c_adapter_id(adapter), address); - if (company == ADM1026_COMPANY_ANALOG_DEV - && verstep == ADM1026_VERSTEP_ADM1026) { - kind = adm1026; - } else if (company == ADM1026_COMPANY_ANALOG_DEV - && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) { - dev_err(&adapter->dev, ": Unrecognized stepping " - "0x%02x. Defaulting to ADM1026.\n", verstep); - kind = adm1026; - } else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) { - dev_err(&adapter->dev, ": Found version/stepping " - "0x%02x. Assuming generic ADM1026.\n", - verstep); - kind = any_chip; - } else { - dev_dbg(&new_client->dev, ": Autodetection " - "failed\n"); - /* Not an ADM1026 ... */ - if (kind == 0) { /* User used force=x,y */ - dev_err(&adapter->dev, "Generic ADM1026 not " - "found at %d,0x%02x. Try " - "force_adm1026.\n", - i2c_adapter_id(adapter), address); - } - err = 0; - goto exitfree; - } - } - - /* Fill in the chip specific driver values */ - switch (kind) { - case any_chip : - type_name = "adm1026"; - break; - case adm1026 : - type_name = "adm1026"; - break; - default : - dev_err(&adapter->dev, ": Internal error, invalid " - "kind (%d)!", kind); - err = -EFAULT; - goto exitfree; - } - strlcpy(new_client->name, type_name, I2C_NAME_SIZE); - - /* Fill in the remaining client fields */ - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exitfree; - - /* Set the VRM version */ - data->vrm = i2c_which_vrm(); - - /* Initialize the ADM1026 chip */ - adm1026_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in11_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in11_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in11_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in12_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in12_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in12_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in13_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in13_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in13_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in14_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in14_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in14_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in15_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in15_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in15_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in16_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in16_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in16_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan4_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan4_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan4_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan5_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan5_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan5_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan6_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan6_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan6_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan7_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan7_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan7_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan8_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan8_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan8_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_offset.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_offset.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_offset.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_auto_point1_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_auto_point1_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_auto_point1_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_auto_point2_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_auto_point2_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_auto_point2_temp.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable); - device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable); - device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable); - /* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */ - device_create_file(&new_client->dev, &dev_attr_vid); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_vrm); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_alarm_mask); - device_create_file(&new_client->dev, &dev_attr_gpio); - device_create_file(&new_client->dev, &dev_attr_gpio_mask); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_pwm3); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, &dev_attr_pwm2_enable); - device_create_file(&new_client->dev, &dev_attr_pwm3_enable); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_point1_pwm); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_point1_pwm); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_point1_pwm); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_point2_pwm); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_point2_pwm); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_point2_pwm); - device_create_file(&new_client->dev, &dev_attr_analog_out); - return 0; - - /* Error out and cleanup code */ -exitfree: - kfree(new_client); -exit: - return err; -} -static int __init sm_adm1026_init(void) -{ - return i2c_add_driver(&adm1026_driver); -} - -static void __exit sm_adm1026_exit(void) -{ - i2c_del_driver(&adm1026_driver); -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Philip Pokorny , " - "Justin Thiessen "); -MODULE_DESCRIPTION("ADM1026 driver"); - -module_init(sm_adm1026_init); -module_exit(sm_adm1026_exit); diff --git a/drivers/i2c/chips/adm1031.c b/drivers/i2c/chips/adm1031.c deleted file mode 100644 index 9168e983ca1..00000000000 --- a/drivers/i2c/chips/adm1031.c +++ /dev/null @@ -1,977 +0,0 @@ -/* - adm1031.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Based on lm75.c and lm85.c - Supports adm1030 / adm1031 - Copyright (C) 2004 Alexandre d'Alton - Reworked by Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include - -/* Following macros takes channel parameter starting from 0 to 2 */ -#define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) -#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) -#define ADM1031_REG_PWM (0x22) -#define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr)) - -#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4*(nr)) -#define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4*(nr)) -#define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4*(nr)) - -#define ADM1031_REG_TEMP(nr) (0xa + (nr)) -#define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr)) - -#define ADM1031_REG_STATUS(nr) (0x2 + (nr)) - -#define ADM1031_REG_CONF1 0x0 -#define ADM1031_REG_CONF2 0x1 -#define ADM1031_REG_EXT_TEMP 0x6 - -#define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */ -#define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert */ -#define ADM1031_CONF1_AUTO_MODE 0x80 /* Auto FAN */ - -#define ADM1031_CONF2_PWM1_ENABLE 0x01 -#define ADM1031_CONF2_PWM2_ENABLE 0x02 -#define ADM1031_CONF2_TACH1_ENABLE 0x04 -#define ADM1031_CONF2_TACH2_ENABLE 0x08 -#define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan)) - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(adm1030, adm1031); - -typedef u8 auto_chan_table_t[8][2]; - -/* Each client has this additional data */ -struct adm1031_data { - struct i2c_client client; - struct semaphore update_lock; - int chip_type; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - /* The chan_select_table contains the possible configurations for - * auto fan control. - */ - auto_chan_table_t *chan_select_table; - u16 alarm; - u8 conf1; - u8 conf2; - u8 fan[2]; - u8 fan_div[2]; - u8 fan_min[2]; - u8 pwm[2]; - u8 old_pwm[2]; - s8 temp[3]; - u8 ext_temp[3]; - u8 auto_temp[3]; - u8 auto_temp_min[3]; - u8 auto_temp_off[3]; - u8 auto_temp_max[3]; - s8 temp_min[3]; - s8 temp_max[3]; - s8 temp_crit[3]; -}; - -static int adm1031_attach_adapter(struct i2c_adapter *adapter); -static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind); -static void adm1031_init_client(struct i2c_client *client); -static int adm1031_detach_client(struct i2c_client *client); -static struct adm1031_data *adm1031_update_device(struct device *dev); - -/* This is the driver that will be inserted */ -static struct i2c_driver adm1031_driver = { - .owner = THIS_MODULE, - .name = "adm1031", - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1031_attach_adapter, - .detach_client = adm1031_detach_client, -}; - -static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static inline int -adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - - -#define TEMP_TO_REG(val) (((val) < 0 ? ((val - 500) / 1000) : \ - ((val + 500) / 1000))) - -#define TEMP_FROM_REG(val) ((val) * 1000) - -#define TEMP_FROM_REG_EXT(val, ext) (TEMP_FROM_REG(val) + (ext) * 125) - -#define FAN_FROM_REG(reg, div) ((reg) ? (11250 * 60) / ((reg) * (div)) : 0) - -static int FAN_TO_REG(int reg, int div) -{ - int tmp; - tmp = FAN_FROM_REG(SENSORS_LIMIT(reg, 0, 65535), div); - return tmp > 255 ? 255 : tmp; -} - -#define FAN_DIV_FROM_REG(reg) (1<<(((reg)&0xc0)>>6)) - -#define PWM_TO_REG(val) (SENSORS_LIMIT((val), 0, 255) >> 4) -#define PWM_FROM_REG(val) ((val) << 4) - -#define FAN_CHAN_FROM_REG(reg) (((reg) >> 5) & 7) -#define FAN_CHAN_TO_REG(val, reg) \ - (((reg) & 0x1F) | (((val) << 5) & 0xe0)) - -#define AUTO_TEMP_MIN_TO_REG(val, reg) \ - ((((val)/500) & 0xf8)|((reg) & 0x7)) -#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1<< ((reg)&0x7))) -#define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2)) - -#define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2) - -#define AUTO_TEMP_OFF_FROM_REG(reg) \ - (AUTO_TEMP_MIN_FROM_REG(reg) - 5000) - -#define AUTO_TEMP_MAX_FROM_REG(reg) \ - (AUTO_TEMP_RANGE_FROM_REG(reg) + \ - AUTO_TEMP_MIN_FROM_REG(reg)) - -static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm) -{ - int ret; - int range = val - AUTO_TEMP_MIN_FROM_REG(reg); - - range = ((val - AUTO_TEMP_MIN_FROM_REG(reg))*10)/(16 - pwm); - ret = ((reg & 0xf8) | - (range < 10000 ? 0 : - range < 20000 ? 1 : - range < 40000 ? 2 : range < 80000 ? 3 : 4)); - return ret; -} - -/* FAN auto control */ -#define GET_FAN_AUTO_BITFIELD(data, idx) \ - (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2] - -/* The tables below contains the possible values for the auto fan - * control bitfields. the index in the table is the register value. - * MSb is the auto fan control enable bit, so the four first entries - * in the table disables auto fan control when both bitfields are zero. - */ -static auto_chan_table_t auto_channel_select_table_adm1031 = { - {0, 0}, {0, 0}, {0, 0}, {0, 0}, - {2 /*0b010 */ , 4 /*0b100 */ }, - {2 /*0b010 */ , 2 /*0b010 */ }, - {4 /*0b100 */ , 4 /*0b100 */ }, - {7 /*0b111 */ , 7 /*0b111 */ }, -}; - -static auto_chan_table_t auto_channel_select_table_adm1030 = { - {0, 0}, {0, 0}, {0, 0}, {0, 0}, - {2 /*0b10 */ , 0}, - {0xff /*invalid */ , 0}, - {0xff /*invalid */ , 0}, - {3 /*0b11 */ , 0}, -}; - -/* That function checks if a bitfield is valid and returns the other bitfield - * nearest match if no exact match where found. - */ -static int -get_fan_auto_nearest(struct adm1031_data *data, - int chan, u8 val, u8 reg, u8 * new_reg) -{ - int i; - int first_match = -1, exact_match = -1; - u8 other_reg_val = - (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1]; - - if (val == 0) { - *new_reg = 0; - return 0; - } - - for (i = 0; i < 8; i++) { - if ((val == (*data->chan_select_table)[i][chan]) && - ((*data->chan_select_table)[i][chan ? 0 : 1] == - other_reg_val)) { - /* We found an exact match */ - exact_match = i; - break; - } else if (val == (*data->chan_select_table)[i][chan] && - first_match == -1) { - /* Save the first match in case of an exact match has not been - * found - */ - first_match = i; - } - } - - if (exact_match >= 0) { - *new_reg = exact_match; - } else if (first_match >= 0) { - *new_reg = first_match; - } else { - return -EINVAL; - } - return 0; -} - -static ssize_t show_fan_auto_channel(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr)); -} - -static ssize_t -set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - u8 reg; - int ret; - u8 old_fan_mode; - - old_fan_mode = data->conf1; - - down(&data->update_lock); - - if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®))) { - up(&data->update_lock); - return ret; - } - if (((data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1)) & ADM1031_CONF1_AUTO_MODE) ^ - (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { - if (data->conf1 & ADM1031_CONF1_AUTO_MODE){ - /* Switch to Auto Fan Mode - * Save PWM registers - * Set PWM registers to 33% Both */ - data->old_pwm[0] = data->pwm[0]; - data->old_pwm[1] = data->pwm[1]; - adm1031_write_value(client, ADM1031_REG_PWM, 0x55); - } else { - /* Switch to Manual Mode */ - data->pwm[0] = data->old_pwm[0]; - data->pwm[1] = data->old_pwm[1]; - /* Restore PWM registers */ - adm1031_write_value(client, ADM1031_REG_PWM, - data->pwm[0] | (data->pwm[1] << 4)); - } - } - data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); - adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1); - up(&data->update_lock); - return count; -} - -#define fan_auto_channel_offset(offset) \ -static ssize_t show_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_auto_channel(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_auto_channel_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_auto_channel(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(auto_fan##offset##_channel, S_IRUGO | S_IWUSR, \ - show_fan_auto_channel_##offset, \ - set_fan_auto_channel_##offset) - -fan_auto_channel_offset(1); -fan_auto_channel_offset(2); - -/* Auto Temps */ -static ssize_t show_auto_temp_off(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", - AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr])); -} -static ssize_t show_auto_temp_min(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr])); -} -static ssize_t -set_auto_temp_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]); - adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), - data->auto_temp[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_auto_temp_max(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", - AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr])); -} -static ssize_t -set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]); - adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), - data->temp_max[nr]); - up(&data->update_lock); - return count; -} - -#define auto_temp_reg(offset) \ -static ssize_t show_auto_temp_##offset##_off (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_auto_temp_off(dev, buf, offset - 1); \ -} \ -static ssize_t show_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_auto_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_auto_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_auto_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_auto_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_auto_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_auto_temp_max(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO, \ - show_auto_temp_##offset##_off, NULL); \ -static DEVICE_ATTR(auto_temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_auto_temp_##offset##_min, set_auto_temp_##offset##_min);\ -static DEVICE_ATTR(auto_temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_auto_temp_##offset##_max, set_auto_temp_##offset##_max) - -auto_temp_reg(1); -auto_temp_reg(2); -auto_temp_reg(3); - -/* pwm */ -static ssize_t show_pwm(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); -} -static ssize_t -set_pwm(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - int reg; - - down(&data->update_lock); - if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && - (((val>>4) & 0xf) != 5)) { - /* In automatic mode, the only PWM accepted is 33% */ - up(&data->update_lock); - return -EINVAL; - } - data->pwm[nr] = PWM_TO_REG(val); - reg = adm1031_read_value(client, ADM1031_REG_PWM); - adm1031_write_value(client, ADM1031_REG_PWM, - nr ? ((data->pwm[nr] << 4) & 0xf0) | (reg & 0xf) - : (data->pwm[nr] & 0xf) | (reg & 0xf0)); - up(&data->update_lock); - return count; -} - -#define pwm_reg(offset) \ -static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm_##offset, set_pwm_##offset) - -pwm_reg(1); -pwm_reg(2); - -/* Fans */ - -/* - * That function checks the cases where the fan reading is not - * relevant. It is used to provide 0 as fan reading when the fan is - * not supposed to run - */ -static int trust_fan_readings(struct adm1031_data *data, int chan) -{ - int res = 0; - - if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { - switch (data->conf1 & 0x60) { - case 0x00: /* remote temp1 controls fan1 remote temp2 controls fan2 */ - res = data->temp[chan+1] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); - break; - case 0x20: /* remote temp1 controls both fans */ - res = - data->temp[1] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]); - break; - case 0x40: /* remote temp2 controls both fans */ - res = - data->temp[2] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]); - break; - case 0x60: /* max controls both fans */ - res = - data->temp[0] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0]) - || data->temp[1] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]) - || (data->chip_type == adm1031 - && data->temp[2] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2])); - break; - } - } else { - res = data->pwm[chan] > 0; - } - return res; -} - - -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - int value; - - value = trust_fan_readings(data, nr) ? FAN_FROM_REG(data->fan[nr], - FAN_DIV_FROM_REG(data->fan_div[nr])) : 0; - return sprintf(buf, "%d\n", value); -} - -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr])); -} -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", - FAN_FROM_REG(data->fan_min[nr], - FAN_DIV_FROM_REG(data->fan_div[nr]))); -} -static ssize_t -set_fan_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - if (val) { - data->fan_min[nr] = - FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr])); - } else { - data->fan_min[nr] = 0xff; - } - adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t -set_fan_div(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - u8 tmp; - int old_div; - int new_min; - - tmp = val == 8 ? 0xc0 : - val == 4 ? 0x80 : - val == 2 ? 0x40 : - val == 1 ? 0x00 : - 0xff; - if (tmp == 0xff) - return -EINVAL; - - down(&data->update_lock); - old_div = FAN_DIV_FROM_REG(data->fan_div[nr]); - data->fan_div[nr] = (tmp & 0xC0) | (0x3f & data->fan_div[nr]); - new_min = data->fan_min[nr] * old_div / - FAN_DIV_FROM_REG(data->fan_div[nr]); - data->fan_min[nr] = new_min > 0xff ? 0xff : new_min; - data->fan[nr] = data->fan[nr] * old_div / - FAN_DIV_FROM_REG(data->fan_div[nr]); - - adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr), - data->fan_div[nr]); - adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), - data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -#define fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ - NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_div, set_fan_##offset##_div); \ -static DEVICE_ATTR(auto_fan##offset##_min_pwm, S_IRUGO | S_IWUSR, \ - show_pwm_##offset, set_pwm_##offset) - -fan_offset(1); -fan_offset(2); - - -/* Temps */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - int ext; - ext = nr == 0 ? - ((data->ext_temp[nr] >> 6) & 0x3) * 2 : - (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7)); - return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext)); -} -static ssize_t show_temp_min(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr])); -} -static ssize_t show_temp_max(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr])); -} -static ssize_t show_temp_crit(struct device *dev, char *buf, int nr) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr])); -} -static ssize_t -set_temp_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val; - - val = simple_strtol(buf, NULL, 10); - val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); - down(&data->update_lock); - data->temp_min[nr] = TEMP_TO_REG(val); - adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr), - data->temp_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t -set_temp_max(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val; - - val = simple_strtol(buf, NULL, 10); - val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); - down(&data->update_lock); - data->temp_max[nr] = TEMP_TO_REG(val); - adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr), - data->temp_max[nr]); - up(&data->update_lock); - return count; -} -static ssize_t -set_temp_crit(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int val; - - val = simple_strtol(buf, NULL, 10); - val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); - down(&data->update_lock); - data->temp_crit[nr] = TEMP_TO_REG(val); - adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr), - data->temp_crit[nr]); - up(&data->update_lock); - return count; -} - -#define temp_reg(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_crit(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_max(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_crit (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_crit(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ - NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max); \ -static DEVICE_ATTR(temp##offset##_crit, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_crit, set_temp_##offset##_crit) - -temp_reg(1); -temp_reg(2); -temp_reg(3); - -/* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm1031_data *data = adm1031_update_device(dev); - return sprintf(buf, "%d\n", data->alarm); -} - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - - -static int adm1031_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, adm1031_detect); -} - -/* This function is called by i2c_detect */ -static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct adm1031_data *data; - int err = 0; - const char *name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct adm1031_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1031_driver; - new_client->flags = 0; - - if (kind < 0) { - int id, co; - id = i2c_smbus_read_byte_data(new_client, 0x3d); - co = i2c_smbus_read_byte_data(new_client, 0x3e); - - if (!((id == 0x31 || id == 0x30) && co == 0x41)) - goto exit_free; - kind = (id == 0x30) ? adm1030 : adm1031; - } - - if (kind <= 0) - kind = adm1031; - - /* Given the detected chip type, set the chip name and the - * auto fan control helper table. */ - if (kind == adm1030) { - name = "adm1030"; - data->chan_select_table = &auto_channel_select_table_adm1030; - } else if (kind == adm1031) { - name = "adm1031"; - data->chan_select_table = &auto_channel_select_table_adm1031; - } - data->chip_type = kind; - - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the ADM1031 chip */ - adm1031_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - - device_create_file(&new_client->dev, &dev_attr_auto_temp1_off); - device_create_file(&new_client->dev, &dev_attr_auto_temp1_min); - device_create_file(&new_client->dev, &dev_attr_auto_temp1_max); - - device_create_file(&new_client->dev, &dev_attr_auto_temp2_off); - device_create_file(&new_client->dev, &dev_attr_auto_temp2_min); - device_create_file(&new_client->dev, &dev_attr_auto_temp2_max); - - device_create_file(&new_client->dev, &dev_attr_auto_fan1_min_pwm); - - device_create_file(&new_client->dev, &dev_attr_alarms); - - if (kind == adm1031) { - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, - &dev_attr_auto_fan2_channel); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp3_crit); - device_create_file(&new_client->dev, &dev_attr_auto_temp3_off); - device_create_file(&new_client->dev, &dev_attr_auto_temp3_min); - device_create_file(&new_client->dev, &dev_attr_auto_temp3_max); - device_create_file(&new_client->dev, &dev_attr_auto_fan2_min_pwm); - } - - return 0; - -exit_free: - kfree(new_client); -exit: - return err; -} - -static int adm1031_detach_client(struct i2c_client *client) -{ - int ret; - if ((ret = i2c_detach_client(client)) != 0) { - return ret; - } - kfree(client); - return 0; -} - -static void adm1031_init_client(struct i2c_client *client) -{ - unsigned int read_val; - unsigned int mask; - struct adm1031_data *data = i2c_get_clientdata(client); - - mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE); - if (data->chip_type == adm1031) { - mask |= (ADM1031_CONF2_PWM2_ENABLE | - ADM1031_CONF2_TACH2_ENABLE); - } - /* Initialize the ADM1031 chip (enables fan speed reading ) */ - read_val = adm1031_read_value(client, ADM1031_REG_CONF2); - if ((read_val | mask) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); - } - - read_val = adm1031_read_value(client, ADM1031_REG_CONF1); - if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF1, read_val | - ADM1031_CONF1_MONITOR_ENABLE); - } - -} - -static struct adm1031_data *adm1031_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm1031_data *data = i2c_get_clientdata(client); - int chan; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - dev_dbg(&client->dev, "Starting adm1031 update\n"); - for (chan = 0; - chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) { - u8 oldh, newh; - - oldh = - adm1031_read_value(client, ADM1031_REG_TEMP(chan)); - data->ext_temp[chan] = - adm1031_read_value(client, ADM1031_REG_EXT_TEMP); - newh = - adm1031_read_value(client, ADM1031_REG_TEMP(chan)); - if (newh != oldh) { - data->ext_temp[chan] = - adm1031_read_value(client, - ADM1031_REG_EXT_TEMP); -#ifdef DEBUG - oldh = - adm1031_read_value(client, - ADM1031_REG_TEMP(chan)); - - /* oldh is actually newer */ - if (newh != oldh) - dev_warn(&client->dev, - "Remote temperature may be " - "wrong.\n"); -#endif - } - data->temp[chan] = newh; - - data->temp_min[chan] = - adm1031_read_value(client, - ADM1031_REG_TEMP_MIN(chan)); - data->temp_max[chan] = - adm1031_read_value(client, - ADM1031_REG_TEMP_MAX(chan)); - data->temp_crit[chan] = - adm1031_read_value(client, - ADM1031_REG_TEMP_CRIT(chan)); - data->auto_temp[chan] = - adm1031_read_value(client, - ADM1031_REG_AUTO_TEMP(chan)); - - } - - data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); - data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); - - data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0)) - | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) - << 8); - if (data->chip_type == adm1030) { - data->alarm &= 0xc0ff; - } - - for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) { - data->fan_div[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan)); - data->fan_min[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_MIN(chan)); - data->fan[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan)); - data->pwm[chan] = - 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >> - (4*chan)); - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_adm1031_init(void) -{ - return i2c_add_driver(&adm1031_driver); -} - -static void __exit sensors_adm1031_exit(void) -{ - i2c_del_driver(&adm1031_driver); -} - -MODULE_AUTHOR("Alexandre d'Alton "); -MODULE_DESCRIPTION("ADM1031/ADM1030 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_adm1031_init); -module_exit(sensors_adm1031_exit); diff --git a/drivers/i2c/chips/adm9240.c b/drivers/i2c/chips/adm9240.c deleted file mode 100644 index 5c68e9c311a..00000000000 --- a/drivers/i2c/chips/adm9240.c +++ /dev/null @@ -1,791 +0,0 @@ -/* - * adm9240.c Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * - * Copyright (C) 1999 Frodo Looijaard - * Philip Edelbrock - * Copyright (C) 2003 Michiel Rook - * Copyright (C) 2005 Grant Coady with valuable - * guidance from Jean Delvare - * - * Driver supports Analog Devices ADM9240 - * Dallas Semiconductor DS1780 - * National Semiconductor LM81 - * - * ADM9240 is the reference, DS1780 and LM81 are register compatibles - * - * Voltage Six inputs are scaled by chip, VID also reported - * Temperature Chip temperature to 0.5'C, maximum and max_hysteris - * Fans 2 fans, low speed alarm, automatic fan clock divider - * Alarms 16-bit map of active alarms - * Analog Out 0..1250 mV output - * - * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear' - * - * Test hardware: Intel SE440BX-2 desktop motherboard --Grant - * - * LM81 extended temp reading not implemented - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, - I2C_CLIENT_END }; - -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_3(adm9240, ds1780, lm81); - -/* ADM9240 registers */ -#define ADM9240_REG_MAN_ID 0x3e -#define ADM9240_REG_DIE_REV 0x3f -#define ADM9240_REG_CONFIG 0x40 - -#define ADM9240_REG_IN(nr) (0x20 + (nr)) /* 0..5 */ -#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define ADM9240_REG_FAN(nr) (0x28 + (nr)) /* 0..1 */ -#define ADM9240_REG_FAN_MIN(nr) (0x3b + (nr)) -#define ADM9240_REG_INT(nr) (0x41 + (nr)) -#define ADM9240_REG_INT_MASK(nr) (0x43 + (nr)) -#define ADM9240_REG_TEMP 0x27 -#define ADM9240_REG_TEMP_HIGH 0x39 -#define ADM9240_REG_TEMP_HYST 0x3a -#define ADM9240_REG_ANALOG_OUT 0x19 -#define ADM9240_REG_CHASSIS_CLEAR 0x46 -#define ADM9240_REG_VID_FAN_DIV 0x47 -#define ADM9240_REG_I2C_ADDR 0x48 -#define ADM9240_REG_VID4 0x49 -#define ADM9240_REG_TEMP_CONF 0x4b - -/* generalised scaling with integer rounding */ -static inline int SCALE(long val, int mul, int div) -{ - if (val < 0) - return (val * mul - div / 2) / div; - else - return (val * mul + div / 2) / div; -} - -/* adm9240 internally scales voltage measurements */ -static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 }; - -static inline unsigned int IN_FROM_REG(u8 reg, int n) -{ - return SCALE(reg, nom_mv[n], 192); -} - -static inline u8 IN_TO_REG(unsigned long val, int n) -{ - return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255); -} - -/* temperature range: -40..125, 127 disables temperature alarm */ -static inline s8 TEMP_TO_REG(long val) -{ - return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127); -} - -/* two fans, each with low fan speed limit */ -static inline unsigned int FAN_FROM_REG(u8 reg, u8 div) -{ - if (!reg) /* error */ - return -1; - - if (reg == 255) - return 0; - - return SCALE(1350000, 1, reg * div); -} - -/* analog out 0..1250mV */ -static inline u8 AOUT_TO_REG(unsigned long val) -{ - return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255); -} - -static inline unsigned int AOUT_FROM_REG(u8 reg) -{ - return SCALE(reg, 1250, 255); -} - -static int adm9240_attach_adapter(struct i2c_adapter *adapter); -static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind); -static void adm9240_init_client(struct i2c_client *client); -static int adm9240_detach_client(struct i2c_client *client); -static struct adm9240_data *adm9240_update_device(struct device *dev); - -/* driver data */ -static struct i2c_driver adm9240_driver = { - .owner = THIS_MODULE, - .name = "adm9240", - .id = I2C_DRIVERID_ADM9240, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm9240_attach_adapter, - .detach_client = adm9240_detach_client, -}; - -/* per client data */ -struct adm9240_data { - enum chips type; - struct i2c_client client; - struct semaphore update_lock; - char valid; - unsigned long last_updated_measure; - unsigned long last_updated_config; - - u8 in[6]; /* ro in0_input */ - u8 in_max[6]; /* rw in0_max */ - u8 in_min[6]; /* rw in0_min */ - u8 fan[2]; /* ro fan1_input */ - u8 fan_min[2]; /* rw fan1_min */ - u8 fan_div[2]; /* rw fan1_div, read-only accessor */ - s16 temp; /* ro temp1_input, 9-bit sign-extended */ - s8 temp_high; /* rw temp1_max */ - s8 temp_hyst; /* rw temp1_max_hyst */ - u16 alarms; /* ro alarms */ - u8 aout; /* rw aout_output */ - u8 vid; /* ro vid */ - u8 vrm; /* -- vrm set on startup, no accessor */ -}; - -/* i2c byte read/write interface */ -static int adm9240_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/*** sysfs accessors ***/ - -/* temperature */ -#define show_temp(value, scale) \ -static ssize_t show_##value(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct adm9240_data *data = adm9240_update_device(dev); \ - return sprintf(buf, "%d\n", data->value * scale); \ -} -show_temp(temp_high, 1000); -show_temp(temp_hyst, 1000); -show_temp(temp, 500); /* 0.5'C per bit */ - -#define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm9240_data *data = adm9240_update_device(dev); \ - long temp = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(temp); \ - adm9240_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} - -set_temp(temp_high, ADM9240_REG_TEMP_HIGH); -set_temp(temp_hyst, ADM9240_REG_TEMP_HYST); - -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, - show_temp_high, set_temp_high); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, - show_temp_hyst, set_temp_hyst); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); - -/* voltage */ -static ssize_t show_in(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr)); -} - -static ssize_t show_in_min(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr)); -} - -static ssize_t show_in_max(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr)); -} - -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val, nr); - adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val, nr); - adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]); - up(&data->update_lock); - return count; -} - -#define show_in_offset(offset) \ -static ssize_t show_in##offset(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \ -static ssize_t show_in##offset##_min(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t \ -set_in##offset##_min(struct device *dev, \ - struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t \ -set_in##offset##_max(struct device *dev, \ - struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); - -show_in_offset(0); -show_in_offset(1); -show_in_offset(2); -show_in_offset(3); -show_in_offset(4); -show_in_offset(5); - -/* fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - 1 << data->fan_div[nr])); -} - -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], - 1 << data->fan_div[nr])); -} - -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", 1 << data->fan_div[nr]); -} - -/* write new fan div, callers must hold data->update_lock */ -static void adm9240_write_fan_div(struct i2c_client *client, int nr, - u8 fan_div) -{ - u8 reg, old, shift = (nr + 2) * 2; - - reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); - old = (reg >> shift) & 3; - reg &= ~(3 << shift); - reg |= (fan_div << shift); - adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg); - dev_dbg(&client->dev, "fan%d clock divider changed from %u " - "to %u\n", nr + 1, 1 << old, 1 << fan_div); -} - -/* - * set fan speed low limit: - * - * - value is zero: disable fan speed low limit alarm - * - * - value is below fan speed measurement range: enable fan speed low - * limit alarm to be asserted while fan speed too slow to measure - * - * - otherwise: select fan clock divider to suit fan speed low limit, - * measurement code may adjust registers to ensure fan speed reading - */ -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - u8 new_div; - - down(&data->update_lock); - - if (!val) { - data->fan_min[nr] = 255; - new_div = data->fan_div[nr]; - - dev_dbg(&client->dev, "fan%u low limit set disabled\n", - nr + 1); - - } else if (val < 1350000 / (8 * 254)) { - new_div = 3; - data->fan_min[nr] = 254; - - dev_dbg(&client->dev, "fan%u low limit set minimum %u\n", - nr + 1, FAN_FROM_REG(254, 1 << new_div)); - - } else { - unsigned int new_min = 1350000 / val; - - new_div = 0; - while (new_min > 192 && new_div < 3) { - new_div++; - new_min /= 2; - } - if (!new_min) /* keep > 0 */ - new_min++; - - data->fan_min[nr] = new_min; - - dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n", - nr + 1, FAN_FROM_REG(new_min, 1 << new_div)); - } - - if (new_div != data->fan_div[nr]) { - data->fan_div[nr] = new_div; - adm9240_write_fan_div(client, nr, new_div); - } - adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr), - data->fan_min[nr]); - - up(&data->update_lock); - return count; -} - -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ -return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ -return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan_##offset, NULL); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ - show_fan_##offset##_div, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); - -show_fan_offset(1); -show_fan_offset(2); - -/* alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* vid */ -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -/* analog output */ -static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct adm9240_data *data = adm9240_update_device(dev); - return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); -} - -static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->aout = AOUT_TO_REG(val); - adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout); - up(&data->update_lock); - return count; -} -static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); - -/* chassis_clear */ -static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - unsigned long val = simple_strtol(buf, NULL, 10); - - if (val == 1) { - adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); - dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); - } - return count; -} -static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear); - - -/*** sensor chip detect and driver install ***/ - -static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct adm9240_data *data; - int err = 0; - const char *name = ""; - u8 man_id, die_rev; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct adm9240_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm9240_driver; - new_client->flags = 0; - - if (kind == 0) { - kind = adm9240; - } - - if (kind < 0) { - - /* verify chip: reg address should match i2c address */ - if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR) - != address) { - dev_err(&adapter->dev, "detect fail: address match, " - "0x%02x\n", address); - goto exit_free; - } - - /* check known chip manufacturer */ - man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID); - - if (man_id == 0x23) { - kind = adm9240; - } else if (man_id == 0xda) { - kind = ds1780; - } else if (man_id == 0x01) { - kind = lm81; - } else { - dev_err(&adapter->dev, "detect fail: unknown manuf, " - "0x%02x\n", man_id); - goto exit_free; - } - - /* successful detect, print chip info */ - die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV); - dev_info(&adapter->dev, "found %s revision %u\n", - man_id == 0x23 ? "ADM9240" : - man_id == 0xda ? "DS1780" : "LM81", die_rev); - } - - /* either forced or detected chip kind */ - if (kind == adm9240) { - name = "adm9240"; - } else if (kind == ds1780) { - name = "ds1780"; - } else if (kind == lm81) { - name = "lm81"; - } - - /* fill in the remaining client fields and attach */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->type = kind; - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - adm9240_init_client(new_client); - - /* populate sysfs filesystem */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_aout_output); - device_create_file(&new_client->dev, &dev_attr_chassis_clear); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - - return 0; -exit_free: - kfree(new_client); -exit: - return err; -} - -static int adm9240_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, adm9240_detect); -} - -static int adm9240_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - -static void adm9240_init_client(struct i2c_client *client) -{ - struct adm9240_data *data = i2c_get_clientdata(client); - u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG); - u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3; - - data->vrm = i2c_which_vrm(); /* need this to report vid as mV */ - - dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10, - data->vrm % 10); - - if (conf & 1) { /* measurement cycle running: report state */ - - dev_info(&client->dev, "status: config 0x%02x mode %u\n", - conf, mode); - - } else { /* cold start: open limits before starting chip */ - int i; - - for (i = 0; i < 6; i++) - { - adm9240_write_value(client, - ADM9240_REG_IN_MIN(i), 0); - adm9240_write_value(client, - ADM9240_REG_IN_MAX(i), 255); - } - adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255); - adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255); - adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127); - adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127); - - /* start measurement cycle */ - adm9240_write_value(client, ADM9240_REG_CONFIG, 1); - - dev_info(&client->dev, "cold start: config was 0x%02x " - "mode %u\n", conf, mode); - } -} - -static struct adm9240_data *adm9240_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adm9240_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - /* minimum measurement cycle: 1.75 seconds */ - if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) - || !data->valid) { - - for (i = 0; i < 6; i++) /* read voltages */ - { - data->in[i] = adm9240_read_value(client, - ADM9240_REG_IN(i)); - } - data->alarms = adm9240_read_value(client, - ADM9240_REG_INT(0)) | - adm9240_read_value(client, - ADM9240_REG_INT(1)) << 8; - - /* read temperature: assume temperature changes less than - * 0.5'C per two measurement cycles thus ignore possible - * but unlikely aliasing error on lsb reading. --Grant */ - data->temp = ((adm9240_read_value(client, - ADM9240_REG_TEMP) << 8) | - adm9240_read_value(client, - ADM9240_REG_TEMP_CONF)) / 128; - - for (i = 0; i < 2; i++) /* read fans */ - { - data->fan[i] = adm9240_read_value(client, - ADM9240_REG_FAN(i)); - - /* adjust fan clock divider on overflow */ - if (data->valid && data->fan[i] == 255 && - data->fan_div[i] < 3) { - - adm9240_write_fan_div(client, i, - ++data->fan_div[i]); - - /* adjust fan_min if active, but not to 0 */ - if (data->fan_min[i] < 255 && - data->fan_min[i] >= 2) - data->fan_min[i] /= 2; - } - } - data->last_updated_measure = jiffies; - } - - /* minimum config reading cycle: 300 seconds */ - if (time_after(jiffies, data->last_updated_config + (HZ * 300)) - || !data->valid) { - - for (i = 0; i < 6; i++) - { - data->in_min[i] = adm9240_read_value(client, - ADM9240_REG_IN_MIN(i)); - data->in_max[i] = adm9240_read_value(client, - ADM9240_REG_IN_MAX(i)); - } - for (i = 0; i < 2; i++) - { - data->fan_min[i] = adm9240_read_value(client, - ADM9240_REG_FAN_MIN(i)); - } - data->temp_high = adm9240_read_value(client, - ADM9240_REG_TEMP_HIGH); - data->temp_hyst = adm9240_read_value(client, - ADM9240_REG_TEMP_HYST); - - /* read fan divs and 5-bit VID */ - i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 3; - data->fan_div[1] = (i >> 6) & 3; - data->vid = i & 0x0f; - data->vid |= (adm9240_read_value(client, - ADM9240_REG_VID4) & 1) << 4; - /* read analog out */ - data->aout = adm9240_read_value(client, - ADM9240_REG_ANALOG_OUT); - - data->last_updated_config = jiffies; - data->valid = 1; - } - up(&data->update_lock); - return data; -} - -static int __init sensors_adm9240_init(void) -{ - return i2c_add_driver(&adm9240_driver); -} - -static void __exit sensors_adm9240_exit(void) -{ - i2c_del_driver(&adm9240_driver); -} - -MODULE_AUTHOR("Michiel Rook , " - "Grant Coady and others"); -MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_adm9240_init); -module_exit(sensors_adm9240_exit); - diff --git a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c deleted file mode 100644 index 70d996d6fe0..00000000000 --- a/drivers/i2c/chips/asb100.c +++ /dev/null @@ -1,1065 +0,0 @@ -/* - asb100.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (C) 2004 Mark M. Hoffman - - (derived from w83781d.c) - - Copyright (C) 1998 - 2003 Frodo Looijaard , - Philip Edelbrock , and - Mark Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This driver supports the hardware sensor chips: Asus ASB100 and - ASB100-A "BACH". - - ASB100-A supports pwm1, while plain ASB100 does not. There is no known - way for the driver to tell which one is there. - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - asb100 7 3 1 4 0x31 0x0694 yes no -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "lm75.h" - -/* - HISTORY: - 2003-12-29 1.0.0 Ported from lm_sensors project for kernel 2.6 -*/ -#define ASB100_VERSION "1.0.0" - -/* I2C addresses to scan */ -static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END }; - -/* ISA addresses to scan (none) */ -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(asb100); -I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " - "{bus, clientaddr, subclientaddr1, subclientaddr2}"); - -/* Voltage IN registers 0-6 */ -#define ASB100_REG_IN(nr) (0x20 + (nr)) -#define ASB100_REG_IN_MAX(nr) (0x2b + (nr * 2)) -#define ASB100_REG_IN_MIN(nr) (0x2c + (nr * 2)) - -/* FAN IN registers 1-3 */ -#define ASB100_REG_FAN(nr) (0x28 + (nr)) -#define ASB100_REG_FAN_MIN(nr) (0x3b + (nr)) - -/* TEMPERATURE registers 1-4 */ -static const u16 asb100_reg_temp[] = {0, 0x27, 0x150, 0x250, 0x17}; -static const u16 asb100_reg_temp_max[] = {0, 0x39, 0x155, 0x255, 0x18}; -static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19}; - -#define ASB100_REG_TEMP(nr) (asb100_reg_temp[nr]) -#define ASB100_REG_TEMP_MAX(nr) (asb100_reg_temp_max[nr]) -#define ASB100_REG_TEMP_HYST(nr) (asb100_reg_temp_hyst[nr]) - -#define ASB100_REG_TEMP2_CONFIG 0x0152 -#define ASB100_REG_TEMP3_CONFIG 0x0252 - - -#define ASB100_REG_CONFIG 0x40 -#define ASB100_REG_ALARM1 0x41 -#define ASB100_REG_ALARM2 0x42 -#define ASB100_REG_SMIM1 0x43 -#define ASB100_REG_SMIM2 0x44 -#define ASB100_REG_VID_FANDIV 0x47 -#define ASB100_REG_I2C_ADDR 0x48 -#define ASB100_REG_CHIPID 0x49 -#define ASB100_REG_I2C_SUBADDR 0x4a -#define ASB100_REG_PIN 0x4b -#define ASB100_REG_IRQ 0x4c -#define ASB100_REG_BANK 0x4e -#define ASB100_REG_CHIPMAN 0x4f - -#define ASB100_REG_WCHIPID 0x58 - -/* bit 7 -> enable, bits 0-3 -> duty cycle */ -#define ASB100_REG_PWM1 0x59 - -/* CONVERSIONS - Rounding and limit checking is only done on the TO_REG variants. */ - -/* These constants are a guess, consistent w/ w83781d */ -#define ASB100_IN_MIN ( 0) -#define ASB100_IN_MAX (4080) - -/* IN: 1/1000 V (0V to 4.08V) - REG: 16mV/bit */ -static u8 IN_TO_REG(unsigned val) -{ - unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX); - return (nval + 8) / 16; -} - -static unsigned IN_FROM_REG(u8 reg) -{ - return reg * 16; -} - -static u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == -1) - return 0; - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); -} - -static int FAN_FROM_REG(u8 val, int div) -{ - return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); -} - -/* These constants are a guess, consistent w/ w83781d */ -#define ASB100_TEMP_MIN (-128000) -#define ASB100_TEMP_MAX ( 127000) - -/* TEMP: 0.001C/bit (-128C to +127C) - REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX); - ntemp += (ntemp<0 ? -500 : 500); - return (u8)(ntemp / 1000); -} - -static int TEMP_FROM_REG(u8 reg) -{ - return (s8)reg * 1000; -} - -/* PWM: 0 - 255 per sensors documentation - REG: (6.25% duty cycle per bit) */ -static u8 ASB100_PWM_TO_REG(int pwm) -{ - pwm = SENSORS_LIMIT(pwm, 0, 255); - return (u8)(pwm / 16); -} - -static int ASB100_PWM_FROM_REG(u8 reg) -{ - return reg * 16; -} - -#define DIV_FROM_REG(val) (1 << (val)) - -/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) - REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ -static u8 DIV_TO_REG(long val) -{ - return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; -} - -/* For each registered client, we need to keep some data in memory. That - data is pointed to by client->data. The structure itself is - dynamically allocated, at the same time the client itself is allocated. */ -struct asb100_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - unsigned long last_updated; /* In jiffies */ - - /* array of 2 pointers to subclients */ - struct i2c_client *lm75[2]; - - char valid; /* !=0 if following fields are valid */ - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u16 temp[4]; /* Register value (0 and 3 are u8 only) */ - u16 temp_max[4]; /* Register value (0 and 3 are u8 only) */ - u16 temp_hyst[4]; /* Register value (0 and 3 are u8 only) */ - u8 fan_div[3]; /* Register encoding, right justified */ - u8 pwm; /* Register encoding */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u8 vrm; -}; - -static int asb100_read_value(struct i2c_client *client, u16 reg); -static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val); - -static int asb100_attach_adapter(struct i2c_adapter *adapter); -static int asb100_detect(struct i2c_adapter *adapter, int address, int kind); -static int asb100_detach_client(struct i2c_client *client); -static struct asb100_data *asb100_update_device(struct device *dev); -static void asb100_init_client(struct i2c_client *client); - -static struct i2c_driver asb100_driver = { - .owner = THIS_MODULE, - .name = "asb100", - .id = I2C_DRIVERID_ASB100, - .flags = I2C_DF_NOTIFY, - .attach_adapter = asb100_attach_adapter, - .detach_client = asb100_detach_client, -}; - -/* 7 Voltages */ -#define show_in_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct asb100_data *data = asb100_update_device(dev); \ - return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \ -} - -show_in_reg(in) -show_in_reg(in_min) -show_in_reg(in_max) - -#define set_in_reg(REG, reg) \ -static ssize_t set_in_##reg(struct device *dev, const char *buf, \ - size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct asb100_data *data = i2c_get_clientdata(client); \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_##reg[nr] = IN_TO_REG(val); \ - asb100_write_value(client, ASB100_REG_IN_##REG(nr), \ - data->in_##reg[nr]); \ - up(&data->update_lock); \ - return count; \ -} - -set_in_reg(MIN, min) -set_in_reg(MAX, max) - -#define sysfs_in(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset, NULL); \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); - -sysfs_in(0); -sysfs_in(1); -sysfs_in(2); -sysfs_in(3); -sysfs_in(4); -sysfs_in(5); -sysfs_in(6); - -#define device_create_file_in(client, offset) do { \ - device_create_file(&client->dev, &dev_attr_in##offset##_input); \ - device_create_file(&client->dev, &dev_attr_in##offset##_min); \ - device_create_file(&client->dev, &dev_attr_in##offset##_max); \ -} while (0) - -/* 3 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr]))); -} - -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr]))); -} - -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); -} - -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - unsigned long min; - unsigned long val = simple_strtoul(buf, NULL, 10); - int reg; - - down(&data->update_lock); - - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - data->fan_div[nr] = DIV_TO_REG(val); - - switch(nr) { - case 0: /* fan 1 */ - reg = asb100_read_value(client, ASB100_REG_VID_FANDIV); - reg = (reg & 0xcf) | (data->fan_div[0] << 4); - asb100_write_value(client, ASB100_REG_VID_FANDIV, reg); - break; - - case 1: /* fan 2 */ - reg = asb100_read_value(client, ASB100_REG_VID_FANDIV); - reg = (reg & 0x3f) | (data->fan_div[1] << 6); - asb100_write_value(client, ASB100_REG_VID_FANDIV, reg); - break; - - case 2: /* fan 3 */ - reg = asb100_read_value(client, ASB100_REG_PIN); - reg = (reg & 0x3f) | (data->fan_div[2] << 6); - asb100_write_value(client, ASB100_REG_PIN, reg); - break; - } - - data->fan_min[nr] = - FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - asb100_write_value(client, ASB100_REG_FAN_MIN(nr), data->fan_min[nr]); - - up(&data->update_lock); - - return count; -} - -#define sysfs_fan(offset) \ -static ssize_t show_fan##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan##offset, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan##offset##_min, set_fan##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan##offset##_div, set_fan##offset##_div); - -sysfs_fan(1); -sysfs_fan(2); -sysfs_fan(3); - -#define device_create_file_fan(client, offset) do { \ - device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ -} while (0) - -/* 4 Temp. Sensors */ -static int sprintf_temp_from_reg(u16 reg, char *buf, int nr) -{ - int ret = 0; - - switch (nr) { - case 1: case 2: - ret = sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(reg)); - break; - case 0: case 3: default: - ret = sprintf(buf, "%d\n", TEMP_FROM_REG(reg)); - break; - } - return ret; -} - -#define show_temp_reg(reg) \ -static ssize_t show_##reg(struct device *dev, char *buf, int nr) \ -{ \ - struct asb100_data *data = asb100_update_device(dev); \ - return sprintf_temp_from_reg(data->reg[nr], buf, nr); \ -} - -show_temp_reg(temp); -show_temp_reg(temp_max); -show_temp_reg(temp_hyst); - -#define set_temp_reg(REG, reg) \ -static ssize_t set_##reg(struct device *dev, const char *buf, \ - size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct asb100_data *data = i2c_get_clientdata(client); \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - switch (nr) { \ - case 1: case 2: \ - data->reg[nr] = LM75_TEMP_TO_REG(val); \ - break; \ - case 0: case 3: default: \ - data->reg[nr] = TEMP_TO_REG(val); \ - break; \ - } \ - asb100_write_value(client, ASB100_REG_TEMP_##REG(nr+1), \ - data->reg[nr]); \ - up(&data->update_lock); \ - return count; \ -} - -set_temp_reg(MAX, temp_max); -set_temp_reg(HYST, temp_hyst); - -#define sysfs_temp(num) \ -static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL); \ -static ssize_t show_temp_max##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, num-1); \ -} \ -static ssize_t set_temp_max##num(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_temp_max(dev, buf, count, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \ - show_temp_max##num, set_temp_max##num); \ -static ssize_t show_temp_hyst##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_hyst(dev, buf, num-1); \ -} \ -static ssize_t set_temp_hyst##num(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_temp_hyst(dev, buf, count, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \ - show_temp_hyst##num, set_temp_hyst##num); - -sysfs_temp(1); -sysfs_temp(2); -sysfs_temp(3); -sysfs_temp(4); - -/* VID */ -#define device_create_file_temp(client, num) do { \ - device_create_file(&client->dev, &dev_attr_temp##num##_input); \ - device_create_file(&client->dev, &dev_attr_temp##num##_max); \ - device_create_file(&client->dev, &dev_attr_temp##num##_max_hyst); \ -} while (0) - -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); -} - -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid) - -/* VRM */ -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", data->vrm); -} - -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - data->vrm = val; - return count; -} - -/* Alarms */ -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -#define device_create_file_alarms(client) \ -device_create_file(&client->dev, &dev_attr_alarms) - -/* 1 PWM */ -static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", ASB100_PWM_FROM_REG(data->pwm & 0x0f)); -} - -static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->pwm &= 0x80; /* keep the enable bit */ - data->pwm |= (0x0f & ASB100_PWM_TO_REG(val)); - asb100_write_value(client, ASB100_REG_PWM1, data->pwm); - up(&data->update_lock); - return count; -} - -static ssize_t show_pwm_enable1(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct asb100_data *data = asb100_update_device(dev); - return sprintf(buf, "%d\n", (data->pwm & 0x80) ? 1 : 0); -} - -static ssize_t set_pwm_enable1(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->pwm &= 0x0f; /* keep the duty cycle bits */ - data->pwm |= (val ? 0x80 : 0x00); - asb100_write_value(client, ASB100_REG_PWM1, data->pwm); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1); -static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, - show_pwm_enable1, set_pwm_enable1); -#define device_create_file_pwm1(client) do { \ - device_create_file(&new_client->dev, &dev_attr_pwm1); \ - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); \ -} while (0) - -/* This function is called when: - asb100_driver is inserted (when this module is loaded), for each - available adapter - when a new adapter is inserted (and asb100_driver is still present) - */ -static int asb100_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, asb100_detect); -} - -static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, - int kind, struct i2c_client *new_client) -{ - int i, id, err; - struct asb100_data *data = i2c_get_clientdata(new_client); - - data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[0])) { - err = -ENOMEM; - goto ERROR_SC_0; - } - memset(data->lm75[0], 0x00, sizeof(struct i2c_client)); - - data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[1])) { - err = -ENOMEM; - goto ERROR_SC_1; - } - memset(data->lm75[1], 0x00, sizeof(struct i2c_client)); - - id = i2c_adapter_id(adapter); - - if (force_subclients[0] == id && force_subclients[1] == address) { - for (i = 2; i <= 3; i++) { - if (force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - dev_err(&new_client->dev, "invalid subclient " - "address %d; must be 0x48-0x4f\n", - force_subclients[i]); - err = -ENODEV; - goto ERROR_SC_2; - } - } - asb100_write_value(new_client, ASB100_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) <<4)); - data->lm75[0]->addr = force_subclients[2]; - data->lm75[1]->addr = force_subclients[3]; - } else { - int val = asb100_read_value(new_client, ASB100_REG_I2C_SUBADDR); - data->lm75[0]->addr = 0x48 + (val & 0x07); - data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07); - } - - if(data->lm75[0]->addr == data->lm75[1]->addr) { - dev_err(&new_client->dev, "duplicate addresses 0x%x " - "for subclients\n", data->lm75[0]->addr); - err = -ENODEV; - goto ERROR_SC_2; - } - - for (i = 0; i <= 1; i++) { - i2c_set_clientdata(data->lm75[i], NULL); - data->lm75[i]->adapter = adapter; - data->lm75[i]->driver = &asb100_driver; - data->lm75[i]->flags = 0; - strlcpy(data->lm75[i]->name, "asb100 subclient", I2C_NAME_SIZE); - } - - if ((err = i2c_attach_client(data->lm75[0]))) { - dev_err(&new_client->dev, "subclient %d registration " - "at address 0x%x failed.\n", i, data->lm75[0]->addr); - goto ERROR_SC_2; - } - - if ((err = i2c_attach_client(data->lm75[1]))) { - dev_err(&new_client->dev, "subclient %d registration " - "at address 0x%x failed.\n", i, data->lm75[1]->addr); - goto ERROR_SC_3; - } - - return 0; - -/* Undo inits in case of errors */ -ERROR_SC_3: - i2c_detach_client(data->lm75[0]); -ERROR_SC_2: - kfree(data->lm75[1]); -ERROR_SC_1: - kfree(data->lm75[0]); -ERROR_SC_0: - return err; -} - -static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int err; - struct i2c_client *new_client; - struct asb100_data *data; - - /* asb100 is SMBus only */ - if (i2c_is_isa_adapter(adapter)) { - pr_debug("asb100.o: detect failed, " - "cannot attach to legacy adapter!\n"); - err = -ENODEV; - goto ERROR0; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - pr_debug("asb100.o: detect failed, " - "smbus byte data not supported!\n"); - err = -ENODEV; - goto ERROR0; - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access asb100_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct asb100_data), GFP_KERNEL))) { - pr_debug("asb100.o: detect failed, kmalloc failed!\n"); - err = -ENOMEM; - goto ERROR0; - } - memset(data, 0, sizeof(struct asb100_data)); - - new_client = &data->client; - init_MUTEX(&data->lock); - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &asb100_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - /* The chip may be stuck in some other bank than bank 0. This may - make reading other information impossible. Specify a force=... or - force_*=... parameter, and the chip will be reset to the right - bank. */ - if (kind < 0) { - - int val1 = asb100_read_value(new_client, ASB100_REG_BANK); - int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); - - /* If we're in bank 0 */ - if ( (!(val1 & 0x07)) && - /* Check for ASB100 ID (low byte) */ - ( ((!(val1 & 0x80)) && (val2 != 0x94)) || - /* Check for ASB100 ID (high byte ) */ - ((val1 & 0x80) && (val2 != 0x06)) ) ) { - pr_debug("asb100.o: detect failed, " - "bad chip id 0x%02x!\n", val2); - err = -ENODEV; - goto ERROR1; - } - - } /* kind < 0 */ - - /* We have either had a force parameter, or we have already detected - Winbond. Put it now into bank 0 and Vendor ID High Byte */ - asb100_write_value(new_client, ASB100_REG_BANK, - (asb100_read_value(new_client, ASB100_REG_BANK) & 0x78) | 0x80); - - /* Determine the chip type. */ - if (kind <= 0) { - int val1 = asb100_read_value(new_client, ASB100_REG_WCHIPID); - int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); - - if ((val1 == 0x31) && (val2 == 0x06)) - kind = asb100; - else { - if (kind == 0) - dev_warn(&new_client->dev, "ignoring " - "'force' parameter for unknown chip " - "at adapter %d, address 0x%02x.\n", - i2c_adapter_id(adapter), address); - err = -ENODEV; - goto ERROR1; - } - } - - /* Fill in remaining client fields and put it into the global list */ - strlcpy(new_client->name, "asb100", I2C_NAME_SIZE); - data->type = kind; - - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Attach secondary lm75 clients */ - if ((err = asb100_detect_subclients(adapter, address, kind, - new_client))) - goto ERROR2; - - /* Initialize the chip */ - asb100_init_client(new_client); - - /* A few vars need to be filled upon startup */ - data->fan_min[0] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(0)); - data->fan_min[1] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(1)); - data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2)); - - /* Register sysfs hooks */ - device_create_file_in(new_client, 0); - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - device_create_file_in(new_client, 4); - device_create_file_in(new_client, 5); - device_create_file_in(new_client, 6); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - device_create_file_temp(new_client, 3); - device_create_file_temp(new_client, 4); - - device_create_file_vid(new_client); - device_create_file_vrm(new_client); - - device_create_file_alarms(new_client); - - device_create_file_pwm1(new_client); - - return 0; - -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); -ERROR0: - return err; -} - -static int asb100_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "client deregistration failed; " - "client not detached.\n"); - return err; - } - - if (i2c_get_clientdata(client)==NULL) { - /* subclients */ - kfree(client); - } else { - /* main client */ - kfree(i2c_get_clientdata(client)); - } - - return 0; -} - -/* The SMBus locks itself, usually, but nothing may access the chip between - bank switches. */ -static int asb100_read_value(struct i2c_client *client, u16 reg) -{ - struct asb100_data *data = i2c_get_clientdata(client); - struct i2c_client *cl; - int res, bank; - - down(&data->lock); - - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); - - if (bank == 0 || bank > 2) { - res = i2c_smbus_read_byte_data(client, reg & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x50: /* TEMP */ - res = swab16(i2c_smbus_read_word_data (cl, 0)); - break; - case 0x52: /* CONFIG */ - res = i2c_smbus_read_byte_data(cl, 1); - break; - case 0x53: /* HYST */ - res = swab16(i2c_smbus_read_word_data (cl, 2)); - break; - case 0x55: /* MAX */ - default: - res = swab16(i2c_smbus_read_word_data (cl, 3)); - break; - } - } - - if (bank > 2) - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); - - up(&data->lock); - - return res; -} - -static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - struct asb100_data *data = i2c_get_clientdata(client); - struct i2c_client *cl; - int bank; - - down(&data->lock); - - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); - - if (bank == 0 || bank > 2) { - i2c_smbus_write_byte_data(client, reg & 0xff, value & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x52: /* CONFIG */ - i2c_smbus_write_byte_data(cl, 1, value & 0xff); - break; - case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, swab16(value)); - break; - case 0x55: /* MAX */ - i2c_smbus_write_word_data(cl, 3, swab16(value)); - break; - } - } - - if (bank > 2) - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); - - up(&data->lock); -} - -static void asb100_init_client(struct i2c_client *client) -{ - struct asb100_data *data = i2c_get_clientdata(client); - int vid = 0; - - vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f; - vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4; - data->vrm = i2c_which_vrm(); - vid = vid_from_reg(vid, data->vrm); - - /* Start monitoring */ - asb100_write_value(client, ASB100_REG_CONFIG, - (asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01); -} - -static struct asb100_data *asb100_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct asb100_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - dev_dbg(&client->dev, "starting device update...\n"); - - /* 7 voltage inputs */ - for (i = 0; i < 7; i++) { - data->in[i] = asb100_read_value(client, - ASB100_REG_IN(i)); - data->in_min[i] = asb100_read_value(client, - ASB100_REG_IN_MIN(i)); - data->in_max[i] = asb100_read_value(client, - ASB100_REG_IN_MAX(i)); - } - - /* 3 fan inputs */ - for (i = 0; i < 3; i++) { - data->fan[i] = asb100_read_value(client, - ASB100_REG_FAN(i)); - data->fan_min[i] = asb100_read_value(client, - ASB100_REG_FAN_MIN(i)); - } - - /* 4 temperature inputs */ - for (i = 1; i <= 4; i++) { - data->temp[i-1] = asb100_read_value(client, - ASB100_REG_TEMP(i)); - data->temp_max[i-1] = asb100_read_value(client, - ASB100_REG_TEMP_MAX(i)); - data->temp_hyst[i-1] = asb100_read_value(client, - ASB100_REG_TEMP_HYST(i)); - } - - /* VID and fan divisors */ - i = asb100_read_value(client, ASB100_REG_VID_FANDIV); - data->vid = i & 0x0f; - data->vid |= (asb100_read_value(client, - ASB100_REG_CHIPID) & 0x01) << 4; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->fan_div[2] = (asb100_read_value(client, - ASB100_REG_PIN) >> 6) & 0x03; - - /* PWM */ - data->pwm = asb100_read_value(client, ASB100_REG_PWM1); - - /* alarms */ - data->alarms = asb100_read_value(client, ASB100_REG_ALARM1) + - (asb100_read_value(client, ASB100_REG_ALARM2) << 8); - - data->last_updated = jiffies; - data->valid = 1; - - dev_dbg(&client->dev, "... device update complete\n"); - } - - up(&data->update_lock); - - return data; -} - -static int __init asb100_init(void) -{ - return i2c_add_driver(&asb100_driver); -} - -static void __exit asb100_exit(void) -{ - i2c_del_driver(&asb100_driver); -} - -MODULE_AUTHOR("Mark M. Hoffman "); -MODULE_DESCRIPTION("ASB100 Bach driver"); -MODULE_LICENSE("GPL"); - -module_init(asb100_init); -module_exit(asb100_exit); - diff --git a/drivers/i2c/chips/atxp1.c b/drivers/i2c/chips/atxp1.c deleted file mode 100644 index 0bcf82b4c07..00000000000 --- a/drivers/i2c/chips/atxp1.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - atxp1.c - kernel module for setting CPU VID and general purpose - I/Os using the Attansic ATXP1 chip. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); -MODULE_VERSION("0.6.2"); -MODULE_AUTHOR("Sebastian Witt "); - -#define ATXP1_VID 0x00 -#define ATXP1_CVID 0x01 -#define ATXP1_GPIO1 0x06 -#define ATXP1_GPIO2 0x0a -#define ATXP1_VIDENA 0x20 -#define ATXP1_VIDMASK 0x1f -#define ATXP1_GPIO1MASK 0x0f - -static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -SENSORS_INSMOD_1(atxp1); - -static int atxp1_attach_adapter(struct i2c_adapter * adapter); -static int atxp1_detach_client(struct i2c_client * client); -static struct atxp1_data * atxp1_update_device(struct device *dev); -static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind); - -static struct i2c_driver atxp1_driver = { - .owner = THIS_MODULE, - .name = "atxp1", - .flags = I2C_DF_NOTIFY, - .attach_adapter = atxp1_attach_adapter, - .detach_client = atxp1_detach_client, -}; - -struct atxp1_data { - struct i2c_client client; - struct semaphore update_lock; - unsigned long last_updated; - u8 valid; - struct { - u8 vid; /* VID output register */ - u8 cpu_vid; /* VID input from CPU */ - u8 gpio1; /* General purpose I/O register 1 */ - u8 gpio2; /* General purpose I/O register 2 */ - } reg; - u8 vrm; /* Detected CPU VRM */ -}; - -static struct atxp1_data * atxp1_update_device(struct device *dev) -{ - struct i2c_client *client; - struct atxp1_data *data; - - client = to_i2c_client(dev); - data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ) || - (jiffies < data->last_updated) || - !data->valid) { - - /* Update local register data */ - data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID); - data->reg.cpu_vid = i2c_smbus_read_byte_data(client, ATXP1_CVID); - data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1); - data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2); - - data->valid = 1; - } - - up(&data->update_lock); - - return(data); -} - -/* sys file functions for cpu0_vid */ -static ssize_t atxp1_showvcore(struct device *dev, struct device_attribute *attr, char *buf) -{ - int size; - struct atxp1_data *data; - - data = atxp1_update_device(dev); - - size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, data->vrm)); - - return size; -} - -static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct atxp1_data *data; - struct i2c_client *client; - char vid; - char cvid; - unsigned int vcore; - - client = to_i2c_client(dev); - data = atxp1_update_device(dev); - - vcore = simple_strtoul(buf, NULL, 10); - vcore /= 25; - vcore *= 25; - - /* Calculate VID */ - vid = vid_to_reg(vcore, data->vrm); - - if (vid < 0) { - dev_err(dev, "VID calculation failed.\n"); - return -1; - } - - /* If output enabled, use control register value. Otherwise original CPU VID */ - if (data->reg.vid & ATXP1_VIDENA) - cvid = data->reg.vid & ATXP1_VIDMASK; - else - cvid = data->reg.cpu_vid; - - /* Nothing changed, aborting */ - if (vid == cvid) - return count; - - dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid); - - /* Write every 25 mV step to increase stability */ - if (cvid > vid) { - for (; cvid >= vid; cvid--) { - i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); - } - } - else { - for (; cvid <= vid; cvid++) { - i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); - } - } - - data->valid = 0; - - return count; -} - -/* CPU core reference voltage - unit: millivolt -*/ -static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore); - -/* sys file functions for GPIO1 */ -static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr, char *buf) -{ - int size; - struct atxp1_data *data; - - data = atxp1_update_device(dev); - - size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK); - - return size; -} - -static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *attr, const char*buf, size_t count) -{ - struct atxp1_data *data; - struct i2c_client *client; - unsigned int value; - - client = to_i2c_client(dev); - data = atxp1_update_device(dev); - - value = simple_strtoul(buf, NULL, 16); - - value &= ATXP1_GPIO1MASK; - - if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) { - dev_info(dev, "Writing 0x%x to GPIO1.\n", value); - - i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value); - - data->valid = 0; - } - - return count; -} - -/* GPIO1 data register - unit: Four bit as hex (e.g. 0x0f) -*/ -static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); - -/* sys file functions for GPIO2 */ -static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr, char *buf) -{ - int size; - struct atxp1_data *data; - - data = atxp1_update_device(dev); - - size = sprintf(buf, "0x%02x\n", data->reg.gpio2); - - return size; -} - -static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct atxp1_data *data; - struct i2c_client *client; - unsigned int value; - - client = to_i2c_client(dev); - data = atxp1_update_device(dev); - - value = simple_strtoul(buf, NULL, 16) & 0xff; - - if (value != data->reg.gpio2) { - dev_info(dev, "Writing 0x%x to GPIO1.\n", value); - - i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value); - - data->valid = 0; - } - - return count; -} - -/* GPIO2 data register - unit: Eight bit as hex (e.g. 0xff) -*/ -static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); - - -static int atxp1_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, &atxp1_detect); -}; - -static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client * new_client; - struct atxp1_data * data; - int err = 0; - u8 temp; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - - memset(data, 0, sizeof(struct atxp1_data)); - new_client = &data->client; - i2c_set_clientdata(new_client, data); - - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &atxp1_driver; - new_client->flags = 0; - - /* Detect ATXP1, checking if vendor ID registers are all zero */ - if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) && - (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) && - (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) && - (i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) { - - /* No vendor ID, now checking if registers 0x10,0x11 (non-existent) - * showing the same as register 0x00 */ - temp = i2c_smbus_read_byte_data(new_client, 0x00); - - if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) && - (i2c_smbus_read_byte_data(new_client, 0x11) == temp) )) - goto exit_free; - } - - /* Get VRM */ - data->vrm = i2c_which_vrm(); - - if ((data->vrm != 90) && (data->vrm != 91)) { - dev_err(&new_client->dev, "Not supporting VRM %d.%d\n", - data->vrm / 10, data->vrm % 10); - goto exit_free; - } - - strncpy(new_client->name, "atxp1", I2C_NAME_SIZE); - - data->valid = 0; - - init_MUTEX(&data->update_lock); - - err = i2c_attach_client(new_client); - - if (err) - { - dev_err(&new_client->dev, "Attach client error.\n"); - goto exit_free; - } - - device_create_file(&new_client->dev, &dev_attr_gpio1); - device_create_file(&new_client->dev, &dev_attr_gpio2); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - - dev_info(&new_client->dev, "Using VRM: %d.%d\n", - data->vrm / 10, data->vrm % 10); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -}; - -static int atxp1_detach_client(struct i2c_client * client) -{ - int err; - - err = i2c_detach_client(client); - - if (err) - dev_err(&client->dev, "Failed to detach client.\n"); - else - kfree(i2c_get_clientdata(client)); - - return err; -}; - -static int __init atxp1_init(void) -{ - return i2c_add_driver(&atxp1_driver); -}; - -static void __exit atxp1_exit(void) -{ - i2c_del_driver(&atxp1_driver); -}; - -module_init(atxp1_init); -module_exit(atxp1_exit); diff --git a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c deleted file mode 100644 index 5360d58804f..00000000000 --- a/drivers/i2c/chips/ds1621.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - ds1621.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Christian W. Zuckschwerdt 2000-11-23 - based on lm75.c by Frodo Looijaard - Ported to Linux 2.6 by Aurelien Jarno with - the help of Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include "lm75.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, - 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(ds1621); -static int polarity = -1; -module_param(polarity, int, 0); -MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low"); - -/* Many DS1621 constants specified below */ -/* Config register used for detection */ -/* 7 6 5 4 3 2 1 0 */ -/* |Done|THF |TLF |NVB | X | X |POL |1SHOT| */ -#define DS1621_REG_CONFIG_NVB 0x10 -#define DS1621_REG_CONFIG_POLARITY 0x02 -#define DS1621_REG_CONFIG_1SHOT 0x01 -#define DS1621_REG_CONFIG_DONE 0x80 - -/* The DS1621 registers */ -#define DS1621_REG_TEMP 0xAA /* word, RO */ -#define DS1621_REG_TEMP_MIN 0xA1 /* word, RW */ -#define DS1621_REG_TEMP_MAX 0xA2 /* word, RW */ -#define DS1621_REG_CONF 0xAC /* byte, RW */ -#define DS1621_COM_START 0xEE /* no data */ -#define DS1621_COM_STOP 0x22 /* no data */ - -/* The DS1621 configuration register */ -#define DS1621_ALARM_TEMP_HIGH 0x40 -#define DS1621_ALARM_TEMP_LOW 0x20 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define ALARMS_FROM_REG(val) ((val) & \ - (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) - -/* Each client has this additional data */ -struct ds1621_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 temp, temp_min, temp_max; /* Register values, word */ - u8 conf; /* Register encoding, combined */ -}; - -static int ds1621_attach_adapter(struct i2c_adapter *adapter); -static int ds1621_detect(struct i2c_adapter *adapter, int address, - int kind); -static void ds1621_init_client(struct i2c_client *client); -static int ds1621_detach_client(struct i2c_client *client); -static struct ds1621_data *ds1621_update_client(struct device *dev); - -/* This is the driver that will be inserted */ -static struct i2c_driver ds1621_driver = { - .owner = THIS_MODULE, - .name = "ds1621", - .id = I2C_DRIVERID_DS1621, - .flags = I2C_DF_NOTIFY, - .attach_adapter = ds1621_attach_adapter, - .detach_client = ds1621_detach_client, -}; - -/* All registers are word-sized, except for the configuration register. - DS1621 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int ds1621_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == DS1621_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return swab16(i2c_smbus_read_word_data(client, reg)); -} - -/* All registers are word-sized, except for the configuration register. - DS1621 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == DS1621_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - -static void ds1621_init_client(struct i2c_client *client) -{ - int reg = ds1621_read_value(client, DS1621_REG_CONF); - /* switch to continuous conversion mode */ - reg &= ~ DS1621_REG_CONFIG_1SHOT; - - /* setup output polarity */ - if (polarity == 0) - reg &= ~DS1621_REG_CONFIG_POLARITY; - else if (polarity == 1) - reg |= DS1621_REG_CONFIG_POLARITY; - - ds1621_write_value(client, DS1621_REG_CONF, reg); - - /* start conversion */ - i2c_smbus_write_byte(client, DS1621_COM_START); -} - -#define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct ds1621_data *data = ds1621_update_client(dev); \ - return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ -} - -show(temp); -show(temp_min); -show(temp_max); - -#define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct ds1621_data *data = ds1621_update_client(dev); \ - u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \ - \ - down(&data->update_lock); \ - data->value = val; \ - ds1621_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} - -set_temp(min, temp_min, DS1621_REG_TEMP_MIN); -set_temp(max, temp_max, DS1621_REG_TEMP_MAX); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct ds1621_data *data = ds1621_update_client(dev); - return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf)); -} - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); - - -static int ds1621_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, ds1621_detect); -} - -/* This function is called by i2c_detect */ -int ds1621_detect(struct i2c_adapter *adapter, int address, - int kind) -{ - int conf, temp; - struct i2c_client *new_client; - struct ds1621_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA - | I2C_FUNC_SMBUS_WORD_DATA - | I2C_FUNC_SMBUS_WRITE_BYTE)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access ds1621_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct ds1621_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &ds1621_driver; - new_client->flags = 0; - - - /* Now, we do the remaining detection. It is lousy. */ - if (kind < 0) { - /* The NVB bit should be low if no EEPROM write has been - requested during the latest 10ms, which is highly - improbable in our case. */ - conf = ds1621_read_value(new_client, DS1621_REG_CONF); - if (conf & DS1621_REG_CONFIG_NVB) - goto exit_free; - /* The 7 lowest bits of a temperature should always be 0. */ - temp = ds1621_read_value(new_client, DS1621_REG_TEMP); - if (temp & 0x007f) - goto exit_free; - temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MIN); - if (temp & 0x007f) - goto exit_free; - temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MAX); - if (temp & 0x007f) - goto exit_free; - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = ds1621; - - /* Fill in remaining client fields and put it into the global list */ - strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the DS1621 chip */ - ds1621_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - exit_free: - kfree(data); - exit: - return err; -} - -static int ds1621_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - - return 0; -} - - -static struct ds1621_data *ds1621_update_client(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct ds1621_data *data = i2c_get_clientdata(client); - u8 new_conf; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - dev_dbg(&client->dev, "Starting ds1621 update\n"); - - data->conf = ds1621_read_value(client, DS1621_REG_CONF); - - data->temp = ds1621_read_value(client, DS1621_REG_TEMP); - - data->temp_min = ds1621_read_value(client, - DS1621_REG_TEMP_MIN); - data->temp_max = ds1621_read_value(client, - DS1621_REG_TEMP_MAX); - - /* reset alarms if necessary */ - new_conf = data->conf; - if (data->temp < data->temp_min) - new_conf &= ~DS1621_ALARM_TEMP_LOW; - if (data->temp > data->temp_max) - new_conf &= ~DS1621_ALARM_TEMP_HIGH; - if (data->conf != new_conf) - ds1621_write_value(client, DS1621_REG_CONF, - new_conf); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init ds1621_init(void) -{ - return i2c_add_driver(&ds1621_driver); -} - -static void __exit ds1621_exit(void) -{ - i2c_del_driver(&ds1621_driver); -} - - -MODULE_AUTHOR("Christian W. Zuckschwerdt "); -MODULE_DESCRIPTION("DS1621 driver"); -MODULE_LICENSE("GPL"); - -module_init(ds1621_init); -module_exit(ds1621_exit); diff --git a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c deleted file mode 100644 index da411741c2c..00000000000 --- a/drivers/i2c/chips/fscher.c +++ /dev/null @@ -1,691 +0,0 @@ -/* - * fscher.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003, 2004 Reinhard Nissl - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * fujitsu siemens hermes chip, - * module based on fscpos.c - * Copyright (C) 2000 Hermann Jung - * Copyright (C) 1998, 1999 Frodo Looijaard - * and Philip Edelbrock - */ - -#include -#include -#include -#include -#include -#include - -/* - * Addresses to scan - */ - -static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(fscher); - -/* - * The FSCHER registers - */ - -/* chip identification */ -#define FSCHER_REG_IDENT_0 0x00 -#define FSCHER_REG_IDENT_1 0x01 -#define FSCHER_REG_IDENT_2 0x02 -#define FSCHER_REG_REVISION 0x03 - -/* global control and status */ -#define FSCHER_REG_EVENT_STATE 0x04 -#define FSCHER_REG_CONTROL 0x05 - -/* watchdog */ -#define FSCHER_REG_WDOG_PRESET 0x28 -#define FSCHER_REG_WDOG_STATE 0x23 -#define FSCHER_REG_WDOG_CONTROL 0x21 - -/* fan 0 */ -#define FSCHER_REG_FAN0_MIN 0x55 -#define FSCHER_REG_FAN0_ACT 0x0e -#define FSCHER_REG_FAN0_STATE 0x0d -#define FSCHER_REG_FAN0_RIPPLE 0x0f - -/* fan 1 */ -#define FSCHER_REG_FAN1_MIN 0x65 -#define FSCHER_REG_FAN1_ACT 0x6b -#define FSCHER_REG_FAN1_STATE 0x62 -#define FSCHER_REG_FAN1_RIPPLE 0x6f - -/* fan 2 */ -#define FSCHER_REG_FAN2_MIN 0xb5 -#define FSCHER_REG_FAN2_ACT 0xbb -#define FSCHER_REG_FAN2_STATE 0xb2 -#define FSCHER_REG_FAN2_RIPPLE 0xbf - -/* voltage supervision */ -#define FSCHER_REG_VOLT_12 0x45 -#define FSCHER_REG_VOLT_5 0x42 -#define FSCHER_REG_VOLT_BATT 0x48 - -/* temperature 0 */ -#define FSCHER_REG_TEMP0_ACT 0x64 -#define FSCHER_REG_TEMP0_STATE 0x71 - -/* temperature 1 */ -#define FSCHER_REG_TEMP1_ACT 0x32 -#define FSCHER_REG_TEMP1_STATE 0x81 - -/* temperature 2 */ -#define FSCHER_REG_TEMP2_ACT 0x35 -#define FSCHER_REG_TEMP2_STATE 0x91 - -/* - * Functions declaration - */ - -static int fscher_attach_adapter(struct i2c_adapter *adapter); -static int fscher_detect(struct i2c_adapter *adapter, int address, int kind); -static int fscher_detach_client(struct i2c_client *client); -static struct fscher_data *fscher_update_device(struct device *dev); -static void fscher_init_client(struct i2c_client *client); - -static int fscher_read_value(struct i2c_client *client, u8 reg); -static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver fscher_driver = { - .owner = THIS_MODULE, - .name = "fscher", - .id = I2C_DRIVERID_FSCHER, - .flags = I2C_DF_NOTIFY, - .attach_adapter = fscher_attach_adapter, - .detach_client = fscher_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct fscher_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* register values */ - u8 revision; /* revision of chip */ - u8 global_event; /* global event status */ - u8 global_control; /* global control register */ - u8 watchdog[3]; /* watchdog */ - u8 volt[3]; /* 12, 5, battery voltage */ - u8 temp_act[3]; /* temperature */ - u8 temp_status[3]; /* status of sensor */ - u8 fan_act[3]; /* fans revolutions per second */ - u8 fan_status[3]; /* fan status */ - u8 fan_min[3]; /* fan min value for rps */ - u8 fan_ripple[3]; /* divider for rps */ -}; - -/* - * Sysfs stuff - */ - -#define sysfs_r(kind, sub, offset, reg) \ -static ssize_t show_##kind##sub (struct fscher_data *, char *, int); \ -static ssize_t show_##kind##offset##sub (struct device *, struct device_attribute *attr, char *); \ -static ssize_t show_##kind##offset##sub (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct fscher_data *data = fscher_update_device(dev); \ - return show_##kind##sub(data, buf, (offset)); \ -} - -#define sysfs_w(kind, sub, offset, reg) \ -static ssize_t set_##kind##sub (struct i2c_client *, struct fscher_data *, const char *, size_t, int, int); \ -static ssize_t set_##kind##offset##sub (struct device *, struct device_attribute *attr, const char *, size_t); \ -static ssize_t set_##kind##offset##sub (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct fscher_data *data = i2c_get_clientdata(client); \ - return set_##kind##sub(client, data, buf, count, (offset), reg); \ -} - -#define sysfs_rw_n(kind, sub, offset, reg) \ -sysfs_r(kind, sub, offset, reg) \ -sysfs_w(kind, sub, offset, reg) \ -static DEVICE_ATTR(kind##offset##sub, S_IRUGO | S_IWUSR, show_##kind##offset##sub, set_##kind##offset##sub); - -#define sysfs_rw(kind, sub, reg) \ -sysfs_r(kind, sub, 0, reg) \ -sysfs_w(kind, sub, 0, reg) \ -static DEVICE_ATTR(kind##sub, S_IRUGO | S_IWUSR, show_##kind##0##sub, set_##kind##0##sub); - -#define sysfs_ro_n(kind, sub, offset, reg) \ -sysfs_r(kind, sub, offset, reg) \ -static DEVICE_ATTR(kind##offset##sub, S_IRUGO, show_##kind##offset##sub, NULL); - -#define sysfs_ro(kind, sub, reg) \ -sysfs_r(kind, sub, 0, reg) \ -static DEVICE_ATTR(kind, S_IRUGO, show_##kind##0##sub, NULL); - -#define sysfs_fan(offset, reg_status, reg_min, reg_ripple, reg_act) \ -sysfs_rw_n(pwm, , offset, reg_min) \ -sysfs_rw_n(fan, _status, offset, reg_status) \ -sysfs_rw_n(fan, _div , offset, reg_ripple) \ -sysfs_ro_n(fan, _input , offset, reg_act) - -#define sysfs_temp(offset, reg_status, reg_act) \ -sysfs_rw_n(temp, _status, offset, reg_status) \ -sysfs_ro_n(temp, _input , offset, reg_act) - -#define sysfs_in(offset, reg_act) \ -sysfs_ro_n(in, _input, offset, reg_act) - -#define sysfs_revision(reg_revision) \ -sysfs_ro(revision, , reg_revision) - -#define sysfs_alarms(reg_events) \ -sysfs_ro(alarms, , reg_events) - -#define sysfs_control(reg_control) \ -sysfs_rw(control, , reg_control) - -#define sysfs_watchdog(reg_control, reg_status, reg_preset) \ -sysfs_rw(watchdog, _control, reg_control) \ -sysfs_rw(watchdog, _status , reg_status) \ -sysfs_rw(watchdog, _preset , reg_preset) - -sysfs_fan(1, FSCHER_REG_FAN0_STATE, FSCHER_REG_FAN0_MIN, - FSCHER_REG_FAN0_RIPPLE, FSCHER_REG_FAN0_ACT) -sysfs_fan(2, FSCHER_REG_FAN1_STATE, FSCHER_REG_FAN1_MIN, - FSCHER_REG_FAN1_RIPPLE, FSCHER_REG_FAN1_ACT) -sysfs_fan(3, FSCHER_REG_FAN2_STATE, FSCHER_REG_FAN2_MIN, - FSCHER_REG_FAN2_RIPPLE, FSCHER_REG_FAN2_ACT) - -sysfs_temp(1, FSCHER_REG_TEMP0_STATE, FSCHER_REG_TEMP0_ACT) -sysfs_temp(2, FSCHER_REG_TEMP1_STATE, FSCHER_REG_TEMP1_ACT) -sysfs_temp(3, FSCHER_REG_TEMP2_STATE, FSCHER_REG_TEMP2_ACT) - -sysfs_in(0, FSCHER_REG_VOLT_12) -sysfs_in(1, FSCHER_REG_VOLT_5) -sysfs_in(2, FSCHER_REG_VOLT_BATT) - -sysfs_revision(FSCHER_REG_REVISION) -sysfs_alarms(FSCHER_REG_EVENTS) -sysfs_control(FSCHER_REG_CONTROL) -sysfs_watchdog(FSCHER_REG_WDOG_CONTROL, FSCHER_REG_WDOG_STATE, FSCHER_REG_WDOG_PRESET) - -#define device_create_file_fan(client, offset) \ -do { \ - device_create_file(&client->dev, &dev_attr_fan##offset##_status); \ - device_create_file(&client->dev, &dev_attr_pwm##offset); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ -} while (0) - -#define device_create_file_temp(client, offset) \ -do { \ - device_create_file(&client->dev, &dev_attr_temp##offset##_status); \ - device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ -} while (0) - -#define device_create_file_in(client, offset) \ -do { \ - device_create_file(&client->dev, &dev_attr_in##offset##_input); \ -} while (0) - -#define device_create_file_revision(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_revision); \ -} while (0) - -#define device_create_file_alarms(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_alarms); \ -} while (0) - -#define device_create_file_control(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_control); \ -} while (0) - -#define device_create_file_watchdog(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_watchdog_status); \ - device_create_file(&client->dev, &dev_attr_watchdog_control); \ - device_create_file(&client->dev, &dev_attr_watchdog_preset); \ -} while (0) - -/* - * Real code - */ - -static int fscher_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, fscher_detect); -} - -static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct fscher_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - * client structure, even though we cannot fill it completely yet. - * But it allows us to access i2c_smbus_read_byte_data. */ - if (!(data = kmalloc(sizeof(struct fscher_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct fscher_data)); - - /* The common I2C client data is placed right before the - * Hermes-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &fscher_driver; - new_client->flags = 0; - - /* Do the remaining detection unless force or force_fscher parameter */ - if (kind < 0) { - if ((i2c_smbus_read_byte_data(new_client, - FSCHER_REG_IDENT_0) != 0x48) /* 'H' */ - || (i2c_smbus_read_byte_data(new_client, - FSCHER_REG_IDENT_1) != 0x45) /* 'E' */ - || (i2c_smbus_read_byte_data(new_client, - FSCHER_REG_IDENT_2) != 0x52)) /* 'R' */ - goto exit_free; - } - - /* Fill in the remaining client fields and put it into the - * global list */ - strlcpy(new_client->name, "fscher", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - fscher_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file_revision(new_client); - device_create_file_alarms(new_client); - device_create_file_control(new_client); - device_create_file_watchdog(new_client); - - device_create_file_in(new_client, 0); - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - device_create_file_temp(new_client, 3); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int fscher_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - -static int fscher_read_value(struct i2c_client *client, u8 reg) -{ - dev_dbg(&client->dev, "read reg 0x%02x\n", reg); - - return i2c_smbus_read_byte_data(client, reg); -} - -static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - dev_dbg(&client->dev, "write reg 0x%02x, val 0x%02x\n", - reg, value); - - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new FSC Hermes. */ -static void fscher_init_client(struct i2c_client *client) -{ - struct fscher_data *data = i2c_get_clientdata(client); - - /* Read revision from chip */ - data->revision = fscher_read_value(client, FSCHER_REG_REVISION); -} - -static struct fscher_data *fscher_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct fscher_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { - - dev_dbg(&client->dev, "Starting fscher update\n"); - - data->temp_act[0] = fscher_read_value(client, FSCHER_REG_TEMP0_ACT); - data->temp_act[1] = fscher_read_value(client, FSCHER_REG_TEMP1_ACT); - data->temp_act[2] = fscher_read_value(client, FSCHER_REG_TEMP2_ACT); - data->temp_status[0] = fscher_read_value(client, FSCHER_REG_TEMP0_STATE); - data->temp_status[1] = fscher_read_value(client, FSCHER_REG_TEMP1_STATE); - data->temp_status[2] = fscher_read_value(client, FSCHER_REG_TEMP2_STATE); - - data->volt[0] = fscher_read_value(client, FSCHER_REG_VOLT_12); - data->volt[1] = fscher_read_value(client, FSCHER_REG_VOLT_5); - data->volt[2] = fscher_read_value(client, FSCHER_REG_VOLT_BATT); - - data->fan_act[0] = fscher_read_value(client, FSCHER_REG_FAN0_ACT); - data->fan_act[1] = fscher_read_value(client, FSCHER_REG_FAN1_ACT); - data->fan_act[2] = fscher_read_value(client, FSCHER_REG_FAN2_ACT); - data->fan_status[0] = fscher_read_value(client, FSCHER_REG_FAN0_STATE); - data->fan_status[1] = fscher_read_value(client, FSCHER_REG_FAN1_STATE); - data->fan_status[2] = fscher_read_value(client, FSCHER_REG_FAN2_STATE); - data->fan_min[0] = fscher_read_value(client, FSCHER_REG_FAN0_MIN); - data->fan_min[1] = fscher_read_value(client, FSCHER_REG_FAN1_MIN); - data->fan_min[2] = fscher_read_value(client, FSCHER_REG_FAN2_MIN); - data->fan_ripple[0] = fscher_read_value(client, FSCHER_REG_FAN0_RIPPLE); - data->fan_ripple[1] = fscher_read_value(client, FSCHER_REG_FAN1_RIPPLE); - data->fan_ripple[2] = fscher_read_value(client, FSCHER_REG_FAN2_RIPPLE); - - data->watchdog[0] = fscher_read_value(client, FSCHER_REG_WDOG_PRESET); - data->watchdog[1] = fscher_read_value(client, FSCHER_REG_WDOG_STATE); - data->watchdog[2] = fscher_read_value(client, FSCHER_REG_WDOG_CONTROL); - - data->global_event = fscher_read_value(client, FSCHER_REG_EVENT_STATE); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - - - -#define FAN_INDEX_FROM_NUM(nr) ((nr) - 1) - -static ssize_t set_fan_status(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - /* bits 0..1, 3..7 reserved => mask with 0x04 */ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0x04; - - down(&data->update_lock); - data->fan_status[FAN_INDEX_FROM_NUM(nr)] &= ~v; - fscher_write_value(client, reg, v); - up(&data->update_lock); - return count; -} - -static ssize_t show_fan_status(struct fscher_data *data, char *buf, int nr) -{ - /* bits 0..1, 3..7 reserved => mask with 0x04 */ - return sprintf(buf, "%u\n", data->fan_status[FAN_INDEX_FROM_NUM(nr)] & 0x04); -} - -static ssize_t set_pwm(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[FAN_INDEX_FROM_NUM(nr)] = v > 0xff ? 0xff : v; - fscher_write_value(client, reg, data->fan_min[FAN_INDEX_FROM_NUM(nr)]); - up(&data->update_lock); - return count; -} - -static ssize_t show_pwm(struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", data->fan_min[FAN_INDEX_FROM_NUM(nr)]); -} - -static ssize_t set_fan_div(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - /* supported values: 2, 4, 8 */ - unsigned long v = simple_strtoul(buf, NULL, 10); - - switch (v) { - case 2: v = 1; break; - case 4: v = 2; break; - case 8: v = 3; break; - default: - dev_err(&client->dev, "fan_div value %ld not " - "supported. Choose one of 2, 4 or 8!\n", v); - return -EINVAL; - } - - down(&data->update_lock); - - /* bits 2..7 reserved => mask with 0x03 */ - data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] &= ~0x03; - data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] |= v; - - fscher_write_value(client, reg, data->fan_ripple[FAN_INDEX_FROM_NUM(nr)]); - up(&data->update_lock); - return count; -} - -static ssize_t show_fan_div(struct fscher_data *data, char *buf, int nr) -{ - /* bits 2..7 reserved => mask with 0x03 */ - return sprintf(buf, "%u\n", 1 << (data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] & 0x03)); -} - -#define RPM_FROM_REG(val) (val*60) - -static ssize_t show_fan_input (struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[FAN_INDEX_FROM_NUM(nr)])); -} - - - -#define TEMP_INDEX_FROM_NUM(nr) ((nr) - 1) - -static ssize_t set_temp_status(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - /* bits 2..7 reserved, 0 read only => mask with 0x02 */ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; - - down(&data->update_lock); - data->temp_status[TEMP_INDEX_FROM_NUM(nr)] &= ~v; - fscher_write_value(client, reg, v); - up(&data->update_lock); - return count; -} - -static ssize_t show_temp_status(struct fscher_data *data, char *buf, int nr) -{ - /* bits 2..7 reserved => mask with 0x03 */ - return sprintf(buf, "%u\n", data->temp_status[TEMP_INDEX_FROM_NUM(nr)] & 0x03); -} - -#define TEMP_FROM_REG(val) (((val) - 128) * 1000) - -static ssize_t show_temp_input(struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[TEMP_INDEX_FROM_NUM(nr)])); -} - -/* - * The final conversion is specified in sensors.conf, as it depends on - * mainboard specific values. We export the registers contents as - * pseudo-hundredths-of-Volts (range 0V - 2.55V). Not that it makes much - * sense per se, but it minimizes the conversions count and keeps the - * values within a usual range. - */ -#define VOLT_FROM_REG(val) ((val) * 10) - -static ssize_t show_in_input(struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[nr])); -} - - - -static ssize_t show_revision(struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", data->revision); -} - - - -static ssize_t show_alarms(struct fscher_data *data, char *buf, int nr) -{ - /* bits 2, 5..6 reserved => mask with 0x9b */ - return sprintf(buf, "%u\n", data->global_event & 0x9b); -} - - - -static ssize_t set_control(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - /* bits 1..7 reserved => mask with 0x01 */ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0x01; - - down(&data->update_lock); - data->global_control &= ~v; - fscher_write_value(client, reg, v); - up(&data->update_lock); - return count; -} - -static ssize_t show_control(struct fscher_data *data, char *buf, int nr) -{ - /* bits 1..7 reserved => mask with 0x01 */ - return sprintf(buf, "%u\n", data->global_control & 0x01); -} - - - -static ssize_t set_watchdog_control(struct i2c_client *client, struct - fscher_data *data, const char *buf, size_t count, - int nr, int reg) -{ - /* bits 0..3 reserved => mask with 0xf0 */ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0; - - down(&data->update_lock); - data->watchdog[2] &= ~0xf0; - data->watchdog[2] |= v; - fscher_write_value(client, reg, data->watchdog[2]); - up(&data->update_lock); - return count; -} - -static ssize_t show_watchdog_control(struct fscher_data *data, char *buf, int nr) -{ - /* bits 0..3 reserved, bit 5 write only => mask with 0xd0 */ - return sprintf(buf, "%u\n", data->watchdog[2] & 0xd0); -} - -static ssize_t set_watchdog_status(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - /* bits 0, 2..7 reserved => mask with 0x02 */ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; - - down(&data->update_lock); - data->watchdog[1] &= ~v; - fscher_write_value(client, reg, v); - up(&data->update_lock); - return count; -} - -static ssize_t show_watchdog_status(struct fscher_data *data, char *buf, int nr) -{ - /* bits 0, 2..7 reserved => mask with 0x02 */ - return sprintf(buf, "%u\n", data->watchdog[1] & 0x02); -} - -static ssize_t set_watchdog_preset(struct i2c_client *client, struct fscher_data *data, - const char *buf, size_t count, int nr, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff; - - down(&data->update_lock); - data->watchdog[0] = v; - fscher_write_value(client, reg, data->watchdog[0]); - up(&data->update_lock); - return count; -} - -static ssize_t show_watchdog_preset(struct fscher_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", data->watchdog[0]); -} - -static int __init sensors_fscher_init(void) -{ - return i2c_add_driver(&fscher_driver); -} - -static void __exit sensors_fscher_exit(void) -{ - i2c_del_driver(&fscher_driver); -} - -MODULE_AUTHOR("Reinhard Nissl "); -MODULE_DESCRIPTION("FSC Hermes driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_fscher_init); -module_exit(sensors_fscher_exit); diff --git a/drivers/i2c/chips/fscpos.c b/drivers/i2c/chips/fscpos.c deleted file mode 100644 index 3beaa6191ef..00000000000 --- a/drivers/i2c/chips/fscpos.c +++ /dev/null @@ -1,641 +0,0 @@ -/* - fscpos.c - Kernel module for hardware monitoring with FSC Poseidon chips - Copyright (C) 2004, 2005 Stefan Ott - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - fujitsu siemens poseidon chip, - module based on the old fscpos module by Hermann Jung and - the fscher module by Reinhard Nissl - - original module based on lm80.c - Copyright (C) 1998, 1999 Frodo Looijaard - and Philip Edelbrock - - Thanks to Jean Delvare for reviewing my code and suggesting a lot of - improvements. -*/ - -#include -#include -#include -#include -#include - -/* - * Addresses to scan - */ -static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ -SENSORS_INSMOD_1(fscpos); - -/* - * The FSCPOS registers - */ - -/* chip identification */ -#define FSCPOS_REG_IDENT_0 0x00 -#define FSCPOS_REG_IDENT_1 0x01 -#define FSCPOS_REG_IDENT_2 0x02 -#define FSCPOS_REG_REVISION 0x03 - -/* global control and status */ -#define FSCPOS_REG_EVENT_STATE 0x04 -#define FSCPOS_REG_CONTROL 0x05 - -/* watchdog */ -#define FSCPOS_REG_WDOG_PRESET 0x28 -#define FSCPOS_REG_WDOG_STATE 0x23 -#define FSCPOS_REG_WDOG_CONTROL 0x21 - -/* voltages */ -#define FSCPOS_REG_VOLT_12 0x45 -#define FSCPOS_REG_VOLT_5 0x42 -#define FSCPOS_REG_VOLT_BATT 0x48 - -/* fans - the chip does not support minimum speed for fan2 */ -static u8 FSCPOS_REG_PWM[] = { 0x55, 0x65 }; -static u8 FSCPOS_REG_FAN_ACT[] = { 0x0e, 0x6b, 0xab }; -static u8 FSCPOS_REG_FAN_STATE[] = { 0x0d, 0x62, 0xa2 }; -static u8 FSCPOS_REG_FAN_RIPPLE[] = { 0x0f, 0x6f, 0xaf }; - -/* temperatures */ -static u8 FSCPOS_REG_TEMP_ACT[] = { 0x64, 0x32, 0x35 }; -static u8 FSCPOS_REG_TEMP_STATE[] = { 0x71, 0x81, 0x91 }; - -/* - * Functions declaration - */ -static int fscpos_attach_adapter(struct i2c_adapter *adapter); -static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind); -static int fscpos_detach_client(struct i2c_client *client); - -static int fscpos_read_value(struct i2c_client *client, u8 register); -static int fscpos_write_value(struct i2c_client *client, u8 register, u8 value); -static struct fscpos_data *fscpos_update_device(struct device *dev); -static void fscpos_init_client(struct i2c_client *client); - -static void reset_fan_alarm(struct i2c_client *client, int nr); - -/* - * Driver data (common to all clients) - */ -static struct i2c_driver fscpos_driver = { - .owner = THIS_MODULE, - .name = "fscpos", - .id = I2C_DRIVERID_FSCPOS, - .flags = I2C_DF_NOTIFY, - .attach_adapter = fscpos_attach_adapter, - .detach_client = fscpos_detach_client, -}; - -/* - * Client data (each client gets its own) - */ -struct fscpos_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* 0 until following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - /* register values */ - u8 revision; /* revision of chip */ - u8 global_event; /* global event status */ - u8 global_control; /* global control register */ - u8 wdog_control; /* watchdog control */ - u8 wdog_state; /* watchdog status */ - u8 wdog_preset; /* watchdog preset */ - u8 volt[3]; /* 12, 5, battery current */ - u8 temp_act[3]; /* temperature */ - u8 temp_status[3]; /* status of sensor */ - u8 fan_act[3]; /* fans revolutions per second */ - u8 fan_status[3]; /* fan status */ - u8 pwm[2]; /* fan min value for rps */ - u8 fan_ripple[3]; /* divider for rps */ -}; - -/* Temperature */ -#define TEMP_FROM_REG(val) (((val) - 128) * 1000) - -static ssize_t show_temp_input(struct fscpos_data *data, char *buf, int nr) -{ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[nr - 1])); -} - -static ssize_t show_temp_status(struct fscpos_data *data, char *buf, int nr) -{ - /* bits 2..7 reserved => mask with 0x03 */ - return sprintf(buf, "%u\n", data->temp_status[nr - 1] & 0x03); -} - -static ssize_t show_temp_reset(struct fscpos_data *data, char *buf, int nr) -{ - return sprintf(buf, "1\n"); -} - -static ssize_t set_temp_reset(struct i2c_client *client, struct fscpos_data - *data, const char *buf, size_t count, int nr, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10); - if (v != 1) { - dev_err(&client->dev, "temp_reset value %ld not supported. " - "Use 1 to reset the alarm!\n", v); - return -EINVAL; - } - - dev_info(&client->dev, "You used the temp_reset feature which has not " - "been proplerly tested. Please report your " - "experience to the module author.\n"); - - /* Supported value: 2 (clears the status) */ - fscpos_write_value(client, FSCPOS_REG_TEMP_STATE[nr], 2); - return count; -} - -/* Fans */ -#define RPM_FROM_REG(val) ((val) * 60) - -static ssize_t show_fan_status(struct fscpos_data *data, char *buf, int nr) -{ - /* bits 0..1, 3..7 reserved => mask with 0x04 */ - return sprintf(buf, "%u\n", data->fan_status[nr - 1] & 0x04); -} - -static ssize_t show_fan_input(struct fscpos_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[nr - 1])); -} - -static ssize_t show_fan_ripple(struct fscpos_data *data, char *buf, int nr) -{ - /* bits 2..7 reserved => mask with 0x03 */ - return sprintf(buf, "%u\n", data->fan_ripple[nr - 1] & 0x03); -} - -static ssize_t set_fan_ripple(struct i2c_client *client, struct fscpos_data - *data, const char *buf, size_t count, int nr, int reg) -{ - /* supported values: 2, 4, 8 */ - unsigned long v = simple_strtoul(buf, NULL, 10); - - switch (v) { - case 2: v = 1; break; - case 4: v = 2; break; - case 8: v = 3; break; - default: - dev_err(&client->dev, "fan_ripple value %ld not supported. " - "Must be one of 2, 4 or 8!\n", v); - return -EINVAL; - } - - down(&data->update_lock); - /* bits 2..7 reserved => mask with 0x03 */ - data->fan_ripple[nr - 1] &= ~0x03; - data->fan_ripple[nr - 1] |= v; - - fscpos_write_value(client, reg, data->fan_ripple[nr - 1]); - up(&data->update_lock); - return count; -} - -static ssize_t show_pwm(struct fscpos_data *data, char *buf, int nr) -{ - return sprintf(buf, "%u\n", data->pwm[nr - 1]); -} - -static ssize_t set_pwm(struct i2c_client *client, struct fscpos_data *data, - const char *buf, size_t count, int nr, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10); - - /* Range: 0..255 */ - if (v < 0) v = 0; - if (v > 255) v = 255; - - down(&data->update_lock); - data->pwm[nr - 1] = v; - fscpos_write_value(client, reg, data->pwm[nr - 1]); - up(&data->update_lock); - return count; -} - -static void reset_fan_alarm(struct i2c_client *client, int nr) -{ - fscpos_write_value(client, FSCPOS_REG_FAN_STATE[nr], 4); -} - -/* Volts */ -#define VOLT_FROM_REG(val, mult) ((val) * (mult) / 255) - -static ssize_t show_volt_12(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct fscpos_data *data = fscpos_update_device(dev); - return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[0], 14200)); -} - -static ssize_t show_volt_5(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct fscpos_data *data = fscpos_update_device(dev); - return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[1], 6600)); -} - -static ssize_t show_volt_batt(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct fscpos_data *data = fscpos_update_device(dev); - return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[2], 3300)); -} - -/* Watchdog */ -static ssize_t show_wdog_control(struct fscpos_data *data, char *buf) -{ - /* bits 0..3 reserved, bit 6 write only => mask with 0xb0 */ - return sprintf(buf, "%u\n", data->wdog_control & 0xb0); -} - -static ssize_t set_wdog_control(struct i2c_client *client, struct fscpos_data - *data, const char *buf, size_t count, int reg) -{ - /* bits 0..3 reserved => mask with 0xf0 */ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0; - - down(&data->update_lock); - data->wdog_control &= ~0xf0; - data->wdog_control |= v; - fscpos_write_value(client, reg, data->wdog_control); - up(&data->update_lock); - return count; -} - -static ssize_t show_wdog_state(struct fscpos_data *data, char *buf) -{ - /* bits 0, 2..7 reserved => mask with 0x02 */ - return sprintf(buf, "%u\n", data->wdog_state & 0x02); -} - -static ssize_t set_wdog_state(struct i2c_client *client, struct fscpos_data - *data, const char *buf, size_t count, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; - - /* Valid values: 2 (clear) */ - if (v != 2) { - dev_err(&client->dev, "wdog_state value %ld not supported. " - "Must be 2 to clear the state!\n", v); - return -EINVAL; - } - - down(&data->update_lock); - data->wdog_state &= ~v; - fscpos_write_value(client, reg, v); - up(&data->update_lock); - return count; -} - -static ssize_t show_wdog_preset(struct fscpos_data *data, char *buf) -{ - return sprintf(buf, "%u\n", data->wdog_preset); -} - -static ssize_t set_wdog_preset(struct i2c_client *client, struct fscpos_data - *data, const char *buf, size_t count, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff; - - down(&data->update_lock); - data->wdog_preset = v; - fscpos_write_value(client, reg, data->wdog_preset); - up(&data->update_lock); - return count; -} - -/* Event */ -static ssize_t show_event(struct device *dev, struct device_attribute *attr, char *buf) -{ - /* bits 5..7 reserved => mask with 0x1f */ - struct fscpos_data *data = fscpos_update_device(dev); - return sprintf(buf, "%u\n", data->global_event & 0x9b); -} - -/* - * Sysfs stuff - */ -#define create_getter(kind, sub) \ - static ssize_t sysfs_show_##kind##sub(struct device *dev, struct device_attribute *attr, char *buf) \ - { \ - struct fscpos_data *data = fscpos_update_device(dev); \ - return show_##kind##sub(data, buf); \ - } - -#define create_getter_n(kind, offset, sub) \ - static ssize_t sysfs_show_##kind##offset##sub(struct device *dev, struct device_attribute *attr, char\ - *buf) \ - { \ - struct fscpos_data *data = fscpos_update_device(dev); \ - return show_##kind##sub(data, buf, offset); \ - } - -#define create_setter(kind, sub, reg) \ - static ssize_t sysfs_set_##kind##sub (struct device *dev, struct device_attribute *attr, const char \ - *buf, size_t count) \ - { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct fscpos_data *data = i2c_get_clientdata(client); \ - return set_##kind##sub(client, data, buf, count, reg); \ - } - -#define create_setter_n(kind, offset, sub, reg) \ - static ssize_t sysfs_set_##kind##offset##sub (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ - { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct fscpos_data *data = i2c_get_clientdata(client); \ - return set_##kind##sub(client, data, buf, count, offset, reg);\ - } - -#define create_sysfs_device_ro(kind, sub, offset) \ - static DEVICE_ATTR(kind##offset##sub, S_IRUGO, \ - sysfs_show_##kind##offset##sub, NULL); - -#define create_sysfs_device_rw(kind, sub, offset) \ - static DEVICE_ATTR(kind##offset##sub, S_IRUGO | S_IWUSR, \ - sysfs_show_##kind##offset##sub, sysfs_set_##kind##offset##sub); - -#define sysfs_ro_n(kind, sub, offset) \ - create_getter_n(kind, offset, sub); \ - create_sysfs_device_ro(kind, sub, offset); - -#define sysfs_rw_n(kind, sub, offset, reg) \ - create_getter_n(kind, offset, sub); \ - create_setter_n(kind, offset, sub, reg); \ - create_sysfs_device_rw(kind, sub, offset); - -#define sysfs_rw(kind, sub, reg) \ - create_getter(kind, sub); \ - create_setter(kind, sub, reg); \ - create_sysfs_device_rw(kind, sub,); - -#define sysfs_fan_with_min(offset, reg_status, reg_ripple, reg_min) \ - sysfs_fan(offset, reg_status, reg_ripple); \ - sysfs_rw_n(pwm,, offset, reg_min); - -#define sysfs_fan(offset, reg_status, reg_ripple) \ - sysfs_ro_n(fan, _input, offset); \ - sysfs_ro_n(fan, _status, offset); \ - sysfs_rw_n(fan, _ripple, offset, reg_ripple); - -#define sysfs_temp(offset, reg_status) \ - sysfs_ro_n(temp, _input, offset); \ - sysfs_ro_n(temp, _status, offset); \ - sysfs_rw_n(temp, _reset, offset, reg_status); - -#define sysfs_watchdog(reg_wdog_preset, reg_wdog_state, reg_wdog_control) \ - sysfs_rw(wdog, _control, reg_wdog_control); \ - sysfs_rw(wdog, _preset, reg_wdog_preset); \ - sysfs_rw(wdog, _state, reg_wdog_state); - -sysfs_fan_with_min(1, FSCPOS_REG_FAN_STATE[0], FSCPOS_REG_FAN_RIPPLE[0], - FSCPOS_REG_PWM[0]); -sysfs_fan_with_min(2, FSCPOS_REG_FAN_STATE[1], FSCPOS_REG_FAN_RIPPLE[1], - FSCPOS_REG_PWM[1]); -sysfs_fan(3, FSCPOS_REG_FAN_STATE[2], FSCPOS_REG_FAN_RIPPLE[2]); - -sysfs_temp(1, FSCPOS_REG_TEMP_STATE[0]); -sysfs_temp(2, FSCPOS_REG_TEMP_STATE[1]); -sysfs_temp(3, FSCPOS_REG_TEMP_STATE[2]); - -sysfs_watchdog(FSCPOS_REG_WDOG_PRESET, FSCPOS_REG_WDOG_STATE, - FSCPOS_REG_WDOG_CONTROL); - -static DEVICE_ATTR(event, S_IRUGO, show_event, NULL); -static DEVICE_ATTR(in0_input, S_IRUGO, show_volt_12, NULL); -static DEVICE_ATTR(in1_input, S_IRUGO, show_volt_5, NULL); -static DEVICE_ATTR(in2_input, S_IRUGO, show_volt_batt, NULL); - -static int fscpos_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, fscpos_detect); -} - -int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct fscpos_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - /* - * OK. For now, we presume we have a valid client. We now create the - * client structure, even though we cannot fill it completely yet. - * But it allows us to access fscpos_{read,write}_value. - */ - - if (!(data = kmalloc(sizeof(struct fscpos_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct fscpos_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &fscpos_driver; - new_client->flags = 0; - - /* Do the remaining detection unless force or force_fscpos parameter */ - if (kind < 0) { - if ((fscpos_read_value(new_client, FSCPOS_REG_IDENT_0) - != 0x50) /* 'P' */ - || (fscpos_read_value(new_client, FSCPOS_REG_IDENT_1) - != 0x45) /* 'E' */ - || (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2) - != 0x47))/* 'G' */ - { - dev_dbg(&new_client->dev, "fscpos detection failed\n"); - goto exit_free; - } - } - - /* Fill in the remaining client fields and put it in the global list */ - strlcpy(new_client->name, "fscpos", I2C_NAME_SIZE); - - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Inizialize the fscpos chip */ - fscpos_init_client(new_client); - - /* Announce that the chip was found */ - dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_event); - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_wdog_control); - device_create_file(&new_client->dev, &dev_attr_wdog_preset); - device_create_file(&new_client->dev, &dev_attr_wdog_state); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_status); - device_create_file(&new_client->dev, &dev_attr_temp1_reset); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_status); - device_create_file(&new_client->dev, &dev_attr_temp2_reset); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp3_status); - device_create_file(&new_client->dev, &dev_attr_temp3_reset); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_status); - device_create_file(&new_client->dev, &dev_attr_fan1_ripple); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_status); - device_create_file(&new_client->dev, &dev_attr_fan2_ripple); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_fan3_input); - device_create_file(&new_client->dev, &dev_attr_fan3_status); - device_create_file(&new_client->dev, &dev_attr_fan3_ripple); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int fscpos_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, client" - " not detached.\n"); - return err; - } - kfree(i2c_get_clientdata(client)); - return 0; -} - -static int fscpos_read_value(struct i2c_client *client, u8 reg) -{ - dev_dbg(&client->dev, "Read reg 0x%02x\n", reg); - return i2c_smbus_read_byte_data(client, reg); -} - -static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - dev_dbg(&client->dev, "Write reg 0x%02x, val 0x%02x\n", reg, value); - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new FSCPOS chip */ -static void fscpos_init_client(struct i2c_client *client) -{ - struct fscpos_data *data = i2c_get_clientdata(client); - - /* read revision from chip */ - data->revision = fscpos_read_value(client, FSCPOS_REG_REVISION); -} - -static struct fscpos_data *fscpos_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct fscpos_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - int i; - - dev_dbg(&client->dev, "Starting fscpos update\n"); - - for (i = 0; i < 3; i++) { - data->temp_act[i] = fscpos_read_value(client, - FSCPOS_REG_TEMP_ACT[i]); - data->temp_status[i] = fscpos_read_value(client, - FSCPOS_REG_TEMP_STATE[i]); - data->fan_act[i] = fscpos_read_value(client, - FSCPOS_REG_FAN_ACT[i]); - data->fan_status[i] = fscpos_read_value(client, - FSCPOS_REG_FAN_STATE[i]); - data->fan_ripple[i] = fscpos_read_value(client, - FSCPOS_REG_FAN_RIPPLE[i]); - if (i < 2) { - /* fan2_min is not supported by the chip */ - data->pwm[i] = fscpos_read_value(client, - FSCPOS_REG_PWM[i]); - } - /* reset fan status if speed is back to > 0 */ - if (data->fan_status[i] != 0 && data->fan_act[i] > 0) { - reset_fan_alarm(client, i); - } - } - - data->volt[0] = fscpos_read_value(client, FSCPOS_REG_VOLT_12); - data->volt[1] = fscpos_read_value(client, FSCPOS_REG_VOLT_5); - data->volt[2] = fscpos_read_value(client, FSCPOS_REG_VOLT_BATT); - - data->wdog_preset = fscpos_read_value(client, - FSCPOS_REG_WDOG_PRESET); - data->wdog_state = fscpos_read_value(client, - FSCPOS_REG_WDOG_STATE); - data->wdog_control = fscpos_read_value(client, - FSCPOS_REG_WDOG_CONTROL); - - data->global_event = fscpos_read_value(client, - FSCPOS_REG_EVENT_STATE); - - data->last_updated = jiffies; - data->valid = 1; - } - up(&data->update_lock); - return data; -} - -static int __init sm_fscpos_init(void) -{ - return i2c_add_driver(&fscpos_driver); -} - -static void __exit sm_fscpos_exit(void) -{ - i2c_del_driver(&fscpos_driver); -} - -MODULE_AUTHOR("Stefan Ott based on work from Hermann Jung " - ", Frodo Looijaard " - " and Philip Edelbrock "); -MODULE_DESCRIPTION("fujitsu siemens poseidon chip driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_fscpos_init); -module_exit(sm_fscpos_exit); diff --git a/drivers/i2c/chips/gl518sm.c b/drivers/i2c/chips/gl518sm.c deleted file mode 100644 index 6bedf729dcf..00000000000 --- a/drivers/i2c/chips/gl518sm.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * gl518sm.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 1998, 1999 Frodo Looijaard and - * Kyosti Malkki - * Copyright (C) 2004 Hong-Gunn Chew and - * Jean Delvare - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Ported to Linux 2.6 by Hong-Gunn Chew with the help of Jean Delvare - * and advice of Greg Kroah-Hartman. - * - * Notes about the port: - * Release 0x00 of the GL518SM chipset doesn't support reading of in0, - * in1 nor in2. The original driver had an ugly workaround to get them - * anyway (changing limits and watching alarms trigger and wear off). - * We did not keep that part of the original driver in the Linux 2.6 - * version, since it was making the driver significantly more complex - * with no real benefit. - * - * History: - * 2004-01-28 Original port. (Hong-Gunn Chew) - * 2004-01-31 Code review and approval. (Jean Delvare) - */ - -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r80); - -/* Many GL518 constants specified below */ - -/* The GL518 registers */ -#define GL518_REG_CHIP_ID 0x00 -#define GL518_REG_REVISION 0x01 -#define GL518_REG_VENDOR_ID 0x02 -#define GL518_REG_CONF 0x03 -#define GL518_REG_TEMP_IN 0x04 -#define GL518_REG_TEMP_MAX 0x05 -#define GL518_REG_TEMP_HYST 0x06 -#define GL518_REG_FAN_COUNT 0x07 -#define GL518_REG_FAN_LIMIT 0x08 -#define GL518_REG_VIN1_LIMIT 0x09 -#define GL518_REG_VIN2_LIMIT 0x0a -#define GL518_REG_VIN3_LIMIT 0x0b -#define GL518_REG_VDD_LIMIT 0x0c -#define GL518_REG_VIN3 0x0d -#define GL518_REG_MISC 0x0f -#define GL518_REG_ALARM 0x10 -#define GL518_REG_MASK 0x11 -#define GL518_REG_INT 0x12 -#define GL518_REG_VIN2 0x13 -#define GL518_REG_VIN1 0x14 -#define GL518_REG_VDD 0x15 - - -/* - * Conversions. Rounding and limit checking is only done on the TO_REG - * variants. Note that you should be a bit careful with which arguments - * these macros are called: arguments may be evaluated more than once. - * Fixing this is just not worth it. - */ - -#define RAW_FROM_REG(val) val - -#define BOOL_FROM_REG(val) ((val)?0:1) -#define BOOL_TO_REG(val) ((val)?0:1) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0? \ - (val)-500:(val)+500)/1000)+119),0,255)) -#define TEMP_FROM_REG(val) (((val) - 119) * 1000) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - long rpmdiv; - if (rpm == 0) - return 0; - rpmdiv = SENSORS_LIMIT(rpm, 1, 1920000) * div; - return SENSORS_LIMIT((960000 + rpmdiv / 2) / rpmdiv, 1, 255); -} -#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (960000/((val)*(div)))) - -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) -#define IN_FROM_REG(val) ((val)*19) - -#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) -#define VDD_FROM_REG(val) (((val)*95+2)/4) - -#define DIV_TO_REG(val) ((val)==4?2:(val)==2?1:(val)==1?0:3) -#define DIV_FROM_REG(val) (1 << (val)) - -#define BEEP_MASK_TO_REG(val) ((val) & 0x7f & data->alarm_mask) -#define BEEP_MASK_FROM_REG(val) ((val) & 0x7f) - -/* Each client has this additional data */ -struct gl518_data { - struct i2c_client client; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 voltage_in[4]; /* Register values; [0] = VDD */ - u8 voltage_min[4]; /* Register values; [0] = VDD */ - u8 voltage_max[4]; /* Register values; [0] = VDD */ - u8 iter_voltage_in[4]; /* Register values; [0] = VDD */ - u8 fan_in[2]; - u8 fan_min[2]; - u8 fan_div[2]; /* Register encoding, shifted right */ - u8 fan_auto1; /* Boolean */ - u8 temp_in; /* Register values */ - u8 temp_max; /* Register values */ - u8 temp_hyst; /* Register values */ - u8 alarms; /* Register value */ - u8 alarm_mask; /* Register value */ - u8 beep_mask; /* Register value */ - u8 beep_enable; /* Boolean */ -}; - -static int gl518_attach_adapter(struct i2c_adapter *adapter); -static int gl518_detect(struct i2c_adapter *adapter, int address, int kind); -static void gl518_init_client(struct i2c_client *client); -static int gl518_detach_client(struct i2c_client *client); -static int gl518_read_value(struct i2c_client *client, u8 reg); -static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); -static struct gl518_data *gl518_update_device(struct device *dev); - -/* This is the driver that will be inserted */ -static struct i2c_driver gl518_driver = { - .owner = THIS_MODULE, - .name = "gl518sm", - .id = I2C_DRIVERID_GL518, - .flags = I2C_DF_NOTIFY, - .attach_adapter = gl518_attach_adapter, - .detach_client = gl518_detach_client, -}; - -/* - * Sysfs stuff - */ - -#define show(type, suffix, value) \ -static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct gl518_data *data = gl518_update_device(dev); \ - return sprintf(buf, "%d\n", type##_FROM_REG(data->value)); \ -} - -#define show_fan(suffix, value, index) \ -static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct gl518_data *data = gl518_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[index], \ - DIV_FROM_REG(data->fan_div[index]))); \ -} - -show(TEMP, temp_input1, temp_in); -show(TEMP, temp_max1, temp_max); -show(TEMP, temp_hyst1, temp_hyst); -show(BOOL, fan_auto1, fan_auto1); -show_fan(fan_input1, fan_in, 0); -show_fan(fan_input2, fan_in, 1); -show_fan(fan_min1, fan_min, 0); -show_fan(fan_min2, fan_min, 1); -show(DIV, fan_div1, fan_div[0]); -show(DIV, fan_div2, fan_div[1]); -show(VDD, in_input0, voltage_in[0]); -show(IN, in_input1, voltage_in[1]); -show(IN, in_input2, voltage_in[2]); -show(IN, in_input3, voltage_in[3]); -show(VDD, in_min0, voltage_min[0]); -show(IN, in_min1, voltage_min[1]); -show(IN, in_min2, voltage_min[2]); -show(IN, in_min3, voltage_min[3]); -show(VDD, in_max0, voltage_max[0]); -show(IN, in_max1, voltage_max[1]); -show(IN, in_max2, voltage_max[2]); -show(IN, in_max3, voltage_max[3]); -show(RAW, alarms, alarms); -show(BOOL, beep_enable, beep_enable); -show(BEEP_MASK, beep_mask, beep_mask); - -#define set(type, suffix, value, reg) \ -static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct gl518_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = type##_TO_REG(val); \ - gl518_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} - -#define set_bits(type, suffix, value, reg, mask, shift) \ -static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct gl518_data *data = i2c_get_clientdata(client); \ - int regvalue; \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - regvalue = gl518_read_value(client, reg); \ - data->value = type##_TO_REG(val); \ - regvalue = (regvalue & ~mask) | (data->value << shift); \ - gl518_write_value(client, reg, regvalue); \ - up(&data->update_lock); \ - return count; \ -} - -#define set_low(type, suffix, value, reg) \ - set_bits(type, suffix, value, reg, 0x00ff, 0) -#define set_high(type, suffix, value, reg) \ - set_bits(type, suffix, value, reg, 0xff00, 8) - -set(TEMP, temp_max1, temp_max, GL518_REG_TEMP_MAX); -set(TEMP, temp_hyst1, temp_hyst, GL518_REG_TEMP_HYST); -set_bits(BOOL, fan_auto1, fan_auto1, GL518_REG_MISC, 0x08, 3); -set_bits(DIV, fan_div1, fan_div[0], GL518_REG_MISC, 0xc0, 6); -set_bits(DIV, fan_div2, fan_div[1], GL518_REG_MISC, 0x30, 4); -set_low(VDD, in_min0, voltage_min[0], GL518_REG_VDD_LIMIT); -set_low(IN, in_min1, voltage_min[1], GL518_REG_VIN1_LIMIT); -set_low(IN, in_min2, voltage_min[2], GL518_REG_VIN2_LIMIT); -set_low(IN, in_min3, voltage_min[3], GL518_REG_VIN3_LIMIT); -set_high(VDD, in_max0, voltage_max[0], GL518_REG_VDD_LIMIT); -set_high(IN, in_max1, voltage_max[1], GL518_REG_VIN1_LIMIT); -set_high(IN, in_max2, voltage_max[2], GL518_REG_VIN2_LIMIT); -set_high(IN, in_max3, voltage_max[3], GL518_REG_VIN3_LIMIT); -set_bits(BOOL, beep_enable, beep_enable, GL518_REG_CONF, 0x04, 2); -set(BEEP_MASK, beep_mask, beep_mask, GL518_REG_ALARM); - -static ssize_t set_fan_min1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct gl518_data *data = i2c_get_clientdata(client); - int regvalue; - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[0] = FAN_TO_REG(val, - DIV_FROM_REG(data->fan_div[0])); - regvalue = (regvalue & 0x00ff) | (data->fan_min[0] << 8); - gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); - - data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); - if (data->fan_min[0] == 0) - data->alarm_mask &= ~0x20; - else - data->alarm_mask |= 0x20; - data->beep_mask &= data->alarm_mask; - gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); - - up(&data->update_lock); - return count; -} - -static ssize_t set_fan_min2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct gl518_data *data = i2c_get_clientdata(client); - int regvalue; - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[1] = FAN_TO_REG(val, - DIV_FROM_REG(data->fan_div[1])); - regvalue = (regvalue & 0xff00) | data->fan_min[1]; - gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); - - data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); - if (data->fan_min[1] == 0) - data->alarm_mask &= ~0x40; - else - data->alarm_mask |= 0x40; - data->beep_mask &= data->alarm_mask; - gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); - - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR|S_IRUGO, show_temp_max1, set_temp_max1); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR|S_IRUGO, - show_temp_hyst1, set_temp_hyst1); -static DEVICE_ATTR(fan1_auto, S_IWUSR|S_IRUGO, show_fan_auto1, set_fan_auto1); -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); -static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); -static DEVICE_ATTR(fan1_min, S_IWUSR|S_IRUGO, show_fan_min1, set_fan_min1); -static DEVICE_ATTR(fan2_min, S_IWUSR|S_IRUGO, show_fan_min2, set_fan_min2); -static DEVICE_ATTR(fan1_div, S_IWUSR|S_IRUGO, show_fan_div1, set_fan_div1); -static DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO, show_fan_div2, set_fan_div2); -static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL); -static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL); -static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL); -static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL); -static DEVICE_ATTR(in0_min, S_IWUSR|S_IRUGO, show_in_min0, set_in_min0); -static DEVICE_ATTR(in1_min, S_IWUSR|S_IRUGO, show_in_min1, set_in_min1); -static DEVICE_ATTR(in2_min, S_IWUSR|S_IRUGO, show_in_min2, set_in_min2); -static DEVICE_ATTR(in3_min, S_IWUSR|S_IRUGO, show_in_min3, set_in_min3); -static DEVICE_ATTR(in0_max, S_IWUSR|S_IRUGO, show_in_max0, set_in_max0); -static DEVICE_ATTR(in1_max, S_IWUSR|S_IRUGO, show_in_max1, set_in_max1); -static DEVICE_ATTR(in2_max, S_IWUSR|S_IRUGO, show_in_max2, set_in_max2); -static DEVICE_ATTR(in3_max, S_IWUSR|S_IRUGO, show_in_max3, set_in_max3); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO, - show_beep_enable, set_beep_enable); -static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO, - show_beep_mask, set_beep_mask); - -/* - * Real code - */ - -static int gl518_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, gl518_detect); -} - -static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i; - struct i2c_client *new_client; - struct gl518_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access gl518_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct gl518_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct gl518_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &gl518_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ((gl518_read_value(new_client, GL518_REG_CHIP_ID) != 0x80) - || (gl518_read_value(new_client, GL518_REG_CONF) & 0x80)) - goto exit_free; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = gl518_read_value(new_client, GL518_REG_REVISION); - if (i == 0x00) { - kind = gl518sm_r00; - } else if (i == 0x80) { - kind = gl518sm_r80; - } else { - if (kind <= 0) - dev_info(&adapter->dev, - "Ignoring 'force' parameter for unknown " - "chip at adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto exit_free; - } - } - - /* Fill in the remaining client fields */ - strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the GL518SM chip */ - data->alarm_mask = 0xff; - data->voltage_in[0]=data->voltage_in[1]=data->voltage_in[2]=0; - gl518_init_client((struct i2c_client *) new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_fan1_auto); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_beep_enable); - device_create_file(&new_client->dev, &dev_attr_beep_mask); - - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -exit_free: - kfree(data); -exit: - return err; -} - - -/* Called when we have found a new GL518SM. - Note that we preserve D4:NoFan2 and D2:beep_enable. */ -static void gl518_init_client(struct i2c_client *client) -{ - /* Make sure we leave D7:Reset untouched */ - u8 regvalue = gl518_read_value(client, GL518_REG_CONF) & 0x7f; - - /* Comparator mode (D3=0), standby mode (D6=0) */ - gl518_write_value(client, GL518_REG_CONF, (regvalue &= 0x37)); - - /* Never interrupts */ - gl518_write_value(client, GL518_REG_MASK, 0x00); - - /* Clear status register (D5=1), start (D6=1) */ - gl518_write_value(client, GL518_REG_CONF, 0x20 | regvalue); - gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue); -} - -static int gl518_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - - return 0; -} - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl518_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return swab16(i2c_smbus_read_word_data(client, reg)); - else - return i2c_smbus_read_byte_data(client, reg); -} - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_data(client, reg, swab16(value)); - else - return i2c_smbus_write_byte_data(client, reg, value); -} - -static struct gl518_data *gl518_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct gl518_data *data = i2c_get_clientdata(client); - int val; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting gl518 update\n"); - - data->alarms = gl518_read_value(client, GL518_REG_INT); - data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); - - val = gl518_read_value(client, GL518_REG_VDD_LIMIT); - data->voltage_min[0] = val & 0xff; - data->voltage_max[0] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN1_LIMIT); - data->voltage_min[1] = val & 0xff; - data->voltage_max[1] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN2_LIMIT); - data->voltage_min[2] = val & 0xff; - data->voltage_max[2] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN3_LIMIT); - data->voltage_min[3] = val & 0xff; - data->voltage_max[3] = (val >> 8) & 0xff; - - val = gl518_read_value(client, GL518_REG_FAN_COUNT); - data->fan_in[0] = (val >> 8) & 0xff; - data->fan_in[1] = val & 0xff; - - val = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[0] = (val >> 8) & 0xff; - data->fan_min[1] = val & 0xff; - - data->temp_in = gl518_read_value(client, GL518_REG_TEMP_IN); - data->temp_max = - gl518_read_value(client, GL518_REG_TEMP_MAX); - data->temp_hyst = - gl518_read_value(client, GL518_REG_TEMP_HYST); - - val = gl518_read_value(client, GL518_REG_MISC); - data->fan_div[0] = (val >> 6) & 0x03; - data->fan_div[1] = (val >> 4) & 0x03; - data->fan_auto1 = (val >> 3) & 0x01; - - data->alarms &= data->alarm_mask; - - val = gl518_read_value(client, GL518_REG_CONF); - data->beep_enable = (val >> 2) & 1; - - if (data->type != gl518sm_r00) { - data->voltage_in[0] = - gl518_read_value(client, GL518_REG_VDD); - data->voltage_in[1] = - gl518_read_value(client, GL518_REG_VIN1); - data->voltage_in[2] = - gl518_read_value(client, GL518_REG_VIN2); - } - data->voltage_in[3] = - gl518_read_value(client, GL518_REG_VIN3); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_gl518sm_init(void) -{ - return i2c_add_driver(&gl518_driver); -} - -static void __exit sensors_gl518sm_exit(void) -{ - i2c_del_driver(&gl518_driver); -} - -MODULE_AUTHOR("Frodo Looijaard , " - "Kyosti Malkki and " - "Hong-Gunn Chew "); -MODULE_DESCRIPTION("GL518SM driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_gl518sm_init); -module_exit(sensors_gl518sm_exit); diff --git a/drivers/i2c/chips/gl520sm.c b/drivers/i2c/chips/gl520sm.c deleted file mode 100644 index a13a504f5bf..00000000000 --- a/drivers/i2c/chips/gl520sm.c +++ /dev/null @@ -1,769 +0,0 @@ -/* - gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard , - Kyösti Mälkki - Copyright (c) 2005 Maarten Deprez - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include - -/* Type of the extra sensor */ -static unsigned short extra_sensor_type; -module_param(extra_sensor_type, ushort, 0); -MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=temperature, 2=voltage)"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(gl520sm); - -/* Many GL520 constants specified below -One of the inputs can be configured as either temp or voltage. -That's why _TEMP2 and _IN4 access the same register -*/ - -/* The GL520 registers */ -#define GL520_REG_CHIP_ID 0x00 -#define GL520_REG_REVISION 0x01 -#define GL520_REG_CONF 0x03 -#define GL520_REG_MASK 0x11 - -#define GL520_REG_VID_INPUT 0x02 - -#define GL520_REG_IN0_INPUT 0x15 -#define GL520_REG_IN0_LIMIT 0x0c -#define GL520_REG_IN0_MIN GL520_REG_IN0_LIMIT -#define GL520_REG_IN0_MAX GL520_REG_IN0_LIMIT - -#define GL520_REG_IN1_INPUT 0x14 -#define GL520_REG_IN1_LIMIT 0x09 -#define GL520_REG_IN1_MIN GL520_REG_IN1_LIMIT -#define GL520_REG_IN1_MAX GL520_REG_IN1_LIMIT - -#define GL520_REG_IN2_INPUT 0x13 -#define GL520_REG_IN2_LIMIT 0x0a -#define GL520_REG_IN2_MIN GL520_REG_IN2_LIMIT -#define GL520_REG_IN2_MAX GL520_REG_IN2_LIMIT - -#define GL520_REG_IN3_INPUT 0x0d -#define GL520_REG_IN3_LIMIT 0x0b -#define GL520_REG_IN3_MIN GL520_REG_IN3_LIMIT -#define GL520_REG_IN3_MAX GL520_REG_IN3_LIMIT - -#define GL520_REG_IN4_INPUT 0x0e -#define GL520_REG_IN4_MAX 0x17 -#define GL520_REG_IN4_MIN 0x18 - -#define GL520_REG_TEMP1_INPUT 0x04 -#define GL520_REG_TEMP1_MAX 0x05 -#define GL520_REG_TEMP1_MAX_HYST 0x06 - -#define GL520_REG_TEMP2_INPUT 0x0e -#define GL520_REG_TEMP2_MAX 0x17 -#define GL520_REG_TEMP2_MAX_HYST 0x18 - -#define GL520_REG_FAN_INPUT 0x07 -#define GL520_REG_FAN_MIN 0x08 -#define GL520_REG_FAN_DIV 0x0f -#define GL520_REG_FAN_OFF GL520_REG_FAN_DIV - -#define GL520_REG_ALARMS 0x12 -#define GL520_REG_BEEP_MASK 0x10 -#define GL520_REG_BEEP_ENABLE GL520_REG_CONF - -/* - * Function declarations - */ - -static int gl520_attach_adapter(struct i2c_adapter *adapter); -static int gl520_detect(struct i2c_adapter *adapter, int address, int kind); -static void gl520_init_client(struct i2c_client *client); -static int gl520_detach_client(struct i2c_client *client); -static int gl520_read_value(struct i2c_client *client, u8 reg); -static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value); -static struct gl520_data *gl520_update_device(struct device *dev); - -/* Driver data */ -static struct i2c_driver gl520_driver = { - .owner = THIS_MODULE, - .name = "gl520sm", - .id = I2C_DRIVERID_GL520, - .flags = I2C_DF_NOTIFY, - .attach_adapter = gl520_attach_adapter, - .detach_client = gl520_detach_client, -}; - -/* Client data */ -struct gl520_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until the following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - u8 vid; - u8 vrm; - u8 in_input[5]; /* [0] = VVD */ - u8 in_min[5]; /* [0] = VDD */ - u8 in_max[5]; /* [0] = VDD */ - u8 fan_input[2]; - u8 fan_min[2]; - u8 fan_div[2]; - u8 fan_off; - u8 temp_input[2]; - u8 temp_max[2]; - u8 temp_max_hyst[2]; - u8 alarms; - u8 beep_enable; - u8 beep_mask; - u8 alarm_mask; - u8 two_temps; -}; - -/* - * Sysfs stuff - */ - -#define sysfs_r(type, n, item, reg) \ -static ssize_t get_##type##item (struct gl520_data *, char *, int); \ -static ssize_t get_##type##n##item (struct device *, struct device_attribute *attr, char *); \ -static ssize_t get_##type##n##item (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct gl520_data *data = gl520_update_device(dev); \ - return get_##type##item(data, buf, (n)); \ -} - -#define sysfs_w(type, n, item, reg) \ -static ssize_t set_##type##item (struct i2c_client *, struct gl520_data *, const char *, size_t, int, int); \ -static ssize_t set_##type##n##item (struct device *, struct device_attribute *attr, const char *, size_t); \ -static ssize_t set_##type##n##item (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct gl520_data *data = i2c_get_clientdata(client); \ - return set_##type##item(client, data, buf, count, (n), reg); \ -} - -#define sysfs_rw_n(type, n, item, reg) \ -sysfs_r(type, n, item, reg) \ -sysfs_w(type, n, item, reg) \ -static DEVICE_ATTR(type##n##item, S_IRUGO | S_IWUSR, get_##type##n##item, set_##type##n##item); - -#define sysfs_ro_n(type, n, item, reg) \ -sysfs_r(type, n, item, reg) \ -static DEVICE_ATTR(type##n##item, S_IRUGO, get_##type##n##item, NULL); - -#define sysfs_rw(type, item, reg) \ -sysfs_r(type, 0, item, reg) \ -sysfs_w(type, 0, item, reg) \ -static DEVICE_ATTR(type##item, S_IRUGO | S_IWUSR, get_##type##0##item, set_##type##0##item); - -#define sysfs_ro(type, item, reg) \ -sysfs_r(type, 0, item, reg) \ -static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL); - - -#define sysfs_vid(n) \ -sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT) - -#define device_create_file_vid(client, n) \ -device_create_file(&client->dev, &dev_attr_cpu##n##_vid) - -#define sysfs_in(n) \ -sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \ -sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \ -sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \ - -#define device_create_file_in(client, n) \ -({device_create_file(&client->dev, &dev_attr_in##n##_input); \ -device_create_file(&client->dev, &dev_attr_in##n##_min); \ -device_create_file(&client->dev, &dev_attr_in##n##_max);}) - -#define sysfs_fan(n) \ -sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \ -sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \ -sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV) - -#define device_create_file_fan(client, n) \ -({device_create_file(&client->dev, &dev_attr_fan##n##_input); \ -device_create_file(&client->dev, &dev_attr_fan##n##_min); \ -device_create_file(&client->dev, &dev_attr_fan##n##_div);}) - -#define sysfs_fan_off(n) \ -sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \ - -#define device_create_file_fan_off(client, n) \ -device_create_file(&client->dev, &dev_attr_fan##n##_off) - -#define sysfs_temp(n) \ -sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \ -sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \ -sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST) - -#define device_create_file_temp(client, n) \ -({device_create_file(&client->dev, &dev_attr_temp##n##_input); \ -device_create_file(&client->dev, &dev_attr_temp##n##_max); \ -device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);}) - -#define sysfs_alarms() \ -sysfs_ro(alarms, , GL520_REG_ALARMS) \ -sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \ -sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK) - -#define device_create_file_alarms(client) \ -({device_create_file(&client->dev, &dev_attr_alarms); \ -device_create_file(&client->dev, &dev_attr_beep_enable); \ -device_create_file(&client->dev, &dev_attr_beep_mask);}) - - -sysfs_vid(0) - -sysfs_in(0) -sysfs_in(1) -sysfs_in(2) -sysfs_in(3) -sysfs_in(4) - -sysfs_fan(1) -sysfs_fan(2) -sysfs_fan_off(1) - -sysfs_temp(1) -sysfs_temp(2) - -sysfs_alarms() - - -static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); -} - -#define VDD_FROM_REG(val) (((val)*95+2)/4) -#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) - -#define IN_FROM_REG(val) ((val)*19) -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) - -static ssize_t get_in_input(struct gl520_data *data, char *buf, int n) -{ - u8 r = data->in_input[n]; - - if (n == 0) - return sprintf(buf, "%d\n", VDD_FROM_REG(r)); - else - return sprintf(buf, "%d\n", IN_FROM_REG(r)); -} - -static ssize_t get_in_min(struct gl520_data *data, char *buf, int n) -{ - u8 r = data->in_min[n]; - - if (n == 0) - return sprintf(buf, "%d\n", VDD_FROM_REG(r)); - else - return sprintf(buf, "%d\n", IN_FROM_REG(r)); -} - -static ssize_t get_in_max(struct gl520_data *data, char *buf, int n) -{ - u8 r = data->in_max[n]; - - if (n == 0) - return sprintf(buf, "%d\n", VDD_FROM_REG(r)); - else - return sprintf(buf, "%d\n", IN_FROM_REG(r)); -} - -static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - long v = simple_strtol(buf, NULL, 10); - u8 r; - - down(&data->update_lock); - - if (n == 0) - r = VDD_TO_REG(v); - else - r = IN_TO_REG(v); - - data->in_min[n] = r; - - if (n < 4) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); - else - gl520_write_value(client, reg, r); - - up(&data->update_lock); - return count; -} - -static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - long v = simple_strtol(buf, NULL, 10); - u8 r; - - if (n == 0) - r = VDD_TO_REG(v); - else - r = IN_TO_REG(v); - - down(&data->update_lock); - - data->in_max[n] = r; - - if (n < 4) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); - else - gl520_write_value(client, reg, r); - - up(&data->update_lock); - return count; -} - -#define DIV_FROM_REG(val) (1 << (val)) -#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div)))) -#define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255)); - -static ssize_t get_fan_input(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n - 1], data->fan_div[n - 1])); -} - -static ssize_t get_fan_min(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n - 1], data->fan_div[n - 1])); -} - -static ssize_t get_fan_div(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n - 1])); -} - -static ssize_t get_fan_off(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", data->fan_off); -} - -static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10); - u8 r; - - down(&data->update_lock); - r = FAN_TO_REG(v, data->fan_div[n - 1]); - data->fan_min[n - 1] = r; - - if (n == 1) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); - else - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); - - data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); - if (data->fan_min[n - 1] == 0) - data->alarm_mask &= (n == 1) ? ~0x20 : ~0x40; - else - data->alarm_mask |= (n == 1) ? 0x20 : 0x40; - data->beep_mask &= data->alarm_mask; - gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); - - up(&data->update_lock); - return count; -} - -static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - unsigned long v = simple_strtoul(buf, NULL, 10); - u8 r; - - switch (v) { - case 1: r = 0; break; - case 2: r = 1; break; - case 4: r = 2; break; - case 8: r = 3; break; - default: - dev_err(&client->dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v); - return -EINVAL; - } - - down(&data->update_lock); - data->fan_div[n - 1] = r; - - if (n == 1) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xc0) | (r << 6)); - else - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4)); - - up(&data->update_lock); - return count; -} - -static ssize_t set_fan_off(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - u8 r = simple_strtoul(buf, NULL, 10)?1:0; - - down(&data->update_lock); - data->fan_off = r; - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2)); - up(&data->update_lock); - return count; -} - -#define TEMP_FROM_REG(val) (((val) - 130) * 1000) -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255)) - -static ssize_t get_temp_input(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n - 1])); -} - -static ssize_t get_temp_max(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n - 1])); -} - -static ssize_t get_temp_max_hyst(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n - 1])); -} - -static ssize_t set_temp_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - long v = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_max[n - 1] = TEMP_TO_REG(v);; - gl520_write_value(client, reg, data->temp_max[n - 1]); - up(&data->update_lock); - return count; -} - -static ssize_t set_temp_max_hyst(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - long v = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_max_hyst[n - 1] = TEMP_TO_REG(v); - gl520_write_value(client, reg, data->temp_max_hyst[n - 1]); - up(&data->update_lock); - return count; -} - -static ssize_t get_alarms(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", data->alarms); -} - -static ssize_t get_beep_enable(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", data->beep_enable); -} - -static ssize_t get_beep_mask(struct gl520_data *data, char *buf, int n) -{ - return sprintf(buf, "%d\n", data->beep_mask); -} - -static ssize_t set_beep_enable(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - u8 r = simple_strtoul(buf, NULL, 10)?0:1; - - down(&data->update_lock); - data->beep_enable = !r; - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2)); - up(&data->update_lock); - return count; -} - -static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) -{ - u8 r = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - r &= data->alarm_mask; - data->beep_mask = r; - gl520_write_value(client, reg, r); - up(&data->update_lock); - return count; -} - - -/* - * Real code - */ - -static int gl520_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, gl520_detect); -} - -static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct gl520_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access gl520_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct gl520_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &gl520_driver; - new_client->flags = 0; - - /* Determine the chip type. */ - if (kind < 0) { - if ((gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) || - ((gl520_read_value(new_client, GL520_REG_REVISION) & 0x7f) != 0x00) || - ((gl520_read_value(new_client, GL520_REG_CONF) & 0x80) != 0x00)) { - dev_dbg(&new_client->dev, "Unknown chip type, skipping\n"); - goto exit_free; - } - } - - /* Fill in the remaining client fields */ - strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the GL520SM chip */ - gl520_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file_vid(new_client, 0); - - device_create_file_in(new_client, 0); - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - if (!data->two_temps) - device_create_file_in(new_client, 4); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan_off(new_client, 1); - - device_create_file_temp(new_client, 1); - if (data->two_temps) - device_create_file_temp(new_client, 2); - - device_create_file_alarms(new_client); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - - -/* Called when we have found a new GL520SM. */ -static void gl520_init_client(struct i2c_client *client) -{ - struct gl520_data *data = i2c_get_clientdata(client); - u8 oldconf, conf; - - conf = oldconf = gl520_read_value(client, GL520_REG_CONF); - - data->alarm_mask = 0xff; - data->vrm = i2c_which_vrm(); - - if (extra_sensor_type == 1) - conf &= ~0x10; - else if (extra_sensor_type == 2) - conf |= 0x10; - data->two_temps = !(conf & 0x10); - - /* If IRQ# is disabled, we can safely force comparator mode */ - if (!(conf & 0x20)) - conf &= 0xf7; - - /* Enable monitoring if needed */ - conf |= 0x40; - - if (conf != oldconf) - gl520_write_value(client, GL520_REG_CONF, conf); - - gl520_update_device(&(client->dev)); - - if (data->fan_min[0] == 0) - data->alarm_mask &= ~0x20; - if (data->fan_min[1] == 0) - data->alarm_mask &= ~0x40; - - data->beep_mask &= data->alarm_mask; - gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); -} - -static int gl520_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL520 uses a high-byte first convention */ -static int gl520_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return swab16(i2c_smbus_read_word_data(client, reg)); - else - return i2c_smbus_read_byte_data(client, reg); -} - -static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_data(client, reg, swab16(value)); - else - return i2c_smbus_write_byte_data(client, reg, value); -} - - -static struct gl520_data *gl520_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct gl520_data *data = i2c_get_clientdata(client); - int val; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - - dev_dbg(&client->dev, "Starting gl520sm update\n"); - - data->alarms = gl520_read_value(client, GL520_REG_ALARMS); - data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); - data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f; - - val = gl520_read_value(client, GL520_REG_IN0_LIMIT); - data->in_min[0] = val & 0xff; - data->in_max[0] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN1_LIMIT); - data->in_min[1] = val & 0xff; - data->in_max[1] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN2_LIMIT); - data->in_min[2] = val & 0xff; - data->in_max[2] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN3_LIMIT); - data->in_min[3] = val & 0xff; - data->in_max[3] = (val >> 8) & 0xff; - - val = gl520_read_value(client, GL520_REG_FAN_INPUT); - data->fan_input[0] = (val >> 8) & 0xff; - data->fan_input[1] = val & 0xff; - - val = gl520_read_value(client, GL520_REG_FAN_MIN); - data->fan_min[0] = (val >> 8) & 0xff; - data->fan_min[1] = val & 0xff; - - data->temp_input[0] = gl520_read_value(client, GL520_REG_TEMP1_INPUT); - data->temp_max[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX); - data->temp_max_hyst[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX_HYST); - - val = gl520_read_value(client, GL520_REG_FAN_DIV); - data->fan_div[0] = (val >> 6) & 0x03; - data->fan_div[1] = (val >> 4) & 0x03; - data->fan_off = (val >> 2) & 0x01; - - data->alarms &= data->alarm_mask; - - val = gl520_read_value(client, GL520_REG_CONF); - data->beep_enable = !((val >> 2) & 1); - - data->in_input[0] = gl520_read_value(client, GL520_REG_IN0_INPUT); - data->in_input[1] = gl520_read_value(client, GL520_REG_IN1_INPUT); - data->in_input[2] = gl520_read_value(client, GL520_REG_IN2_INPUT); - data->in_input[3] = gl520_read_value(client, GL520_REG_IN3_INPUT); - - /* Temp1 and Vin4 are the same input */ - if (data->two_temps) { - data->temp_input[1] = gl520_read_value(client, GL520_REG_TEMP2_INPUT); - data->temp_max[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX); - data->temp_max_hyst[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX_HYST); - } else { - data->in_input[4] = gl520_read_value(client, GL520_REG_IN4_INPUT); - data->in_min[4] = gl520_read_value(client, GL520_REG_IN4_MIN); - data->in_max[4] = gl520_read_value(client, GL520_REG_IN4_MAX); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - - -static int __init sensors_gl520sm_init(void) -{ - return i2c_add_driver(&gl520_driver); -} - -static void __exit sensors_gl520sm_exit(void) -{ - i2c_del_driver(&gl520_driver); -} - - -MODULE_AUTHOR("Frodo Looijaard , " - "Kyösti Mälkki , " - "Maarten Deprez "); -MODULE_DESCRIPTION("GL520SM driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_gl520sm_init); -module_exit(sensors_gl520sm_exit); diff --git a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c deleted file mode 100644 index db20c9e4739..00000000000 --- a/drivers/i2c/chips/it87.c +++ /dev/null @@ -1,1184 +0,0 @@ -/* - it87.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring. - - Supports: IT8705F Super I/O chip w/LPC interface & SMBus - IT8712F Super I/O chip w/LPC interface & SMBus - Sis950 A clone of the IT8705F - - Copyright (C) 2001 Chris Gauthron - Largely inspired by lm78.c of the same package - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - djg@pdp8.net David Gesswein 7/18/01 - Modified to fix bug with not all alarms enabled. - Added ability to read battery voltage and select temperature sensor - type at module load time. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, - 0x2e, 0x2f, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(it87, it8712); - -#define REG 0x2e /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -#define VAL 0x2f /* The value to read/write */ -#define PME 0x04 /* The device with the fan registers in it */ -#define DEVID 0x20 /* Register: Device ID */ -#define DEVREV 0x22 /* Register: Device Revision */ - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static int superio_inw(int reg) -{ - int val; - outb(reg++, REG); - val = inb(VAL) << 8; - outb(reg, REG); - val |= inb(VAL); - return val; -} - -static inline void -superio_select(void) -{ - outb(DEV, REG); - outb(PME, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x01, REG); - outb(0x55, REG); - outb(0x55, REG); -} - -static inline void -superio_exit(void) -{ - outb(0x02, REG); - outb(0x02, VAL); -} - -#define IT8712F_DEVID 0x8712 -#define IT8705F_DEVID 0x8705 -#define IT87_ACT_REG 0x30 -#define IT87_BASE_REG 0x60 - -/* Update battery voltage after every reading if true */ -static int update_vbat; - -/* Not all BIOSes properly configure the PWM registers */ -static int fix_pwm_polarity; - -/* Chip Type */ - -static u16 chip_type; - -/* Many IT87 constants specified below */ - -/* Length of ISA address segment */ -#define IT87_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define IT87_ADDR_REG_OFFSET 5 -#define IT87_DATA_REG_OFFSET 6 - -/*----- The IT87 registers -----*/ - -#define IT87_REG_CONFIG 0x00 - -#define IT87_REG_ALARM1 0x01 -#define IT87_REG_ALARM2 0x02 -#define IT87_REG_ALARM3 0x03 - -#define IT87_REG_VID 0x0a -#define IT87_REG_FAN_DIV 0x0b - -/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ - -#define IT87_REG_FAN(nr) (0x0d + (nr)) -#define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) -#define IT87_REG_FAN_MAIN_CTRL 0x13 -#define IT87_REG_FAN_CTL 0x14 -#define IT87_REG_PWM(nr) (0x15 + (nr)) - -#define IT87_REG_VIN(nr) (0x20 + (nr)) -#define IT87_REG_TEMP(nr) (0x29 + (nr)) - -#define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2) -#define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2) -#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2) -#define IT87_REG_TEMP_LOW(nr) (0x41 + (nr) * 2) - -#define IT87_REG_I2C_ADDR 0x48 - -#define IT87_REG_VIN_ENABLE 0x50 -#define IT87_REG_TEMP_ENABLE 0x51 - -#define IT87_REG_CHIPID 0x58 - -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) -#define IN_FROM_REG(val) ((val) * 16) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\ - ((val)+500)/1000),-128,127)) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) - -#define PWM_TO_REG(val) ((val) >> 1) -#define PWM_FROM_REG(val) (((val)&0x7f) << 1) - -static int DIV_TO_REG(int val) -{ - int answer = 0; - while ((val >>= 1) != 0) - answer++; - return answer; -} -#define DIV_FROM_REG(val) (1 << (val)) - - -/* For each registered IT87, we need to keep some data in memory. That - data is pointed to by it87_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new it87 client is - allocated. */ -struct it87_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[9]; /* Register value */ - u8 in_max[9]; /* Register value */ - u8 in_min[9]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp[3]; /* Register value */ - u8 temp_high[3]; /* Register value */ - u8 temp_low[3]; /* Register value */ - u8 sensor; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - int vrm; - u32 alarms; /* Register encoding, combined */ - u8 fan_main_ctrl; /* Register value */ - u8 manual_pwm_ctl[3]; /* manual PWM value set by user */ -}; - - -static int it87_attach_adapter(struct i2c_adapter *adapter); -static int it87_find(int *address); -static int it87_detect(struct i2c_adapter *adapter, int address, int kind); -static int it87_detach_client(struct i2c_client *client); - -static int it87_read_value(struct i2c_client *client, u8 register); -static int it87_write_value(struct i2c_client *client, u8 register, - u8 value); -static struct it87_data *it87_update_device(struct device *dev); -static int it87_check_pwm(struct i2c_client *client); -static void it87_init_client(struct i2c_client *client, struct it87_data *data); - - -static struct i2c_driver it87_driver = { - .owner = THIS_MODULE, - .name = "it87", - .id = I2C_DRIVERID_IT87, - .flags = I2C_DF_NOTIFY, - .attach_adapter = it87_attach_adapter, - .detach_client = it87_detach_client, -}; - -static ssize_t show_in(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); -} - -static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); -} - -static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); -} - -static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val); - it87_write_value(client, IT87_REG_VIN_MIN(nr), - data->in_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val); - it87_write_value(client, IT87_REG_VIN_MAX(nr), - data->in_max[nr]); - up(&data->update_lock); - return count; -} - -#define show_in_offset(offset) \ -static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in, NULL, offset); - -#define limit_in_offset(offset) \ -static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in_min, set_in_min, offset); \ -static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in_max, set_in_max, offset); - -show_in_offset(0); -limit_in_offset(0); -show_in_offset(1); -limit_in_offset(1); -show_in_offset(2); -limit_in_offset(2); -show_in_offset(3); -limit_in_offset(3); -show_in_offset(4); -limit_in_offset(4); -show_in_offset(5); -limit_in_offset(5); -show_in_offset(6); -limit_in_offset(6); -show_in_offset(7); -limit_in_offset(7); -show_in_offset(8); - -/* 3 temperatures */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); -} -static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); -} -static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); -} -static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_high[nr] = TEMP_TO_REG(val); - it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_low[nr] = TEMP_TO_REG(val); - it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]); - up(&data->update_lock); - return count; -} -#define show_temp_offset(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_temp, NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_max, set_temp_max, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_min, set_temp_min, offset - 1); - -show_temp_offset(1); -show_temp_offset(2); -show_temp_offset(3); - -static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - u8 reg = data->sensor; /* In case the value is updated while we use it */ - - if (reg & (1 << nr)) - return sprintf(buf, "3\n"); /* thermal diode */ - if (reg & (8 << nr)) - return sprintf(buf, "2\n"); /* thermistor */ - return sprintf(buf, "0\n"); /* disabled */ -} -static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - - data->sensor &= ~(1 << nr); - data->sensor &= ~(8 << nr); - /* 3 = thermal diode; 2 = thermistor; 0 = disabled */ - if (val == 3) - data->sensor |= 1 << nr; - else if (val == 2) - data->sensor |= 8 << nr; - else if (val != 0) { - up(&data->update_lock); - return -EINVAL; - } - it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor); - up(&data->update_lock); - return count; -} -#define show_sensor_offset(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_sensor, set_sensor, offset - 1); - -show_sensor_offset(1); -show_sensor_offset(2); -show_sensor_offset(3); - -/* 3 Fans */ -static ssize_t show_fan(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr]))); -} -static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf,"%d\n", - FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]))); -} -static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); -} -static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0); -} -static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]); -} -static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - int i, min[3]; - u8 old; - - down(&data->update_lock); - old = it87_read_value(client, IT87_REG_FAN_DIV); - - for (i = 0; i < 3; i++) - min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i])); - - switch (nr) { - case 0: - case 1: - data->fan_div[nr] = DIV_TO_REG(val); - break; - case 2: - if (val < 8) - data->fan_div[nr] = 1; - else - data->fan_div[nr] = 3; - } - val = old & 0x80; - val |= (data->fan_div[0] & 0x07); - val |= (data->fan_div[1] & 0x07) << 3; - if (data->fan_div[2] == 3) - val |= 0x1 << 6; - it87_write_value(client, IT87_REG_FAN_DIV, val); - - for (i = 0; i < 3; i++) { - data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i])); - it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]); - } - up(&data->update_lock); - return count; -} -static ssize_t set_pwm_enable(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - - if (val == 0) { - int tmp; - /* make sure the fan is on when in on/off mode */ - tmp = it87_read_value(client, IT87_REG_FAN_CTL); - it87_write_value(client, IT87_REG_FAN_CTL, tmp | (1 << nr)); - /* set on/off mode */ - data->fan_main_ctrl &= ~(1 << nr); - it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); - } else if (val == 1) { - /* set SmartGuardian mode */ - data->fan_main_ctrl |= (1 << nr); - it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); - /* set saved pwm value, clear FAN_CTLX PWM mode bit */ - it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr])); - } else { - up(&data->update_lock); - return -EINVAL; - } - - up(&data->update_lock); - return count; -} -static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - if (val < 0 || val > 255) - return -EINVAL; - - down(&data->update_lock); - data->manual_pwm_ctl[nr] = val; - if (data->fan_main_ctrl & (1 << nr)) - it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr])); - up(&data->update_lock); - return count; -} - -#define show_fan_offset(offset) \ -static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan, NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_min, set_fan_min, offset - 1); \ -static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_div, set_fan_div, offset - 1); - -show_fan_offset(1); -show_fan_offset(2); -show_fan_offset(3); - -#define show_pwm_offset(offset) \ -static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - show_pwm_enable, set_pwm_enable, offset - 1); \ -static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm, set_pwm, offset - 1); - -show_pwm_offset(1); -show_pwm_offset(2); -show_pwm_offset(3); - -/* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -static ssize_t -show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->vrm); -} -static ssize_t -store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - data->vrm = val; - - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm) - -static ssize_t -show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid) - -/* This function is called when: - * it87_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and it87_driver is still present) */ -static int it87_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, it87_detect); -} - -/* SuperIO detection - will change normal_isa[0] if a chip is found */ -static int it87_find(int *address) -{ - int err = -ENODEV; - - superio_enter(); - chip_type = superio_inw(DEVID); - if (chip_type != IT8712F_DEVID - && chip_type != IT8705F_DEVID) - goto exit; - - superio_select(); - if (!(superio_inb(IT87_ACT_REG) & 0x01)) { - pr_info("it87: Device not activated, skipping\n"); - goto exit; - } - - *address = superio_inw(IT87_BASE_REG) & ~(IT87_EXTENT - 1); - if (*address == 0) { - pr_info("it87: Base address not set, skipping\n"); - goto exit; - } - - err = 0; - pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n", - chip_type, *address, superio_inb(DEVREV) & 0x0f); - -exit: - superio_exit(); - return err; -} - -/* This function is called by i2c_detect */ -int it87_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i; - struct i2c_client *new_client; - struct it87_data *data; - int err = 0; - const char *name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - int enable_pwm_interface; - - if (!is_isa && - !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* Reserve the ISA region */ - if (is_isa) - if (!request_region(address, IT87_EXTENT, it87_driver.name)) - goto ERROR0; - - /* Probe whether there is anything available on this address. Already - done for SMBus and Super-I/O clients */ - if (kind < 0) { - if (is_isa && !chip_type) { -#define REALLY_SLOW_IO - /* We need the timeouts for at least some IT87-like chips. But only - if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i - || inb_p(address + 3) != i - || inb_p(address + 7) != i) { - err = -ENODEV; - goto ERROR1; - } -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - err = -ENODEV; - goto ERROR1; - } - } - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access it87_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct it87_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR1; - } - memset(data, 0, sizeof(struct it87_data)); - - new_client = &data->client; - if (is_isa) - init_MUTEX(&data->lock); - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &it87_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80) - || (!is_isa - && it87_read_value(new_client, IT87_REG_I2C_ADDR) != address)) { - err = -ENODEV; - goto ERROR2; - } - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = it87_read_value(new_client, IT87_REG_CHIPID); - if (i == 0x90) { - kind = it87; - if ((is_isa) && (chip_type == IT8712F_DEVID)) - kind = it8712; - } - else { - if (kind == 0) - dev_info(&adapter->dev, - "Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - err = -ENODEV; - goto ERROR2; - } - } - - if (kind == it87) { - name = "it87"; - } else if (kind == it8712) { - name = "it8712"; - } - - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - /* Check PWM configuration */ - enable_pwm_interface = it87_check_pwm(new_client); - - /* Initialize the IT87 chip */ - it87_init_client(new_client, data); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); - device_create_file(&new_client->dev, &dev_attr_alarms); - if (enable_pwm_interface) { - device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); - } - - if (data->type == it8712) { - data->vrm = i2c_which_vrm(); - device_create_file_vrm(new_client); - device_create_file_vid(new_client); - } - - return 0; - -ERROR2: - kfree(data); -ERROR1: - if (is_isa) - release_region(address, IT87_EXTENT); -ERROR0: - return err; -} - -static int it87_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - - if(i2c_is_isa_client(client)) - release_region(client->addr, IT87_EXTENT); - kfree(i2c_get_clientdata(client)); - - return 0; -} - -/* The SMBus locks itself, but ISA access must be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. */ -static int it87_read_value(struct i2c_client *client, u8 reg) -{ - struct it87_data *data = i2c_get_clientdata(client); - - int res; - if (i2c_is_isa_client(client)) { - down(&data->lock); - outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); - res = inb_p(client->addr + IT87_DATA_REG_OFFSET); - up(&data->lock); - return res; - } else - return i2c_smbus_read_byte_data(client, reg); -} - -/* The SMBus locks itself, but ISA access muse be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. */ -static int it87_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - struct it87_data *data = i2c_get_clientdata(client); - - if (i2c_is_isa_client(client)) { - down(&data->lock); - outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); - outb_p(value, client->addr + IT87_DATA_REG_OFFSET); - up(&data->lock); - return 0; - } else - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Return 1 if and only if the PWM interface is safe to use */ -static int it87_check_pwm(struct i2c_client *client) -{ - /* Some BIOSes fail to correctly configure the IT87 fans. All fans off - * and polarity set to active low is sign that this is the case so we - * disable pwm control to protect the user. */ - int tmp = it87_read_value(client, IT87_REG_FAN_CTL); - if ((tmp & 0x87) == 0) { - if (fix_pwm_polarity) { - /* The user asks us to attempt a chip reconfiguration. - * This means switching to active high polarity and - * inverting all fan speed values. */ - int i; - u8 pwm[3]; - - for (i = 0; i < 3; i++) - pwm[i] = it87_read_value(client, - IT87_REG_PWM(i)); - - /* If any fan is in automatic pwm mode, the polarity - * might be correct, as suspicious as it seems, so we - * better don't change anything (but still disable the - * PWM interface). */ - if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) { - dev_info(&client->dev, "Reconfiguring PWM to " - "active high polarity\n"); - it87_write_value(client, IT87_REG_FAN_CTL, - tmp | 0x87); - for (i = 0; i < 3; i++) - it87_write_value(client, - IT87_REG_PWM(i), - 0x7f & ~pwm[i]); - return 1; - } - - dev_info(&client->dev, "PWM configuration is " - "too broken to be fixed\n"); - } - - dev_info(&client->dev, "Detected broken BIOS " - "defaults, disabling PWM interface\n"); - return 0; - } else if (fix_pwm_polarity) { - dev_info(&client->dev, "PWM configuration looks " - "sane, won't touch\n"); - } - - return 1; -} - -/* Called when we have found a new IT87. */ -static void it87_init_client(struct i2c_client *client, struct it87_data *data) -{ - int tmp, i; - - /* initialize to sane defaults: - * - if the chip is in manual pwm mode, this will be overwritten with - * the actual settings on the chip (so in this case, initialization - * is not needed) - * - if in automatic or on/off mode, we could switch to manual mode, - * read the registers and set manual_pwm_ctl accordingly, but currently - * this is not implemented, so we initialize to something sane */ - for (i = 0; i < 3; i++) { - data->manual_pwm_ctl[i] = 0xff; - } - - /* Check if temperature channnels are reset manually or by some reason */ - tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE); - if ((tmp & 0x3f) == 0) { - /* Temp1,Temp3=thermistor; Temp2=thermal diode */ - tmp = (tmp & 0xc0) | 0x2a; - it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp); - } - data->sensor = tmp; - - /* Check if voltage monitors are reset manually or by some reason */ - tmp = it87_read_value(client, IT87_REG_VIN_ENABLE); - if ((tmp & 0xff) == 0) { - /* Enable all voltage monitors */ - it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff); - } - - /* Check if tachometers are reset manually or by some reason */ - data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL); - if ((data->fan_main_ctrl & 0x70) == 0) { - /* Enable all fan tachometers */ - data->fan_main_ctrl |= 0x70; - it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); - } - - /* Set current fan mode registers and the default settings for the - * other mode registers */ - for (i = 0; i < 3; i++) { - if (data->fan_main_ctrl & (1 << i)) { - /* pwm mode */ - tmp = it87_read_value(client, IT87_REG_PWM(i)); - if (tmp & 0x80) { - /* automatic pwm - not yet implemented, but - * leave the settings made by the BIOS alone - * until a change is requested via the sysfs - * interface */ - } else { - /* manual pwm */ - data->manual_pwm_ctl[i] = PWM_FROM_REG(tmp); - } - } - } - - /* Start monitoring */ - it87_write_value(client, IT87_REG_CONFIG, - (it87_read_value(client, IT87_REG_CONFIG) & 0x36) - | (update_vbat ? 0x41 : 0x01)); -} - -static struct it87_data *it87_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct it87_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - if (update_vbat) { - /* Cleared after each update, so reenable. Value - returned by this read will be previous value */ - it87_write_value(client, IT87_REG_CONFIG, - it87_read_value(client, IT87_REG_CONFIG) | 0x40); - } - for (i = 0; i <= 7; i++) { - data->in[i] = - it87_read_value(client, IT87_REG_VIN(i)); - data->in_min[i] = - it87_read_value(client, IT87_REG_VIN_MIN(i)); - data->in_max[i] = - it87_read_value(client, IT87_REG_VIN_MAX(i)); - } - data->in[8] = - it87_read_value(client, IT87_REG_VIN(8)); - /* Temperature sensor doesn't have limit registers, set - to min and max value */ - data->in_min[8] = 0; - data->in_max[8] = 255; - - for (i = 0; i < 3; i++) { - data->fan[i] = - it87_read_value(client, IT87_REG_FAN(i)); - data->fan_min[i] = - it87_read_value(client, IT87_REG_FAN_MIN(i)); - } - for (i = 0; i < 3; i++) { - data->temp[i] = - it87_read_value(client, IT87_REG_TEMP(i)); - data->temp_high[i] = - it87_read_value(client, IT87_REG_TEMP_HIGH(i)); - data->temp_low[i] = - it87_read_value(client, IT87_REG_TEMP_LOW(i)); - } - - i = it87_read_value(client, IT87_REG_FAN_DIV); - data->fan_div[0] = i & 0x07; - data->fan_div[1] = (i >> 3) & 0x07; - data->fan_div[2] = (i & 0x40) ? 3 : 1; - - data->alarms = - it87_read_value(client, IT87_REG_ALARM1) | - (it87_read_value(client, IT87_REG_ALARM2) << 8) | - (it87_read_value(client, IT87_REG_ALARM3) << 16); - data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL); - - data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE); - /* The 8705 does not have VID capability */ - if (data->type == it8712) { - data->vid = it87_read_value(client, IT87_REG_VID); - data->vid &= 0x1f; - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sm_it87_init(void) -{ - int addr; - - if (!it87_find(&addr)) { - normal_isa[0] = addr; - } - return i2c_add_driver(&it87_driver); -} - -static void __exit sm_it87_exit(void) -{ - i2c_del_driver(&it87_driver); -} - - -MODULE_AUTHOR("Chris Gauthron "); -MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver"); -module_param(update_vbat, bool, 0); -MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); -module_param(fix_pwm_polarity, bool, 0); -MODULE_PARM_DESC(fix_pwm_polarity, "Force PWM polarity to active high (DANGEROUS)"); -MODULE_LICENSE("GPL"); - -module_init(sm_it87_init); -module_exit(sm_it87_exit); diff --git a/drivers/i2c/chips/lm63.c b/drivers/i2c/chips/lm63.c deleted file mode 100644 index 7c6f9ea5a25..00000000000 --- a/drivers/i2c/chips/lm63.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * lm63.c - driver for the National Semiconductor LM63 temperature sensor - * with integrated fan control - * Copyright (C) 2004-2005 Jean Delvare - * Based on the lm90 driver. - * - * The LM63 is a sensor chip made by National Semiconductor. It measures - * two temperatures (its own and one external one) and the speed of one - * fan, those speed it can additionally control. Complete datasheet can be - * obtained from National's website at: - * http://www.national.com/pf/LM/LM63.html - * - * The LM63 is basically an LM86 with fan speed monitoring and control - * capabilities added. It misses some of the LM86 features though: - * - No low limit for local temperature. - * - No critical limit for local temperature. - * - Critical limit for remote temperature can be changed only once. We - * will consider that the critical limit is read-only. - * - * The datasheet isn't very clear about what the tachometer reading is. - * I had a explanation from National Semiconductor though. The two lower - * bits of the read value have to be masked out. The value is still 16 bit - * in width. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Addresses to scan - * Address is fully defined internally and cannot be changed. - */ - -static unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(lm63); - -/* - * The LM63 registers - */ - -#define LM63_REG_CONFIG1 0x03 -#define LM63_REG_CONFIG2 0xBF -#define LM63_REG_CONFIG_FAN 0x4A - -#define LM63_REG_TACH_COUNT_MSB 0x47 -#define LM63_REG_TACH_COUNT_LSB 0x46 -#define LM63_REG_TACH_LIMIT_MSB 0x49 -#define LM63_REG_TACH_LIMIT_LSB 0x48 - -#define LM63_REG_PWM_VALUE 0x4C -#define LM63_REG_PWM_FREQ 0x4D - -#define LM63_REG_LOCAL_TEMP 0x00 -#define LM63_REG_LOCAL_HIGH 0x05 - -#define LM63_REG_REMOTE_TEMP_MSB 0x01 -#define LM63_REG_REMOTE_TEMP_LSB 0x10 -#define LM63_REG_REMOTE_OFFSET_MSB 0x11 -#define LM63_REG_REMOTE_OFFSET_LSB 0x12 -#define LM63_REG_REMOTE_HIGH_MSB 0x07 -#define LM63_REG_REMOTE_HIGH_LSB 0x13 -#define LM63_REG_REMOTE_LOW_MSB 0x08 -#define LM63_REG_REMOTE_LOW_LSB 0x14 -#define LM63_REG_REMOTE_TCRIT 0x19 -#define LM63_REG_REMOTE_TCRIT_HYST 0x21 - -#define LM63_REG_ALERT_STATUS 0x02 -#define LM63_REG_ALERT_MASK 0x16 - -#define LM63_REG_MAN_ID 0xFE -#define LM63_REG_CHIP_ID 0xFF - -/* - * Conversions and various macros - * For tachometer counts, the LM63 uses 16-bit values. - * For local temperature and high limit, remote critical limit and hysteresis - * value, it uses signed 8-bit values with LSB = 1 degree Celsius. - * For remote temperature, low and high limits, it uses signed 11-bit values - * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers. - */ - -#define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ - 5400000 / (reg)) -#define FAN_TO_REG(val) ((val) <= 82 ? 0xFFFC : \ - (5400000 / (val)) & 0xFFFC) -#define TEMP8_FROM_REG(reg) ((reg) * 1000) -#define TEMP8_TO_REG(val) ((val) <= -128000 ? -128 : \ - (val) >= 127000 ? 127 : \ - (val) < 0 ? ((val) - 500) / 1000 : \ - ((val) + 500) / 1000) -#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) -#define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ - (val) >= 127875 ? 0x7FE0 : \ - (val) < 0 ? ((val) - 62) / 125 * 32 : \ - ((val) + 62) / 125 * 32) -#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ - (val) >= 127000 ? 127 : \ - ((val) + 500) / 1000) - -/* - * Functions declaration - */ - -static int lm63_attach_adapter(struct i2c_adapter *adapter); -static int lm63_detach_client(struct i2c_client *client); - -static struct lm63_data *lm63_update_device(struct device *dev); - -static int lm63_detect(struct i2c_adapter *adapter, int address, int kind); -static void lm63_init_client(struct i2c_client *client); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm63_driver = { - .owner = THIS_MODULE, - .name = "lm63", - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm63_attach_adapter, - .detach_client = lm63_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm63_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - u8 config, config_fan; - u16 fan[2]; /* 0: input - 1: low limit */ - u8 pwm1_freq; - u8 pwm1_value; - s8 temp8[3]; /* 0: local input - 1: local high limit - 2: remote critical limit */ - s16 temp11[3]; /* 0: remote input - 1: remote low limit - 2: remote high limit */ - u8 temp2_crit_hyst; - u8 alarms; -}; - -/* - * Sysfs callback functions and files - */ - -static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index])); -} - -static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan[1] = FAN_TO_REG(val); - i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB, - data->fan[1] & 0xFF); - i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB, - data->fan[1] >> 8); - up(&data->update_lock); - return count; -} - -static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? - 255 : (data->pwm1_value * 255 + data->pwm1_freq) / - (2 * data->pwm1_freq)); -} - -static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - unsigned long val; - - if (!(data->config_fan & 0x20)) /* register is read-only */ - return -EPERM; - - val = simple_strtoul(buf, NULL, 10); - down(&data->update_lock); - data->pwm1_value = val <= 0 ? 0 : - val >= 255 ? 2 * data->pwm1_freq : - (val * data->pwm1_freq * 2 + 127) / 255; - i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value); - up(&data->update_lock); - return count; -} - -static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); -} - -static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])); -} - -static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp8[1] = TEMP8_TO_REG(val); - i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); - up(&data->update_lock); - return count; -} - -static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])); -} - -static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - static const u8 reg[4] = { - LM63_REG_REMOTE_LOW_MSB, - LM63_REG_REMOTE_LOW_LSB, - LM63_REG_REMOTE_HIGH_MSB, - LM63_REG_REMOTE_HIGH_LSB, - }; - - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - int nr = attr->index; - - down(&data->update_lock); - data->temp11[nr] = TEMP11_TO_REG(val); - i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], - data->temp11[nr] >> 8); - i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], - data->temp11[nr] & 0xff); - up(&data->update_lock); - return count; -} - -/* Hysteresis register holds a relative value, while we want to present - an absolute to user-space */ -static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2]) - - TEMP8_FROM_REG(data->temp2_crit_hyst)); -} - -/* And now the other way around, user-space provides an absolute - hysteresis value and we have to store a relative one */ -static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - long hyst; - - down(&data->update_lock); - hyst = TEMP8_FROM_REG(data->temp8[2]) - val; - i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, - HYST_TO_REG(hyst)); - up(&data->update_lock); - return count; -} - -static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} - -static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); -static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, - set_fan, 1); - -static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); -static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); - -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 1); - -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); -static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 1); -static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 2); -static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2); -static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, - set_temp2_crit_hyst); - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* - * Real code - */ - -static int lm63_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm63_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm63_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct lm63_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm63_data)); - - /* The common I2C client data is placed right before the - LM63-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm63_driver; - new_client->flags = 0; - - /* Default to an LM63 if forced */ - if (kind == 0) - kind = lm63; - - if (kind < 0) { /* must identify */ - u8 man_id, chip_id, reg_config1, reg_config2; - u8 reg_alert_status, reg_alert_mask; - - man_id = i2c_smbus_read_byte_data(new_client, - LM63_REG_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - LM63_REG_CHIP_ID); - reg_config1 = i2c_smbus_read_byte_data(new_client, - LM63_REG_CONFIG1); - reg_config2 = i2c_smbus_read_byte_data(new_client, - LM63_REG_CONFIG2); - reg_alert_status = i2c_smbus_read_byte_data(new_client, - LM63_REG_ALERT_STATUS); - reg_alert_mask = i2c_smbus_read_byte_data(new_client, - LM63_REG_ALERT_MASK); - - if (man_id == 0x01 /* National Semiconductor */ - && chip_id == 0x41 /* LM63 */ - && (reg_config1 & 0x18) == 0x00 - && (reg_config2 & 0xF8) == 0x00 - && (reg_alert_status & 0x20) == 0x00 - && (reg_alert_mask & 0xA4) == 0xA4) { - kind = lm63; - } else { /* failed */ - dev_dbg(&adapter->dev, "Unsupported chip " - "(man_id=0x%02X, chip_id=0x%02X).\n", - man_id, chip_id); - goto exit_free; - } - } - - strlcpy(new_client->name, "lm63", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the LM63 chip */ - lm63_init_client(new_client); - - /* Register sysfs hooks */ - if (data->config & 0x04) { /* tachometer enabled */ - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_min.dev_attr); - } - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -/* Idealy we shouldn't have to initialize anything, since the BIOS - should have taken care of everything */ -static void lm63_init_client(struct i2c_client *client) -{ - struct lm63_data *data = i2c_get_clientdata(client); - - data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); - data->config_fan = i2c_smbus_read_byte_data(client, - LM63_REG_CONFIG_FAN); - - /* Start converting if needed */ - if (data->config & 0x40) { /* standby */ - dev_dbg(&client->dev, "Switching to operational mode"); - data->config &= 0xA7; - i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1, - data->config); - } - - /* We may need pwm1_freq before ever updating the client data */ - data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ); - if (data->pwm1_freq == 0) - data->pwm1_freq = 1; - - /* Show some debug info about the LM63 configuration */ - dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", - (data->config & 0x04) ? "tachometer input" : - "alert output"); - dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n", - (data->config_fan & 0x08) ? "1.4" : "360", - ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq); - dev_dbg(&client->dev, "PWM output active %s, %s mode\n", - (data->config_fan & 0x10) ? "low" : "high", - (data->config_fan & 0x20) ? "manual" : "auto"); -} - -static int lm63_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - -static struct lm63_data *lm63_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm63_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - if (data->config & 0x04) { /* tachometer enabled */ - /* order matters for fan1_input */ - data->fan[0] = i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_LSB) & 0xFC; - data->fan[0] |= i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_MSB) << 8; - data->fan[1] = (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_LSB) & 0xFC) - | (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_MSB) << 8); - } - - data->pwm1_freq = i2c_smbus_read_byte_data(client, - LM63_REG_PWM_FREQ); - if (data->pwm1_freq == 0) - data->pwm1_freq = 1; - data->pwm1_value = i2c_smbus_read_byte_data(client, - LM63_REG_PWM_VALUE); - - data->temp8[0] = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_TEMP); - data->temp8[1] = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_HIGH); - - /* order matters for temp2_input */ - data->temp11[0] = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_MSB) << 8; - data->temp11[0] |= i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_LSB); - data->temp11[1] = (i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_LOW_MSB) << 8) - | i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_LOW_LSB); - data->temp11[2] = (i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_MSB) << 8) - | i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_LSB); - data->temp8[2] = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TCRIT); - data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TCRIT_HYST); - - data->alarms = i2c_smbus_read_byte_data(client, - LM63_REG_ALERT_STATUS) & 0x7F; - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm63_init(void) -{ - return i2c_add_driver(&lm63_driver); -} - -static void __exit sensors_lm63_exit(void) -{ - i2c_del_driver(&lm63_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM63 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm63_init); -module_exit(sensors_lm63_exit); diff --git a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c deleted file mode 100644 index 5be164ed278..00000000000 --- a/drivers/i2c/chips/lm75.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - lm75.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include "lm75.h" - - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, - 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm75); - -/* Many LM75 constants specified below */ - -/* The LM75 registers */ -#define LM75_REG_TEMP 0x00 -#define LM75_REG_CONF 0x01 -#define LM75_REG_TEMP_HYST 0x02 -#define LM75_REG_TEMP_OS 0x03 - -/* Each client has this additional data */ -struct lm75_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - u16 temp_input; /* Register values */ - u16 temp_max; - u16 temp_hyst; -}; - -static int lm75_attach_adapter(struct i2c_adapter *adapter); -static int lm75_detect(struct i2c_adapter *adapter, int address, int kind); -static void lm75_init_client(struct i2c_client *client); -static int lm75_detach_client(struct i2c_client *client); -static int lm75_read_value(struct i2c_client *client, u8 reg); -static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); -static struct lm75_data *lm75_update_device(struct device *dev); - - -/* This is the driver that will be inserted */ -static struct i2c_driver lm75_driver = { - .owner = THIS_MODULE, - .name = "lm75", - .id = I2C_DRIVERID_LM75, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm75_attach_adapter, - .detach_client = lm75_detach_client, -}; - -#define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm75_data *data = lm75_update_device(dev); \ - return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \ -} -show(temp_max); -show(temp_hyst); -show(temp_input); - -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm75_data *data = i2c_get_clientdata(client); \ - int temp = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = LM75_TEMP_TO_REG(temp); \ - lm75_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} -set(temp_max, LM75_REG_TEMP_OS); -set(temp_hyst, LM75_REG_TEMP_HYST); - -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); - -static int lm75_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm75_detect); -} - -/* This function is called by i2c_detect */ -static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i; - struct i2c_client *new_client; - struct lm75_data *data; - int err = 0; - const char *name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - dev_dbg(&adapter->dev, - "lm75_detect called for an ISA bus adapter?!?\n"); - goto exit; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm75_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm75_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm75_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm75_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. There is no identification- - dedicated register so we have to rely on several tricks: - unused bits, registers cycling over 8-address boundaries, - addresses 0x04-0x07 returning the last read value. - The cycling+unused addresses combination is not tested, - since it would significantly slow the detection down and would - hardly add any value. */ - if (kind < 0) { - int cur, conf, hyst, os; - - /* Unused addresses */ - cur = i2c_smbus_read_word_data(new_client, 0); - conf = i2c_smbus_read_byte_data(new_client, 1); - hyst = i2c_smbus_read_word_data(new_client, 2); - if (i2c_smbus_read_word_data(new_client, 4) != hyst - || i2c_smbus_read_word_data(new_client, 5) != hyst - || i2c_smbus_read_word_data(new_client, 6) != hyst - || i2c_smbus_read_word_data(new_client, 7) != hyst) - goto exit_free; - os = i2c_smbus_read_word_data(new_client, 3); - if (i2c_smbus_read_word_data(new_client, 4) != os - || i2c_smbus_read_word_data(new_client, 5) != os - || i2c_smbus_read_word_data(new_client, 6) != os - || i2c_smbus_read_word_data(new_client, 7) != os) - goto exit_free; - - /* Unused bits */ - if (conf & 0xe0) - goto exit_free; - - /* Addresses cycling */ - for (i = 8; i < 0xff; i += 8) - if (i2c_smbus_read_byte_data(new_client, i + 1) != conf - || i2c_smbus_read_word_data(new_client, i + 2) != hyst - || i2c_smbus_read_word_data(new_client, i + 3) != os) - goto exit_free; - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = lm75; - - if (kind == lm75) { - name = "lm75"; - } - - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the LM75 chip */ - lm75_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int lm75_detach_client(struct i2c_client *client) -{ - i2c_detach_client(client); - kfree(i2c_get_clientdata(client)); - return 0; -} - -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int lm75_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == LM75_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return swab16(i2c_smbus_read_word_data(client, reg)); -} - -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == LM75_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - -static void lm75_init_client(struct i2c_client *client) -{ - /* Initialize the LM75 chip */ - lm75_write_value(client, LM75_REG_CONF, 0); -} - -static struct lm75_data *lm75_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm75_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting lm75 update\n"); - - data->temp_input = lm75_read_value(client, LM75_REG_TEMP); - data->temp_max = lm75_read_value(client, LM75_REG_TEMP_OS); - data->temp_hyst = lm75_read_value(client, LM75_REG_TEMP_HYST); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm75_init(void) -{ - return i2c_add_driver(&lm75_driver); -} - -static void __exit sensors_lm75_exit(void) -{ - i2c_del_driver(&lm75_driver); -} - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM75 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm75_init); -module_exit(sensors_lm75_exit); diff --git a/drivers/i2c/chips/lm75.h b/drivers/i2c/chips/lm75.h deleted file mode 100644 index 63e3f2fb4c2..00000000000 --- a/drivers/i2c/chips/lm75.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - lm75.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2003 Mark M. Hoffman - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This file contains common code for encoding/decoding LM75 type - temperature readings, which are emulated by many of the chips - we support. As the user is unlikely to load more than one driver - which contains this code, we don't worry about the wasted space. -*/ - -#include - -/* straight from the datasheet */ -#define LM75_TEMP_MIN (-55000) -#define LM75_TEMP_MAX 125000 - -/* TEMP: 0.001C/bit (-55C to +125C) - REG: (0.5C/bit, two's complement) << 7 */ -static inline u16 LM75_TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); - ntemp += (ntemp<0 ? -250 : 250); - return (u16)((ntemp / 500) << 7); -} - -static inline int LM75_TEMP_FROM_REG(u16 reg) -{ - /* use integer division instead of equivalent right shift to - guarantee arithmetic shift and preserve the sign */ - return ((s16)reg / 128) * 500; -} - diff --git a/drivers/i2c/chips/lm77.c b/drivers/i2c/chips/lm77.c deleted file mode 100644 index b98f4495299..00000000000 --- a/drivers/i2c/chips/lm77.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - lm77.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (c) 2004 Andras BALI - - Heavily based on lm75.c by Frodo Looijaard . The LM77 - is a temperature sensor and thermal window comparator with 0.5 deg - resolution made by National Semiconductor. Complete datasheet can be - obtained at their site: - http://www.national.com/pf/LM/LM77.html - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include - - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm77); - -/* The LM77 registers */ -#define LM77_REG_TEMP 0x00 -#define LM77_REG_CONF 0x01 -#define LM77_REG_TEMP_HYST 0x02 -#define LM77_REG_TEMP_CRIT 0x03 -#define LM77_REG_TEMP_MIN 0x04 -#define LM77_REG_TEMP_MAX 0x05 - -/* Each client has this additional data */ -struct lm77_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; - unsigned long last_updated; /* In jiffies */ - int temp_input; /* Temperatures */ - int temp_crit; - int temp_min; - int temp_max; - int temp_hyst; - u8 alarms; -}; - -static int lm77_attach_adapter(struct i2c_adapter *adapter); -static int lm77_detect(struct i2c_adapter *adapter, int address, int kind); -static void lm77_init_client(struct i2c_client *client); -static int lm77_detach_client(struct i2c_client *client); -static u16 lm77_read_value(struct i2c_client *client, u8 reg); -static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value); - -static struct lm77_data *lm77_update_device(struct device *dev); - - -/* This is the driver that will be inserted */ -static struct i2c_driver lm77_driver = { - .owner = THIS_MODULE, - .name = "lm77", - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm77_attach_adapter, - .detach_client = lm77_detach_client, -}; - -/* straight from the datasheet */ -#define LM77_TEMP_MIN (-55000) -#define LM77_TEMP_MAX 125000 - -/* In the temperature registers, the low 3 bits are not part of the - temperature values; they are the status bits. */ -static inline u16 LM77_TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX); - return (u16)((ntemp / 500) * 8); -} - -static inline int LM77_TEMP_FROM_REG(u16 reg) -{ - return ((int)reg / 8) * 500; -} - -/* sysfs stuff */ - -/* read routines for temperature limits */ -#define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm77_data *data = lm77_update_device(dev); \ - return sprintf(buf, "%d\n", data->value); \ -} - -show(temp_input); -show(temp_crit); -show(temp_min); -show(temp_max); -show(alarms); - -/* read routines for hysteresis values */ -static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst); -} -static ssize_t show_temp_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst); -} -static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm77_data *data = lm77_update_device(dev); - return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst); -} - -/* write routines */ -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm77_data *data = i2c_get_clientdata(client); \ - long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = val; \ - lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \ - up(&data->update_lock); \ - return count; \ -} - -set(temp_min, LM77_REG_TEMP_MIN); -set(temp_max, LM77_REG_TEMP_MAX); - -/* hysteresis is stored as a relative value on the chip, so it has to be - converted first */ -static ssize_t set_temp_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->temp_hyst = data->temp_crit - val; - lm77_write_value(client, LM77_REG_TEMP_HYST, - LM77_TEMP_TO_REG(data->temp_hyst)); - up(&data->update_lock); - return count; -} - -/* preserve hysteresis when setting T_crit */ -static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - long val = simple_strtoul(buf, NULL, 10); - int oldcrithyst; - - down(&data->update_lock); - oldcrithyst = data->temp_crit - data->temp_hyst; - data->temp_crit = val; - data->temp_hyst = data->temp_crit - oldcrithyst; - lm77_write_value(client, LM77_REG_TEMP_CRIT, - LM77_TEMP_TO_REG(data->temp_crit)); - lm77_write_value(client, LM77_REG_TEMP_HYST, - LM77_TEMP_TO_REG(data->temp_hyst)); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, - show_temp_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, - show_temp_crit, set_temp_crit); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, - show_temp_min, set_temp_min); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, - show_temp_max, set_temp_max); - -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, - show_temp_crit_hyst, set_temp_crit_hyst); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, - show_temp_min_hyst, NULL); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, - show_temp_max_hyst, NULL); - -static DEVICE_ATTR(alarms, S_IRUGO, - show_alarms, NULL); - -static int lm77_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm77_detect); -} - -/* This function is called by i2c_detect */ -static int lm77_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm77_data *data; - int err = 0; - const char *name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm77_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm77_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm77_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm77_driver; - new_client->flags = 0; - - /* Here comes the remaining detection. Since the LM77 has no - register dedicated to identification, we have to rely on the - following tricks: - - 1. the high 4 bits represent the sign and thus they should - always be the same - 2. the high 3 bits are unused in the configuration register - 3. addresses 0x06 and 0x07 return the last read value - 4. registers cycling over 8-address boundaries - - Word-sized registers are high-byte first. */ - if (kind < 0) { - int i, cur, conf, hyst, crit, min, max; - - /* addresses cycling */ - cur = i2c_smbus_read_word_data(new_client, 0); - conf = i2c_smbus_read_byte_data(new_client, 1); - hyst = i2c_smbus_read_word_data(new_client, 2); - crit = i2c_smbus_read_word_data(new_client, 3); - min = i2c_smbus_read_word_data(new_client, 4); - max = i2c_smbus_read_word_data(new_client, 5); - for (i = 8; i <= 0xff; i += 8) - if (i2c_smbus_read_byte_data(new_client, i + 1) != conf - || i2c_smbus_read_word_data(new_client, i + 2) != hyst - || i2c_smbus_read_word_data(new_client, i + 3) != crit - || i2c_smbus_read_word_data(new_client, i + 4) != min - || i2c_smbus_read_word_data(new_client, i + 5) != max) - goto exit_free; - - /* sign bits */ - if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0) - || ((hyst & 0x00f0) != 0xf0 && (hyst & 0x00f0) != 0x0) - || ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0) - || ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0) - || ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0)) - goto exit_free; - - /* unused bits */ - if (conf & 0xe0) - goto exit_free; - - /* 0x06 and 0x07 return the last read value */ - cur = i2c_smbus_read_word_data(new_client, 0); - if (i2c_smbus_read_word_data(new_client, 6) != cur - || i2c_smbus_read_word_data(new_client, 7) != cur) - goto exit_free; - hyst = i2c_smbus_read_word_data(new_client, 2); - if (i2c_smbus_read_word_data(new_client, 6) != hyst - || i2c_smbus_read_word_data(new_client, 7) != hyst) - goto exit_free; - min = i2c_smbus_read_word_data(new_client, 4); - if (i2c_smbus_read_word_data(new_client, 6) != min - || i2c_smbus_read_word_data(new_client, 7) != min) - goto exit_free; - - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = lm77; - - if (kind == lm77) { - name = "lm77"; - } - - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the LM77 chip */ - lm77_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int lm77_detach_client(struct i2c_client *client) -{ - i2c_detach_client(client); - kfree(i2c_get_clientdata(client)); - return 0; -} - -/* All registers are word-sized, except for the configuration register. - The LM77 uses the high-byte first convention. */ -static u16 lm77_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == LM77_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return swab16(i2c_smbus_read_word_data(client, reg)); -} - -static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == LM77_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - -static void lm77_init_client(struct i2c_client *client) -{ - /* Initialize the LM77 chip - turn off shutdown mode */ - int conf = lm77_read_value(client, LM77_REG_CONF); - if (conf & 1) - lm77_write_value(client, LM77_REG_CONF, conf & 0xfe); -} - -static struct lm77_data *lm77_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm77_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting lm77 update\n"); - data->temp_input = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP)); - data->temp_hyst = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_HYST)); - data->temp_crit = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_CRIT)); - data->temp_min = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MIN)); - data->temp_max = - LM77_TEMP_FROM_REG(lm77_read_value(client, - LM77_REG_TEMP_MAX)); - data->alarms = - lm77_read_value(client, LM77_REG_TEMP) & 0x0007; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm77_init(void) -{ - return i2c_add_driver(&lm77_driver); -} - -static void __exit sensors_lm77_exit(void) -{ - i2c_del_driver(&lm77_driver); -} - -MODULE_AUTHOR("Andras BALI "); -MODULE_DESCRIPTION("LM77 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm77_init); -module_exit(sensors_lm77_exit); diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c deleted file mode 100644 index 29241469dcb..00000000000 --- a/drivers/i2c/chips/lm78.c +++ /dev/null @@ -1,795 +0,0 @@ -/* - lm78.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, - 0x25, 0x26, 0x27, 0x28, 0x29, - 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_3(lm78, lm78j, lm79); - -/* Many LM78 constants specified below */ - -/* Length of ISA address segment */ -#define LM78_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define LM78_ADDR_REG_OFFSET 5 -#define LM78_DATA_REG_OFFSET 6 - -/* The LM78 registers */ -#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define LM78_REG_IN(nr) (0x20 + (nr)) - -#define LM78_REG_FAN_MIN(nr) (0x3b + (nr)) -#define LM78_REG_FAN(nr) (0x28 + (nr)) - -#define LM78_REG_TEMP 0x27 -#define LM78_REG_TEMP_OVER 0x39 -#define LM78_REG_TEMP_HYST 0x3a - -#define LM78_REG_ALARM1 0x41 -#define LM78_REG_ALARM2 0x42 - -#define LM78_REG_VID_FANDIV 0x47 - -#define LM78_REG_CONFIG 0x40 -#define LM78_REG_CHIPID 0x49 -#define LM78_REG_I2C_ADDR 0x48 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. */ - -/* IN: mV, (0V to 4.08V) - REG: 16mV/bit */ -static inline u8 IN_TO_REG(unsigned long val) -{ - unsigned long nval = SENSORS_LIMIT(val, 0, 4080); - return (nval + 8) / 16; -} -#define IN_FROM_REG(val) ((val) * 16) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm <= 0) - return 255; - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); -} - -static inline int FAN_FROM_REG(u8 val, int div) -{ - return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); -} - -/* TEMP: mC (-128C to +127C) - REG: 1C/bit, two's complement */ -static inline s8 TEMP_TO_REG(int val) -{ - int nval = SENSORS_LIMIT(val, -128000, 127000) ; - return nval<0 ? (nval-500)/1000 : (nval+500)/1000; -} - -static inline int TEMP_FROM_REG(s8 val) -{ - return val * 1000; -} - -/* VID: mV - REG: (see doc/vid) */ -static inline int VID_FROM_REG(u8 val) -{ - return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50; -} - -#define DIV_FROM_REG(val) (1 << (val)) - -/* There are some complications in a module like this. First off, LM78 chips - may be both present on the SMBus and the ISA bus, and we have to handle - those cases separately at some places. Second, there might be several - LM78 chips available (well, actually, that is probably never done; but - it is a clean illustration of how to handle a case like that). Finally, - a specific chip may be attached to *both* ISA and SMBus, and we would - not like to detect it double. Fortunately, in the case of the LM78 at - least, a register tells us what SMBus address we are on, so that helps - a bit - except if there could be more than one SMBus. Groan. No solution - for this yet. */ - -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* For each registered LM78, we need to keep some data in memory. That - data is pointed to by lm78_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new lm78 client is - allocated. */ -struct lm78_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - s8 temp; /* Register value */ - s8 temp_over; /* Register value */ - s8 temp_hyst; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u16 alarms; /* Register encoding, combined */ -}; - - -static int lm78_attach_adapter(struct i2c_adapter *adapter); -static int lm78_detect(struct i2c_adapter *adapter, int address, int kind); -static int lm78_detach_client(struct i2c_client *client); - -static int lm78_read_value(struct i2c_client *client, u8 register); -static int lm78_write_value(struct i2c_client *client, u8 register, u8 value); -static struct lm78_data *lm78_update_device(struct device *dev); -static void lm78_init_client(struct i2c_client *client); - - -static struct i2c_driver lm78_driver = { - .owner = THIS_MODULE, - .name = "lm78", - .id = I2C_DRIVERID_LM78, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm78_attach_adapter, - .detach_client = lm78_detach_client, -}; - -/* 7 Voltages */ -static ssize_t show_in(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); -} - -static ssize_t show_in_min(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); -} - -static ssize_t show_in_max(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); -} - -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val); - lm78_write_value(client, LM78_REG_IN_MIN(nr), data->in_min[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val); - lm78_write_value(client, LM78_REG_IN_MAX(nr), data->in_max[nr]); - up(&data->update_lock); - return count; -} - -#define show_in_offset(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset, NULL); \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); - -show_in_offset(0); -show_in_offset(1); -show_in_offset(2); -show_in_offset(3); -show_in_offset(4); -show_in_offset(5); -show_in_offset(6); - -/* Temperature */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); -} - -static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); -} - -static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_over = TEMP_TO_REG(val); - lm78_write_value(client, LM78_REG_TEMP_OVER, data->temp_over); - up(&data->update_lock); - return count; -} - -static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); -} - -static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_hyst = TEMP_TO_REG(val); - lm78_write_value(client, LM78_REG_TEMP_HYST, data->temp_hyst); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, - show_temp_over, set_temp_over); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, - show_temp_hyst, set_temp_hyst); - -/* 3 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])) ); -} - -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])) ); -} - -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - unsigned long min; - u8 reg; - - down(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - - switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; - default: - dev_err(&client->dev, "fan_div value %ld not " - "supported. Choose one of 1, 2, 4 or 8!\n", val); - up(&data->update_lock); - return -EINVAL; - } - - reg = lm78_read_value(client, LM78_REG_VID_FANDIV); - switch (nr) { - case 0: - reg = (reg & 0xcf) | (data->fan_div[nr] << 4); - break; - case 1: - reg = (reg & 0x3f) | (data->fan_div[nr] << 6); - break; - } - lm78_write_value(client, LM78_REG_VID_FANDIV, reg); - - data->fan_min[nr] = - FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - - return count; -} - -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); - -static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - return set_fan_div(dev, buf, count, 0) ; -} - -static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - return set_fan_div(dev, buf, count, 1) ; -} - -show_fan_offset(1); -show_fan_offset(2); -show_fan_offset(3); - -/* Fan 3 divisor is locked in H/W */ -static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, - show_fan_1_div, set_fan_1_div); -static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, - show_fan_2_div, set_fan_2_div); -static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL); - -/* VID */ -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%d\n", VID_FROM_REG(data->vid)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -/* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm78_data *data = lm78_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* This function is called when: - * lm78_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm78_driver is still present) */ -static int lm78_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm78_detect); -} - -/* This function is called by i2c_detect */ -int lm78_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i, err; - struct i2c_client *new_client; - struct lm78_data *data; - const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - - if (!is_isa && - !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - err = -ENODEV; - goto ERROR0; - } - - /* Reserve the ISA region */ - if (is_isa) - if (!request_region(address, LM78_EXTENT, lm78_driver.name)) { - err = -EBUSY; - goto ERROR0; - } - - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (kind < 0) { - if (is_isa) { - -#define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like - chips. But only if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i) { - err = -ENODEV; - goto ERROR1; - } - if (inb_p(address + 3) != i) { - err = -ENODEV; - goto ERROR1; - } - if (inb_p(address + 7) != i) { - err = -ENODEV; - goto ERROR1; - } -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - err = -ENODEV; - goto ERROR1; - } - } - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm78_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm78_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR1; - } - memset(data, 0, sizeof(struct lm78_data)); - - new_client = &data->client; - if (is_isa) - init_MUTEX(&data->lock); - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm78_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - if (kind < 0) { - if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80) { - err = -ENODEV; - goto ERROR2; - } - if (!is_isa && (lm78_read_value( - new_client, LM78_REG_I2C_ADDR) != address)) { - err = -ENODEV; - goto ERROR2; - } - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = lm78_read_value(new_client, LM78_REG_CHIPID); - if (i == 0x00 || i == 0x20) - kind = lm78; - else if (i == 0x40) - kind = lm78j; - else if ((i & 0xfe) == 0xc0) - kind = lm79; - else { - if (kind == 0) - dev_warn(&adapter->dev, "Ignoring 'force' " - "parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - err = -ENODEV; - goto ERROR2; - } - } - - if (kind == lm78) { - client_name = "lm78"; - } else if (kind == lm78j) { - client_name = "lm78-j"; - } else if (kind == lm79) { - client_name = "lm79"; - } - - /* Fill in the remaining client fields and put into the global list */ - strlcpy(new_client->name, client_name, I2C_NAME_SIZE); - data->type = kind; - - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - /* Initialize the LM78 chip */ - lm78_init_client(new_client); - - /* A few vars need to be filled upon startup */ - for (i = 0; i < 3; i++) { - data->fan_min[i] = lm78_read_value(new_client, - LM78_REG_FAN_MIN(i)); - } - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in6_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan3_input); - device_create_file(&new_client->dev, &dev_attr_fan3_min); - device_create_file(&new_client->dev, &dev_attr_fan3_div); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - - return 0; - -ERROR2: - kfree(data); -ERROR1: - if (is_isa) - release_region(address, LM78_EXTENT); -ERROR0: - return err; -} - -static int lm78_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - - if(i2c_is_isa_client(client)) - release_region(client->addr, LM78_EXTENT); - - kfree(i2c_get_clientdata(client)); - - return 0; -} - -/* The SMBus locks itself, but ISA access must be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. */ -static int lm78_read_value(struct i2c_client *client, u8 reg) -{ - int res; - if (i2c_is_isa_client(client)) { - struct lm78_data *data = i2c_get_clientdata(client); - down(&data->lock); - outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); - res = inb_p(client->addr + LM78_DATA_REG_OFFSET); - up(&data->lock); - return res; - } else - return i2c_smbus_read_byte_data(client, reg); -} - -/* The SMBus locks itself, but ISA access muse be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - if (i2c_is_isa_client(client)) { - struct lm78_data *data = i2c_get_clientdata(client); - down(&data->lock); - outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); - outb_p(value, client->addr + LM78_DATA_REG_OFFSET); - up(&data->lock); - return 0; - } else - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM78. It should set limits, etc. */ -static void lm78_init_client(struct i2c_client *client) -{ - u8 config = lm78_read_value(client, LM78_REG_CONFIG); - - /* Start monitoring */ - if (!(config & 0x01)) - lm78_write_value(client, LM78_REG_CONFIG, - (config & 0xf7) | 0x01); -} - -static struct lm78_data *lm78_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm78_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - dev_dbg(&client->dev, "Starting lm78 update\n"); - - for (i = 0; i <= 6; i++) { - data->in[i] = - lm78_read_value(client, LM78_REG_IN(i)); - data->in_min[i] = - lm78_read_value(client, LM78_REG_IN_MIN(i)); - data->in_max[i] = - lm78_read_value(client, LM78_REG_IN_MAX(i)); - } - for (i = 0; i < 3; i++) { - data->fan[i] = - lm78_read_value(client, LM78_REG_FAN(i)); - data->fan_min[i] = - lm78_read_value(client, LM78_REG_FAN_MIN(i)); - } - data->temp = lm78_read_value(client, LM78_REG_TEMP); - data->temp_over = - lm78_read_value(client, LM78_REG_TEMP_OVER); - data->temp_hyst = - lm78_read_value(client, LM78_REG_TEMP_HYST); - i = lm78_read_value(client, LM78_REG_VID_FANDIV); - data->vid = i & 0x0f; - if (data->type == lm79) - data->vid |= - (lm78_read_value(client, LM78_REG_CHIPID) & - 0x01) << 4; - else - data->vid |= 0x10; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = lm78_read_value(client, LM78_REG_ALARM1) + - (lm78_read_value(client, LM78_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - - data->fan_div[2] = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sm_lm78_init(void) -{ - return i2c_add_driver(&lm78_driver); -} - -static void __exit sm_lm78_exit(void) -{ - i2c_del_driver(&lm78_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_lm78_init); -module_exit(sm_lm78_exit); diff --git a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c deleted file mode 100644 index 8100595feb4..00000000000 --- a/drivers/i2c/chips/lm80.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * lm80.c - From lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 1998, 1999 Frodo Looijaard - * and Philip Edelbrock - * - * Ported to Linux 2.6 by Tiago Sousa - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, - 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm80); - -/* Many LM80 constants specified below */ - -/* The LM80 registers */ -#define LM80_REG_IN_MAX(nr) (0x2a + (nr) * 2) -#define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2) -#define LM80_REG_IN(nr) (0x20 + (nr)) - -#define LM80_REG_FAN1 0x28 -#define LM80_REG_FAN2 0x29 -#define LM80_REG_FAN_MIN(nr) (0x3b + (nr)) - -#define LM80_REG_TEMP 0x27 -#define LM80_REG_TEMP_HOT_MAX 0x38 -#define LM80_REG_TEMP_HOT_HYST 0x39 -#define LM80_REG_TEMP_OS_MAX 0x3a -#define LM80_REG_TEMP_OS_HYST 0x3b - -#define LM80_REG_CONFIG 0x00 -#define LM80_REG_ALARM1 0x01 -#define LM80_REG_ALARM2 0x02 -#define LM80_REG_MASK1 0x03 -#define LM80_REG_MASK2 0x04 -#define LM80_REG_FANDIV 0x05 -#define LM80_REG_RES 0x06 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define IN_TO_REG(val) (SENSORS_LIMIT(((val)+5)/10,0,255)) -#define IN_FROM_REG(val) ((val)*10) - -static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm*div / 2) / (rpm*div), 1, 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -static inline long TEMP_FROM_REG(u16 temp) -{ - long res; - - temp >>= 4; - if (temp < 0x0800) - res = 625 * (long) temp; - else - res = ((long) temp - 0x01000) * 625; - - return res / 10; -} - -#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000) - -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val)<0?\ - ((val)-500)/1000:((val)+500)/1000,0,255) - -#define DIV_FROM_REG(val) (1 << (val)) - -/* - * Client data (each client gets its own) - */ - -struct lm80_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 temp; /* Register values, shifted right */ - u8 temp_hot_max; /* Register value */ - u8 temp_hot_hyst; /* Register value */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ - u16 alarms; /* Register encoding, combined */ -}; - -/* - * Functions declaration - */ - -static int lm80_attach_adapter(struct i2c_adapter *adapter); -static int lm80_detect(struct i2c_adapter *adapter, int address, int kind); -static void lm80_init_client(struct i2c_client *client); -static int lm80_detach_client(struct i2c_client *client); -static struct lm80_data *lm80_update_device(struct device *dev); -static int lm80_read_value(struct i2c_client *client, u8 reg); -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm80_driver = { - .owner = THIS_MODULE, - .name = "lm80", - .id = I2C_DRIVERID_LM80, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm80_attach_adapter, - .detach_client = lm80_detach_client, -}; - -/* - * Sysfs stuff - */ - -#define show_in(suffix, value) \ -static ssize_t show_in_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - return sprintf(buf, "%d\n", IN_FROM_REG(data->value)); \ -} -show_in(min0, in_min[0]); -show_in(min1, in_min[1]); -show_in(min2, in_min[2]); -show_in(min3, in_min[3]); -show_in(min4, in_min[4]); -show_in(min5, in_min[5]); -show_in(min6, in_min[6]); -show_in(max0, in_max[0]); -show_in(max1, in_max[1]); -show_in(max2, in_max[2]); -show_in(max3, in_max[3]); -show_in(max4, in_max[4]); -show_in(max5, in_max[5]); -show_in(max6, in_max[6]); -show_in(input0, in[0]); -show_in(input1, in[1]); -show_in(input2, in[2]); -show_in(input3, in[3]); -show_in(input4, in[4]); -show_in(input5, in[5]); -show_in(input6, in[6]); - -#define set_in(suffix, value, reg) \ -static ssize_t set_in_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm80_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock);\ - data->value = IN_TO_REG(val); \ - lm80_write_value(client, reg, data->value); \ - up(&data->update_lock);\ - return count; \ -} -set_in(min0, in_min[0], LM80_REG_IN_MIN(0)); -set_in(min1, in_min[1], LM80_REG_IN_MIN(1)); -set_in(min2, in_min[2], LM80_REG_IN_MIN(2)); -set_in(min3, in_min[3], LM80_REG_IN_MIN(3)); -set_in(min4, in_min[4], LM80_REG_IN_MIN(4)); -set_in(min5, in_min[5], LM80_REG_IN_MIN(5)); -set_in(min6, in_min[6], LM80_REG_IN_MIN(6)); -set_in(max0, in_max[0], LM80_REG_IN_MAX(0)); -set_in(max1, in_max[1], LM80_REG_IN_MAX(1)); -set_in(max2, in_max[2], LM80_REG_IN_MAX(2)); -set_in(max3, in_max[3], LM80_REG_IN_MAX(3)); -set_in(max4, in_max[4], LM80_REG_IN_MAX(4)); -set_in(max5, in_max[5], LM80_REG_IN_MAX(5)); -set_in(max6, in_max[6], LM80_REG_IN_MAX(6)); - -#define show_fan(suffix, value, div) \ -static ssize_t show_fan_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value, \ - DIV_FROM_REG(data->div))); \ -} -show_fan(min1, fan_min[0], fan_div[0]); -show_fan(min2, fan_min[1], fan_div[1]); -show_fan(input1, fan[0], fan_div[0]); -show_fan(input2, fan[1], fan_div[1]); - -#define show_fan_div(suffix, value) \ -static ssize_t show_fan_div##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - return sprintf(buf, "%d\n", DIV_FROM_REG(data->value)); \ -} -show_fan_div(1, fan_div[0]); -show_fan_div(2, fan_div[1]); - -#define set_fan(suffix, value, reg, div) \ -static ssize_t set_fan_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm80_data *data = i2c_get_clientdata(client); \ - long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock);\ - data->value = FAN_TO_REG(val, DIV_FROM_REG(data->div)); \ - lm80_write_value(client, reg, data->value); \ - up(&data->update_lock);\ - return count; \ -} -set_fan(min1, fan_min[0], LM80_REG_FAN_MIN(1), fan_div[0]); -set_fan(min2, fan_min[1], LM80_REG_FAN_MIN(2), fan_div[1]); - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm80_data *data = i2c_get_clientdata(client); - unsigned long min, val = simple_strtoul(buf, NULL, 10); - u8 reg; - - /* Save fan_min */ - down(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - - switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; - default: - dev_err(&client->dev, "fan_div value %ld not " - "supported. Choose one of 1, 2, 4 or 8!\n", val); - up(&data->update_lock); - return -EINVAL; - } - - reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1)))) - | (data->fan_div[nr] << (2 * (nr + 1))); - lm80_write_value(client, LM80_REG_FANDIV, reg); - - /* Restore fan_min */ - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); - up(&data->update_lock); - - return count; -} - -#define set_fan_div(number) \ -static ssize_t set_fan_div##number(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_div(dev, buf, count, number - 1); \ -} -set_fan_div(1); -set_fan_div(2); - -static ssize_t show_temp_input1(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm80_data *data = lm80_update_device(dev); - return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp)); -} - -#define show_temp(suffix, value) \ -static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \ -} -show_temp(hot_max, temp_hot_max); -show_temp(hot_hyst, temp_hot_hyst); -show_temp(os_max, temp_os_max); -show_temp(os_hyst, temp_os_hyst); - -#define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm80_data *data = i2c_get_clientdata(client); \ - long val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_LIMIT_TO_REG(val); \ - lm80_write_value(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} -set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX); -set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST); -set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX); -set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm80_data *data = lm80_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} - -static DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min0, set_in_min0); -static DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min1, set_in_min1); -static DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min2, set_in_min2); -static DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min3, set_in_min3); -static DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min4, set_in_min4); -static DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min5, set_in_min5); -static DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min6, set_in_min6); -static DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max0, set_in_max0); -static DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max1, set_in_max1); -static DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max2, set_in_max2); -static DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max3, set_in_max3); -static DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max4, set_in_max4); -static DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max5, set_in_max5); -static DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max6, set_in_max6); -static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL); -static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL); -static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL); -static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL); -static DEVICE_ATTR(in4_input, S_IRUGO, show_in_input4, NULL); -static DEVICE_ATTR(in5_input, S_IRUGO, show_in_input5, NULL); -static DEVICE_ATTR(in6_input, S_IRUGO, show_in_input6, NULL); -static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min1, - set_fan_min1); -static DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min2, - set_fan_min2); -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); -static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); -static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div1, set_fan_div1); -static DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div2, set_fan_div2); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max, - set_temp_hot_max); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst, - set_temp_hot_hyst); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max, - set_temp_os_max); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst, - set_temp_os_hyst); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* - * Real code - */ - -static int lm80_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm80_detect); -} - -int lm80_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i, cur; - struct i2c_client *new_client; - struct lm80_data *data; - int err = 0; - const char *name; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm80_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm80_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm80_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm80_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. It is lousy. */ - if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0) - goto error_free; - for (i = 0x2a; i <= 0x3d; i++) { - cur = i2c_smbus_read_byte_data(new_client, i); - if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur) - || (i2c_smbus_read_byte_data(new_client, i + 0x80) != cur) - || (i2c_smbus_read_byte_data(new_client, i + 0xc0) != cur)) - goto error_free; - } - - /* Determine the chip type - only one kind supported! */ - kind = lm80; - name = "lm80"; - - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto error_free; - - /* Initialize the LM80 chip */ - lm80_init_client(new_client); - - /* A few vars need to be filled upon startup */ - data->fan_min[0] = lm80_read_value(new_client, LM80_REG_FAN_MIN(1)); - data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2)); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_in6_max); - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -error_free: - kfree(data); -exit: - return err; -} - -static int lm80_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - -static int lm80_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM80. */ -static void lm80_init_client(struct i2c_client *client) -{ - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others. This makes most other - initializations unnecessary */ - lm80_write_value(client, LM80_REG_CONFIG, 0x80); - /* Set 11-bit temperature resolution */ - lm80_write_value(client, LM80_REG_RES, 0x08); - - /* Start monitoring */ - lm80_write_value(client, LM80_REG_CONFIG, 0x01); -} - -static struct lm80_data *lm80_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm80_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { - dev_dbg(&client->dev, "Starting lm80 update\n"); - for (i = 0; i <= 6; i++) { - data->in[i] = - lm80_read_value(client, LM80_REG_IN(i)); - data->in_min[i] = - lm80_read_value(client, LM80_REG_IN_MIN(i)); - data->in_max[i] = - lm80_read_value(client, LM80_REG_IN_MAX(i)); - } - data->fan[0] = lm80_read_value(client, LM80_REG_FAN1); - data->fan_min[0] = - lm80_read_value(client, LM80_REG_FAN_MIN(1)); - data->fan[1] = lm80_read_value(client, LM80_REG_FAN2); - data->fan_min[1] = - lm80_read_value(client, LM80_REG_FAN_MIN(2)); - - data->temp = - (lm80_read_value(client, LM80_REG_TEMP) << 8) | - (lm80_read_value(client, LM80_REG_RES) & 0xf0); - data->temp_os_max = - lm80_read_value(client, LM80_REG_TEMP_OS_MAX); - data->temp_os_hyst = - lm80_read_value(client, LM80_REG_TEMP_OS_HYST); - data->temp_hot_max = - lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); - data->temp_hot_hyst = - lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); - - i = lm80_read_value(client, LM80_REG_FANDIV); - data->fan_div[0] = (i >> 2) & 0x03; - data->fan_div[1] = (i >> 4) & 0x03; - data->alarms = lm80_read_value(client, LM80_REG_ALARM1) + - (lm80_read_value(client, LM80_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm80_init(void) -{ - return i2c_add_driver(&lm80_driver); -} - -static void __exit sensors_lm80_exit(void) -{ - i2c_del_driver(&lm80_driver); -} - -MODULE_AUTHOR("Frodo Looijaard and " - "Philip Edelbrock "); -MODULE_DESCRIPTION("LM80 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm80_init); -module_exit(sensors_lm80_exit); diff --git a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c deleted file mode 100644 index a49008b444c..00000000000 --- a/drivers/i2c/chips/lm83.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * lm83.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2005 Jean Delvare - * - * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is - * a sensor chip made by National Semiconductor. It reports up to four - * temperatures (its own plus up to three external ones) with a 1 deg - * resolution and a 3-4 deg accuracy. Complete datasheet can be obtained - * from National's website at: - * http://www.national.com/pf/LM/LM83.html - * Since the datasheet omits to give the chip stepping code, I give it - * here: 0x03 (at register 0xff). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Addresses to scan - * Address is selected using 2 three-level pins, resulting in 9 possible - * addresses. - */ - -static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, - 0x29, 0x2a, 0x2b, - 0x4c, 0x4d, 0x4e, - I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(lm83); - -/* - * The LM83 registers - * Manufacturer ID is 0x01 for National Semiconductor. - */ - -#define LM83_REG_R_MAN_ID 0xFE -#define LM83_REG_R_CHIP_ID 0xFF -#define LM83_REG_R_CONFIG 0x03 -#define LM83_REG_W_CONFIG 0x09 -#define LM83_REG_R_STATUS1 0x02 -#define LM83_REG_R_STATUS2 0x35 -#define LM83_REG_R_LOCAL_TEMP 0x00 -#define LM83_REG_R_LOCAL_HIGH 0x05 -#define LM83_REG_W_LOCAL_HIGH 0x0B -#define LM83_REG_R_REMOTE1_TEMP 0x30 -#define LM83_REG_R_REMOTE1_HIGH 0x38 -#define LM83_REG_W_REMOTE1_HIGH 0x50 -#define LM83_REG_R_REMOTE2_TEMP 0x01 -#define LM83_REG_R_REMOTE2_HIGH 0x07 -#define LM83_REG_W_REMOTE2_HIGH 0x0D -#define LM83_REG_R_REMOTE3_TEMP 0x31 -#define LM83_REG_R_REMOTE3_HIGH 0x3A -#define LM83_REG_W_REMOTE3_HIGH 0x52 -#define LM83_REG_R_TCRIT 0x42 -#define LM83_REG_W_TCRIT 0x5A - -/* - * Conversions and various macros - * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius. - */ - -#define TEMP_FROM_REG(val) ((val) * 1000) -#define TEMP_TO_REG(val) ((val) <= -128000 ? -128 : \ - (val) >= 127000 ? 127 : \ - (val) < 0 ? ((val) - 500) / 1000 : \ - ((val) + 500) / 1000) - -static const u8 LM83_REG_R_TEMP[] = { - LM83_REG_R_LOCAL_TEMP, - LM83_REG_R_REMOTE1_TEMP, - LM83_REG_R_REMOTE2_TEMP, - LM83_REG_R_REMOTE3_TEMP, - LM83_REG_R_LOCAL_HIGH, - LM83_REG_R_REMOTE1_HIGH, - LM83_REG_R_REMOTE2_HIGH, - LM83_REG_R_REMOTE3_HIGH, - LM83_REG_R_TCRIT, -}; - -static const u8 LM83_REG_W_HIGH[] = { - LM83_REG_W_LOCAL_HIGH, - LM83_REG_W_REMOTE1_HIGH, - LM83_REG_W_REMOTE2_HIGH, - LM83_REG_W_REMOTE3_HIGH, - LM83_REG_W_TCRIT, -}; - -/* - * Functions declaration - */ - -static int lm83_attach_adapter(struct i2c_adapter *adapter); -static int lm83_detect(struct i2c_adapter *adapter, int address, int kind); -static int lm83_detach_client(struct i2c_client *client); -static struct lm83_data *lm83_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm83_driver = { - .owner = THIS_MODULE, - .name = "lm83", - .id = I2C_DRIVERID_LM83, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm83_attach_adapter, - .detach_client = lm83_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm83_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - s8 temp[9]; /* 0..3: input 1-4, - 4..7: high limit 1-4, - 8 : critical limit */ - u16 alarms; /* bitvector, combined */ -}; - -/* - * Sysfs stuff - */ - -static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm83_data *data = lm83_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); -} - -static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm83_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - int nr = attr->index; - - down(&data->update_lock); - data->temp[nr] = TEMP_TO_REG(val); - i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4], - data->temp[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm83_data *data = lm83_update_device(dev); - return sprintf(buf, "%d\n", data->alarms); -} - -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); -static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); -static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, - set_temp, 4); -static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp, - set_temp, 5); -static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp, - set_temp, 6); -static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp, - set_temp, 7); -static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, 8); -static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8); -static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp, - set_temp, 8); -static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* - * Real code - */ - -static int lm83_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm83_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm83_data *data; - int err = 0; - const char *name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct lm83_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm83_data)); - - /* The common I2C client data is placed right after the - * LM83-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm83_driver; - new_client->flags = 0; - - /* Now we do the detection and identification. A negative kind - * means that the driver was loaded with no force parameter - * (default), so we must both detect and identify the chip - * (actually there is only one possible kind of chip for now, LM83). - * A zero kind means that the driver was loaded with the force - * parameter, the detection step shall be skipped. A positive kind - * means that the driver was loaded with the force parameter and a - * given kind of chip is requested, so both the detection and the - * identification steps are skipped. */ - - /* Default to an LM83 if forced */ - if (kind == 0) - kind = lm83; - - if (kind < 0) { /* detection */ - if (((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1) - & 0xA8) != 0x00) || - ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS2) - & 0x48) != 0x00) || - ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG) - & 0x41) != 0x00)) { - dev_dbg(&adapter->dev, - "LM83 detection failed at 0x%02x.\n", address); - goto exit_free; - } - } - - if (kind <= 0) { /* identification */ - u8 man_id, chip_id; - - man_id = i2c_smbus_read_byte_data(new_client, - LM83_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - LM83_REG_R_CHIP_ID); - - if (man_id == 0x01) { /* National Semiconductor */ - if (chip_id == 0x03) { - kind = lm83; - } - } - - if (kind <= 0) { /* identification failed */ - dev_info(&adapter->dev, - "Unsupported chip (man_id=0x%02X, " - "chip_id=0x%02X).\n", man_id, chip_id); - goto exit_free; - } - } - - if (kind == lm83) { - name = "lm83"; - } - - /* We can fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* - * Initialize the LM83 chip - * (Nothing to do for this one.) - */ - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_crit.dev_attr); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int lm83_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - -static struct lm83_data *lm83_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm83_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - int nr; - - dev_dbg(&client->dev, "Updating lm83 data.\n"); - for (nr = 0; nr < 9; nr++) { - data->temp[nr] = - i2c_smbus_read_byte_data(client, - LM83_REG_R_TEMP[nr]); - } - data->alarms = - i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) - + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) - << 8); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm83_init(void) -{ - return i2c_add_driver(&lm83_driver); -} - -static void __exit sensors_lm83_exit(void) -{ - i2c_del_driver(&lm83_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM83 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm83_init); -module_exit(sensors_lm83_exit); diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c deleted file mode 100644 index b4d7fd41826..00000000000 --- a/drivers/i2c/chips/lm85.c +++ /dev/null @@ -1,1575 +0,0 @@ -/* - lm85.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - Copyright (c) 2002, 2003 Philip Pokorny - Copyright (c) 2003 Margit Schubert-While - Copyright (c) 2004 Justin Thiessen - - Chip details at - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); - -/* The LM85 registers */ - -#define LM85_REG_IN(nr) (0x20 + (nr)) -#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2) -#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2) - -#define LM85_REG_TEMP(nr) (0x25 + (nr)) -#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2) -#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2) - -/* Fan speeds are LSB, MSB (2 bytes) */ -#define LM85_REG_FAN(nr) (0x28 + (nr) *2) -#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) *2) - -#define LM85_REG_PWM(nr) (0x30 + (nr)) - -#define ADT7463_REG_OPPOINT(nr) (0x33 + (nr)) - -#define ADT7463_REG_TMIN_CTL1 0x36 -#define ADT7463_REG_TMIN_CTL2 0x37 - -#define LM85_REG_DEVICE 0x3d -#define LM85_REG_COMPANY 0x3e -#define LM85_REG_VERSTEP 0x3f -/* These are the recognized values for the above regs */ -#define LM85_DEVICE_ADX 0x27 -#define LM85_COMPANY_NATIONAL 0x01 -#define LM85_COMPANY_ANALOG_DEV 0x41 -#define LM85_COMPANY_SMSC 0x5c -#define LM85_VERSTEP_VMASK 0xf0 -#define LM85_VERSTEP_GENERIC 0x60 -#define LM85_VERSTEP_LM85C 0x60 -#define LM85_VERSTEP_LM85B 0x62 -#define LM85_VERSTEP_ADM1027 0x60 -#define LM85_VERSTEP_ADT7463 0x62 -#define LM85_VERSTEP_ADT7463C 0x6A -#define LM85_VERSTEP_EMC6D100_A0 0x60 -#define LM85_VERSTEP_EMC6D100_A1 0x61 -#define LM85_VERSTEP_EMC6D102 0x65 - -#define LM85_REG_CONFIG 0x40 - -#define LM85_REG_ALARM1 0x41 -#define LM85_REG_ALARM2 0x42 - -#define LM85_REG_VID 0x43 - -/* Automated FAN control */ -#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr)) -#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr)) -#define LM85_REG_AFAN_SPIKE1 0x62 -#define LM85_REG_AFAN_SPIKE2 0x63 -#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr)) -#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr)) -#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr)) -#define LM85_REG_AFAN_HYST1 0x6d -#define LM85_REG_AFAN_HYST2 0x6e - -#define LM85_REG_TACH_MODE 0x74 -#define LM85_REG_SPINUP_CTL 0x75 - -#define ADM1027_REG_TEMP_OFFSET(nr) (0x70 + (nr)) -#define ADM1027_REG_CONFIG2 0x73 -#define ADM1027_REG_INTMASK1 0x74 -#define ADM1027_REG_INTMASK2 0x75 -#define ADM1027_REG_EXTEND_ADC1 0x76 -#define ADM1027_REG_EXTEND_ADC2 0x77 -#define ADM1027_REG_CONFIG3 0x78 -#define ADM1027_REG_FAN_PPR 0x7b - -#define ADT7463_REG_THERM 0x79 -#define ADT7463_REG_THERM_LIMIT 0x7A - -#define EMC6D100_REG_ALARM3 0x7d -/* IN5, IN6 and IN7 */ -#define EMC6D100_REG_IN(nr) (0x70 + ((nr)-5)) -#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr)-5) * 2) -#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr)-5) * 2) -#define EMC6D102_REG_EXTEND_ADC1 0x85 -#define EMC6D102_REG_EXTEND_ADC2 0x86 -#define EMC6D102_REG_EXTEND_ADC3 0x87 -#define EMC6D102_REG_EXTEND_ADC4 0x88 - -#define LM85_ALARM_IN0 0x0001 -#define LM85_ALARM_IN1 0x0002 -#define LM85_ALARM_IN2 0x0004 -#define LM85_ALARM_IN3 0x0008 -#define LM85_ALARM_TEMP1 0x0010 -#define LM85_ALARM_TEMP2 0x0020 -#define LM85_ALARM_TEMP3 0x0040 -#define LM85_ALARM_ALARM2 0x0080 -#define LM85_ALARM_IN4 0x0100 -#define LM85_ALARM_RESERVED 0x0200 -#define LM85_ALARM_FAN1 0x0400 -#define LM85_ALARM_FAN2 0x0800 -#define LM85_ALARM_FAN3 0x1000 -#define LM85_ALARM_FAN4 0x2000 -#define LM85_ALARM_TEMP1_FAULT 0x4000 -#define LM85_ALARM_TEMP3_FAULT 0x8000 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - */ - -/* IN are scaled acording to built-in resistors */ -static int lm85_scaling[] = { /* .001 Volts */ - 2500, 2250, 3300, 5000, 12000, - 3300, 1500, 1800 /*EMC6D100*/ - }; -#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) - -#define INS_TO_REG(n,val) \ - SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255) - -#define INSEXT_FROM_REG(n,val,ext,scale) \ - SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n]) - -#define INS_FROM_REG(n,val) INSEXT_FROM_REG(n,val,0,1) - -/* FAN speed is measured using 90kHz clock */ -#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534)) -#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) - -/* Temperature is reported in .001 degC increments */ -#define TEMP_TO_REG(val) \ - SENSORS_LIMIT(SCALE(val,1000,1),-127,127) -#define TEMPEXT_FROM_REG(val,ext,scale) \ - SCALE((val)*scale + (ext),scale,1000) -#define TEMP_FROM_REG(val) \ - TEMPEXT_FROM_REG(val,0,1) - -#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) -#define PWM_FROM_REG(val) (val) - - -/* ZONEs have the following parameters: - * Limit (low) temp, 1. degC - * Hysteresis (below limit), 1. degC (0-15) - * Range of speed control, .1 degC (2-80) - * Critical (high) temp, 1. degC - * - * FAN PWMs have the following parameters: - * Reference Zone, 1, 2, 3, etc. - * Spinup time, .05 sec - * PWM value at limit/low temp, 1 count - * PWM Frequency, 1. Hz - * PWM is Min or OFF below limit, flag - * Invert PWM output, flag - * - * Some chips filter the temp, others the fan. - * Filter constant (or disabled) .1 seconds - */ - -/* These are the zone temperature range encodings in .001 degree C */ -static int lm85_range_map[] = { - 2000, 2500, 3300, 4000, 5000, 6600, - 8000, 10000, 13300, 16000, 20000, 26600, - 32000, 40000, 53300, 80000 - }; -static int RANGE_TO_REG( int range ) -{ - int i; - - if ( range < lm85_range_map[0] ) { - return 0 ; - } else if ( range > lm85_range_map[15] ) { - return 15 ; - } else { /* find closest match */ - for ( i = 14 ; i >= 0 ; --i ) { - if ( range > lm85_range_map[i] ) { /* range bracketed */ - if ((lm85_range_map[i+1] - range) < - (range - lm85_range_map[i])) { - i++; - break; - } - break; - } - } - } - return( i & 0x0f ); -} -#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f]) - -/* These are the Acoustic Enhancement, or Temperature smoothing encodings - * NOTE: The enable/disable bit is INCLUDED in these encodings as the - * MSB (bit 3, value 8). If the enable bit is 0, the encoded value - * is ignored, or set to 0. - */ -/* These are the PWM frequency encodings */ -static int lm85_freq_map[] = { /* .1 Hz */ - 100, 150, 230, 300, 380, 470, 620, 940 - }; -static int FREQ_TO_REG( int freq ) -{ - int i; - - if( freq >= lm85_freq_map[7] ) { return 7 ; } - for( i = 0 ; i < 7 ; ++i ) - if( freq <= lm85_freq_map[i] ) - break ; - return( i & 0x07 ); -} -#define FREQ_FROM_REG(val) (lm85_freq_map[(val)&0x07]) - -/* Since we can't use strings, I'm abusing these numbers - * to stand in for the following meanings: - * 1 -- PWM responds to Zone 1 - * 2 -- PWM responds to Zone 2 - * 3 -- PWM responds to Zone 3 - * 23 -- PWM responds to the higher temp of Zone 2 or 3 - * 123 -- PWM responds to highest of Zone 1, 2, or 3 - * 0 -- PWM is always at 0% (ie, off) - * -1 -- PWM is always at 100% - * -2 -- PWM responds to manual control - */ - -static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 }; -#define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07]) - -static int ZONE_TO_REG( int zone ) -{ - int i; - - for( i = 0 ; i <= 7 ; ++i ) - if( zone == lm85_zone_map[i] ) - break ; - if( i > 7 ) /* Not found. */ - i = 3; /* Always 100% */ - return( (i & 0x07)<<5 ); -} - -#define HYST_TO_REG(val) (SENSORS_LIMIT(((val)+500)/1000,0,15)) -#define HYST_FROM_REG(val) ((val)*1000) - -#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) -#define OFFSET_FROM_REG(val) ((val)*25) - -#define PPR_MASK(fan) (0x03<<(fan *2)) -#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2)) -#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1) - -/* i2c-vid.h defines vid_from_reg() */ -#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm))) - -/* Unlike some other drivers we DO NOT set initial limits. Use - * the config file to set limits. Some users have reported - * motherboards shutting down when we set limits in a previous - * version of the driver. - */ - -/* Chip sampling rates - * - * Some sensors are not updated more frequently than once per second - * so it doesn't make sense to read them more often than that. - * We cache the results and return the saved data if the driver - * is called again before a second has elapsed. - * - * Also, there is significant configuration data for this chip - * given the automatic PWM fan control that is possible. There - * are about 47 bytes of config data to only 22 bytes of actual - * readings. So, we keep the config data up to date in the cache - * when it is written and only sample it once every 1 *minute* - */ -#define LM85_DATA_INTERVAL (HZ + HZ / 2) -#define LM85_CONFIG_INTERVAL (1 * 60 * HZ) - -/* For each registered LM85, we need to keep some data in memory. That - data is pointed to by lm85_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new lm85 client is - allocated. */ - -/* LM85 can automatically adjust fan speeds based on temperature - * This structure encapsulates an entire Zone config. There are - * three zones (one for each temperature input) on the lm85 - */ -struct lm85_zone { - s8 limit; /* Low temp limit */ - u8 hyst; /* Low limit hysteresis. (0-15) */ - u8 range; /* Temp range, encoded */ - s8 critical; /* "All fans ON" temp limit */ - u8 off_desired; /* Actual "off" temperature specified. Preserved - * to prevent "drift" as other autofan control - * values change. - */ - u8 max_desired; /* Actual "max" temperature specified. Preserved - * to prevent "drift" as other autofan control - * values change. - */ -}; - -struct lm85_autofan { - u8 config; /* Register value */ - u8 freq; /* PWM frequency, encoded */ - u8 min_pwm; /* Minimum PWM value, encoded */ - u8 min_off; /* Min PWM or OFF below "limit", flag */ -}; - -struct lm85_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - int valid; /* !=0 if following fields are valid */ - unsigned long last_reading; /* In jiffies */ - unsigned long last_config; /* In jiffies */ - - u8 in[8]; /* Register value */ - u8 in_max[8]; /* Register value */ - u8 in_min[8]; /* Register value */ - s8 temp[3]; /* Register value */ - s8 temp_min[3]; /* Register value */ - s8 temp_max[3]; /* Register value */ - s8 temp_offset[3]; /* Register value */ - u16 fan[4]; /* Register value */ - u16 fan_min[4]; /* Register value */ - u8 pwm[3]; /* Register value */ - u8 spinup_ctl; /* Register encoding, combined */ - u8 tach_mode; /* Register encoding, combined */ - u8 temp_ext[3]; /* Decoded values */ - u8 in_ext[8]; /* Decoded values */ - u8 adc_scale; /* ADC Extended bits scaling factor */ - u8 fan_ppr; /* Register value */ - u8 smooth[3]; /* Register encoding */ - u8 vid; /* Register value */ - u8 vrm; /* VRM version */ - u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */ - u8 oppoint[3]; /* Register value */ - u16 tmin_ctl; /* Register value */ - unsigned long therm_total; /* Cummulative therm count */ - u8 therm_limit; /* Register value */ - u32 alarms; /* Register encoding, combined */ - struct lm85_autofan autofan[3]; - struct lm85_zone zone[3]; -}; - -static int lm85_attach_adapter(struct i2c_adapter *adapter); -static int lm85_detect(struct i2c_adapter *adapter, int address, - int kind); -static int lm85_detach_client(struct i2c_client *client); - -static int lm85_read_value(struct i2c_client *client, u8 register); -static int lm85_write_value(struct i2c_client *client, u8 register, int value); -static struct lm85_data *lm85_update_device(struct device *dev); -static void lm85_init_client(struct i2c_client *client); - - -static struct i2c_driver lm85_driver = { - .owner = THIS_MODULE, - .name = "lm85", - .id = I2C_DRIVERID_LM85, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm85_attach_adapter, - .detach_client = lm85_detach_client, -}; - - -/* 4 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) ); -} -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) ); -} -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val); - lm85_write_value(client, LM85_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ - NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); - -show_fan_offset(1); -show_fan_offset(2); -show_fan_offset(3); -show_fan_offset(4); - -/* vid, vrm, alarms */ - -static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); -} - -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); - -static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->vrm); -} - -static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - data->vrm = val; - return count; -} - -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); - -static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} - -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); - -/* pwm */ - -static ssize_t show_pwm(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) ); -} -static ssize_t set_pwm(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->pwm[nr] = PWM_TO_REG(val); - lm85_write_value(client, LM85_REG_PWM(nr), data->pwm[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - int pwm_zone; - - pwm_zone = ZONE_FROM_REG(data->autofan[nr].config); - return sprintf(buf,"%d\n", (pwm_zone != 0 && pwm_zone != -1) ); -} - -#define show_pwm_reg(offset) \ -static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm_enable##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_enable(dev, buf, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm_##offset, set_pwm_##offset); \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \ - show_pwm_enable##offset, NULL); - -show_pwm_reg(1); -show_pwm_reg(2); -show_pwm_reg(3); - -/* Voltages */ - -static ssize_t show_in(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf( buf, "%d\n", INSEXT_FROM_REG(nr, - data->in[nr], - data->in_ext[nr], - data->adc_scale) ); -} -static ssize_t show_in_min(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) ); -} -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = INS_TO_REG(nr, val); - lm85_write_value(client, LM85_REG_IN_MIN(nr), data->in_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_in_max(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) ); -} -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = INS_TO_REG(nr, val); - lm85_write_value(client, LM85_REG_IN_MAX(nr), data->in_max[nr]); - up(&data->update_lock); - return count; -} -#define show_in_reg(offset) \ -static ssize_t show_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static ssize_t show_in_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t show_in_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, \ - NULL); \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in_##offset##_min, set_in_##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in_##offset##_max, set_in_##offset##_max); - -show_in_reg(0); -show_in_reg(1); -show_in_reg(2); -show_in_reg(3); -show_in_reg(4); - -/* Temps */ - -static ssize_t show_temp(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr], - data->temp_ext[nr], - data->adc_scale) ); -} -static ssize_t show_temp_min(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) ); -} -static ssize_t set_temp_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_min[nr] = TEMP_TO_REG(val); - lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t show_temp_max(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) ); -} -static ssize_t set_temp_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_max[nr] = TEMP_TO_REG(val); - lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]); - up(&data->update_lock); - return count; -} -#define show_temp_reg(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_max(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ - NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max); - -show_temp_reg(1); -show_temp_reg(2); -show_temp_reg(3); - - -/* Automatic PWM control */ - -static ssize_t show_pwm_auto_channels(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", ZONE_FROM_REG(data->autofan[nr].config)); -} -static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->autofan[nr].config = (data->autofan[nr].config & (~0xe0)) - | ZONE_TO_REG(val) ; - lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), - data->autofan[nr].config); - up(&data->update_lock); - return count; -} -static ssize_t show_pwm_auto_pwm_min(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm)); -} -static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->autofan[nr].min_pwm = PWM_TO_REG(val); - lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr), - data->autofan[nr].min_pwm); - up(&data->update_lock); - return count; -} -static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", data->autofan[nr].min_off); -} -static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->autofan[nr].min_off = val; - lm85_write_value(client, LM85_REG_AFAN_SPIKE1, data->smooth[0] - | data->syncpwm3 - | (data->autofan[0].min_off ? 0x20 : 0) - | (data->autofan[1].min_off ? 0x40 : 0) - | (data->autofan[2].min_off ? 0x80 : 0) - ); - up(&data->update_lock); - return count; -} -static ssize_t show_pwm_auto_pwm_freq(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", FREQ_FROM_REG(data->autofan[nr].freq)); -} -static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->autofan[nr].freq = FREQ_TO_REG(val); - lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), - (data->zone[nr].range << 4) - | data->autofan[nr].freq - ); - up(&data->update_lock); - return count; -} -#define pwm_auto(offset) \ -static ssize_t show_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_channels(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_channels(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_minctl(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_minctl(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_freq (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_freq(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_freq(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_freq(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset##_auto_channels, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_channels, \ - set_pwm##offset##_auto_channels); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_min, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_min, \ - set_pwm##offset##_auto_pwm_min); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_minctl, \ - set_pwm##offset##_auto_pwm_minctl); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_freq, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_freq, \ - set_pwm##offset##_auto_pwm_freq); -pwm_auto(1); -pwm_auto(2); -pwm_auto(3); - -/* Temperature settings for automatic PWM control */ - -static ssize_t show_temp_auto_temp_off(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) - - HYST_FROM_REG(data->zone[nr].hyst)); -} -static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - int min; - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - min = TEMP_FROM_REG(data->zone[nr].limit); - data->zone[nr].off_desired = TEMP_TO_REG(val); - data->zone[nr].hyst = HYST_TO_REG(min - val); - if ( nr == 0 || nr == 1 ) { - lm85_write_value(client, LM85_REG_AFAN_HYST1, - (data->zone[0].hyst << 4) - | data->zone[1].hyst - ); - } else { - lm85_write_value(client, LM85_REG_AFAN_HYST2, - (data->zone[2].hyst << 4) - ); - } - up(&data->update_lock); - return count; -} -static ssize_t show_temp_auto_temp_min(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) ); -} -static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->zone[nr].limit = TEMP_TO_REG(val); - lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr), - data->zone[nr].limit); - -/* Update temp_auto_max and temp_auto_range */ - data->zone[nr].range = RANGE_TO_REG( - TEMP_FROM_REG(data->zone[nr].max_desired) - - TEMP_FROM_REG(data->zone[nr].limit)); - lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), - ((data->zone[nr].range & 0x0f) << 4) - | (data->autofan[nr].freq & 0x07)); - -/* Update temp_auto_hyst and temp_auto_off */ - data->zone[nr].hyst = HYST_TO_REG(TEMP_FROM_REG( - data->zone[nr].limit) - TEMP_FROM_REG( - data->zone[nr].off_desired)); - if ( nr == 0 || nr == 1 ) { - lm85_write_value(client, LM85_REG_AFAN_HYST1, - (data->zone[0].hyst << 4) - | data->zone[1].hyst - ); - } else { - lm85_write_value(client, LM85_REG_AFAN_HYST2, - (data->zone[2].hyst << 4) - ); - } - up(&data->update_lock); - return count; -} -static ssize_t show_temp_auto_temp_max(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) + - RANGE_FROM_REG(data->zone[nr].range)); -} -static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - int min; - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - min = TEMP_FROM_REG(data->zone[nr].limit); - data->zone[nr].max_desired = TEMP_TO_REG(val); - data->zone[nr].range = RANGE_TO_REG( - val - min); - lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), - ((data->zone[nr].range & 0x0f) << 4) - | (data->autofan[nr].freq & 0x07)); - up(&data->update_lock); - return count; -} -static ssize_t show_temp_auto_temp_crit(struct device *dev, char *buf, int nr) -{ - struct lm85_data *data = lm85_update_device(dev); - return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].critical)); -} -static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->zone[nr].critical = TEMP_TO_REG(val); - lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr), - data->zone[nr].critical); - up(&data->update_lock); - return count; -} -#define temp_auto(offset) \ -static ssize_t show_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_off(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_off(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_max(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_crit(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_crit(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_auto_temp_off, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_off, \ - set_temp##offset##_auto_temp_off); \ -static DEVICE_ATTR(temp##offset##_auto_temp_min, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_min, \ - set_temp##offset##_auto_temp_min); \ -static DEVICE_ATTR(temp##offset##_auto_temp_max, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_max, \ - set_temp##offset##_auto_temp_max); \ -static DEVICE_ATTR(temp##offset##_auto_temp_crit, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_crit, \ - set_temp##offset##_auto_temp_crit); -temp_auto(1); -temp_auto(2); -temp_auto(3); - -int lm85_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm85_detect); -} - -int lm85_detect(struct i2c_adapter *adapter, int address, - int kind) -{ - int company, verstep ; - struct i2c_client *new_client = NULL; - struct lm85_data *data; - int err = 0; - const char *type_name = ""; - - if (i2c_is_isa_adapter(adapter)) { - /* This chip has no ISA interface */ - goto ERROR0 ; - }; - - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { - /* We need to be able to do byte I/O */ - goto ERROR0 ; - }; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm85_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm85_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - memset(data, 0, sizeof(struct lm85_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm85_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - company = lm85_read_value(new_client, LM85_REG_COMPANY); - verstep = lm85_read_value(new_client, LM85_REG_VERSTEP); - - dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with" - " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", - i2c_adapter_id(new_client->adapter), new_client->addr, - company, verstep); - - /* If auto-detecting, Determine the chip type. */ - if (kind <= 0) { - dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x ...\n", - i2c_adapter_id(adapter), address ); - if( company == LM85_COMPANY_NATIONAL - && verstep == LM85_VERSTEP_LM85C ) { - kind = lm85c ; - } else if( company == LM85_COMPANY_NATIONAL - && verstep == LM85_VERSTEP_LM85B ) { - kind = lm85b ; - } else if( company == LM85_COMPANY_NATIONAL - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) { - dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x" - " Defaulting to LM85.\n", verstep); - kind = any_chip ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && verstep == LM85_VERSTEP_ADM1027 ) { - kind = adm1027 ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && (verstep == LM85_VERSTEP_ADT7463 - || verstep == LM85_VERSTEP_ADT7463C) ) { - kind = adt7463 ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC ) { - dev_err(&adapter->dev, "Unrecognized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( company == LM85_COMPANY_SMSC - && (verstep == LM85_VERSTEP_EMC6D100_A0 - || verstep == LM85_VERSTEP_EMC6D100_A1) ) { - /* Unfortunately, we can't tell a '100 from a '101 - * from the registers. Since a '101 is a '100 - * in a package with fewer pins and therefore no - * 3.3V, 1.5V or 1.8V inputs, perhaps if those - * inputs read 0, then it's a '101. - */ - kind = emc6d100 ; - } else if( company == LM85_COMPANY_SMSC - && verstep == LM85_VERSTEP_EMC6D102) { - kind = emc6d102 ; - } else if( company == LM85_COMPANY_SMSC - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - dev_err(&adapter->dev, "lm85: Detected SMSC chip\n"); - dev_err(&adapter->dev, "lm85: Unrecognized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( kind == any_chip - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - dev_err(&adapter->dev, "Generic LM85 Version 6 detected\n"); - /* Leave kind as "any_chip" */ - } else { - dev_dbg(&adapter->dev, "Autodetection failed\n"); - /* Not an LM85 ... */ - if( kind == any_chip ) { /* User used force=x,y */ - dev_err(&adapter->dev, "Generic LM85 Version 6 not" - " found at %d,0x%02x. Try force_lm85c.\n", - i2c_adapter_id(adapter), address ); - } - err = 0 ; - goto ERROR1; - } - } - - /* Fill in the chip specific driver values */ - if ( kind == any_chip ) { - type_name = "lm85"; - } else if ( kind == lm85b ) { - type_name = "lm85b"; - } else if ( kind == lm85c ) { - type_name = "lm85c"; - } else if ( kind == adm1027 ) { - type_name = "adm1027"; - } else if ( kind == adt7463 ) { - type_name = "adt7463"; - } else if ( kind == emc6d100){ - type_name = "emc6d100"; - } else if ( kind == emc6d102 ) { - type_name = "emc6d102"; - } - strlcpy(new_client->name, type_name, I2C_NAME_SIZE); - - /* Fill in the remaining client fields */ - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Set the VRM version */ - data->vrm = i2c_which_vrm(); - - /* Initialize the LM85 chip */ - lm85_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan3_input); - device_create_file(&new_client->dev, &dev_attr_fan4_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan3_min); - device_create_file(&new_client->dev, &dev_attr_fan4_min); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_pwm3); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, &dev_attr_pwm2_enable); - device_create_file(&new_client->dev, &dev_attr_pwm3_enable); - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_vrm); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_channels); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_channels); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_channels); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_min); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_min); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_min); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_minctl); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_minctl); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_minctl); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_freq); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_freq); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_freq); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_off); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_off); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_off); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_min); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_min); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_min); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_max); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_max); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_max); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_crit); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_crit); - - return 0; - - /* Error out and cleanup code */ - ERROR1: - kfree(data); - ERROR0: - return err; -} - -int lm85_detach_client(struct i2c_client *client) -{ - i2c_detach_client(client); - kfree(i2c_get_clientdata(client)); - return 0; -} - - -int lm85_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - /* What size location is it? */ - switch( reg ) { - case LM85_REG_FAN(0) : /* Read WORD data */ - case LM85_REG_FAN(1) : - case LM85_REG_FAN(2) : - case LM85_REG_FAN(3) : - case LM85_REG_FAN_MIN(0) : - case LM85_REG_FAN_MIN(1) : - case LM85_REG_FAN_MIN(2) : - case LM85_REG_FAN_MIN(3) : - case LM85_REG_ALARM1 : /* Read both bytes at once */ - res = i2c_smbus_read_byte_data(client, reg) & 0xff ; - res |= i2c_smbus_read_byte_data(client, reg+1) << 8 ; - break ; - case ADT7463_REG_TMIN_CTL1 : /* Read WORD MSB, LSB */ - res = i2c_smbus_read_byte_data(client, reg) << 8 ; - res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff ; - break ; - default: /* Read BYTE data */ - res = i2c_smbus_read_byte_data(client, reg); - break ; - } - - return res ; -} - -int lm85_write_value(struct i2c_client *client, u8 reg, int value) -{ - int res ; - - switch( reg ) { - case LM85_REG_FAN(0) : /* Write WORD data */ - case LM85_REG_FAN(1) : - case LM85_REG_FAN(2) : - case LM85_REG_FAN(3) : - case LM85_REG_FAN_MIN(0) : - case LM85_REG_FAN_MIN(1) : - case LM85_REG_FAN_MIN(2) : - case LM85_REG_FAN_MIN(3) : - /* NOTE: ALARM is read only, so not included here */ - res = i2c_smbus_write_byte_data(client, reg, value & 0xff) ; - res |= i2c_smbus_write_byte_data(client, reg+1, (value>>8) & 0xff) ; - break ; - case ADT7463_REG_TMIN_CTL1 : /* Write WORD MSB, LSB */ - res = i2c_smbus_write_byte_data(client, reg, (value>>8) & 0xff); - res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff) ; - break ; - default: /* Write BYTE data */ - res = i2c_smbus_write_byte_data(client, reg, value); - break ; - } - - return res ; -} - -void lm85_init_client(struct i2c_client *client) -{ - int value; - struct lm85_data *data = i2c_get_clientdata(client); - - dev_dbg(&client->dev, "Initializing device\n"); - - /* Warn if part was not "READY" */ - value = lm85_read_value(client, LM85_REG_CONFIG); - dev_dbg(&client->dev, "LM85_REG_CONFIG is: 0x%02x\n", value); - if( value & 0x02 ) { - dev_err(&client->dev, "Client (%d,0x%02x) config is locked.\n", - i2c_adapter_id(client->adapter), client->addr ); - }; - if( ! (value & 0x04) ) { - dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n", - i2c_adapter_id(client->adapter), client->addr ); - }; - if( value & 0x10 - && ( data->type == adm1027 - || data->type == adt7463 ) ) { - dev_err(&client->dev, "Client (%d,0x%02x) VxI mode is set. " - "Please report this to the lm85 maintainer.\n", - i2c_adapter_id(client->adapter), client->addr ); - }; - - /* WE INTENTIONALLY make no changes to the limits, - * offsets, pwms, fans and zones. If they were - * configured, we don't want to mess with them. - * If they weren't, the default is 100% PWM, no - * control and will suffice until 'sensors -s' - * can be run by the user. - */ - - /* Start monitoring */ - value = lm85_read_value(client, LM85_REG_CONFIG); - /* Try to clear LOCK, Set START, save everything else */ - value = (value & ~ 0x02) | 0x01 ; - dev_dbg(&client->dev, "Setting CONFIG to: 0x%02x\n", value); - lm85_write_value(client, LM85_REG_CONFIG, value); -} - -static struct lm85_data *lm85_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm85_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if ( !data->valid || - time_after(jiffies, data->last_reading + LM85_DATA_INTERVAL) ) { - /* Things that change quickly */ - dev_dbg(&client->dev, "Reading sensor values\n"); - - /* Have to read extended bits first to "freeze" the - * more significant bits that are read later. - */ - if ( (data->type == adm1027) || (data->type == adt7463) ) { - int ext1 = lm85_read_value(client, - ADM1027_REG_EXTEND_ADC1); - int ext2 = lm85_read_value(client, - ADM1027_REG_EXTEND_ADC2); - int val = (ext1 << 8) + ext2; - - for(i = 0; i <= 4; i++) - data->in_ext[i] = (val>>(i * 2))&0x03; - - for(i = 0; i <= 2; i++) - data->temp_ext[i] = (val>>((i + 5) * 2))&0x03; - } - - /* adc_scale is 2^(number of LSBs). There are 4 extra bits in - the emc6d102 and 2 in the adt7463 and adm1027. In all - other chips ext is always 0 and the value of scale is - irrelevant. So it is left in 4*/ - data->adc_scale = (data->type == emc6d102 ) ? 16 : 4; - - for (i = 0; i <= 4; ++i) { - data->in[i] = - lm85_read_value(client, LM85_REG_IN(i)); - } - - for (i = 0; i <= 3; ++i) { - data->fan[i] = - lm85_read_value(client, LM85_REG_FAN(i)); - } - - for (i = 0; i <= 2; ++i) { - data->temp[i] = - lm85_read_value(client, LM85_REG_TEMP(i)); - } - - for (i = 0; i <= 2; ++i) { - data->pwm[i] = - lm85_read_value(client, LM85_REG_PWM(i)); - } - - data->alarms = lm85_read_value(client, LM85_REG_ALARM1); - - if ( data->type == adt7463 ) { - if( data->therm_total < ULONG_MAX - 256 ) { - data->therm_total += - lm85_read_value(client, ADT7463_REG_THERM ); - } - } else if ( data->type == emc6d100 ) { - /* Three more voltage sensors */ - for (i = 5; i <= 7; ++i) { - data->in[i] = - lm85_read_value(client, EMC6D100_REG_IN(i)); - } - /* More alarm bits */ - data->alarms |= - lm85_read_value(client, EMC6D100_REG_ALARM3) << 16; - } else if (data->type == emc6d102 ) { - /* Have to read LSB bits after the MSB ones because - the reading of the MSB bits has frozen the - LSBs (backward from the ADM1027). - */ - int ext1 = lm85_read_value(client, - EMC6D102_REG_EXTEND_ADC1); - int ext2 = lm85_read_value(client, - EMC6D102_REG_EXTEND_ADC2); - int ext3 = lm85_read_value(client, - EMC6D102_REG_EXTEND_ADC3); - int ext4 = lm85_read_value(client, - EMC6D102_REG_EXTEND_ADC4); - data->in_ext[0] = ext3 & 0x0f; - data->in_ext[1] = ext4 & 0x0f; - data->in_ext[2] = (ext4 >> 4) & 0x0f; - data->in_ext[3] = (ext3 >> 4) & 0x0f; - data->in_ext[4] = (ext2 >> 4) & 0x0f; - - data->temp_ext[0] = ext1 & 0x0f; - data->temp_ext[1] = ext2 & 0x0f; - data->temp_ext[2] = (ext1 >> 4) & 0x0f; - } - - data->last_reading = jiffies ; - }; /* last_reading */ - - if ( !data->valid || - time_after(jiffies, data->last_config + LM85_CONFIG_INTERVAL) ) { - /* Things that don't change often */ - dev_dbg(&client->dev, "Reading config values\n"); - - for (i = 0; i <= 4; ++i) { - data->in_min[i] = - lm85_read_value(client, LM85_REG_IN_MIN(i)); - data->in_max[i] = - lm85_read_value(client, LM85_REG_IN_MAX(i)); - } - - if ( data->type == emc6d100 ) { - for (i = 5; i <= 7; ++i) { - data->in_min[i] = - lm85_read_value(client, EMC6D100_REG_IN_MIN(i)); - data->in_max[i] = - lm85_read_value(client, EMC6D100_REG_IN_MAX(i)); - } - } - - for (i = 0; i <= 3; ++i) { - data->fan_min[i] = - lm85_read_value(client, LM85_REG_FAN_MIN(i)); - } - - for (i = 0; i <= 2; ++i) { - data->temp_min[i] = - lm85_read_value(client, LM85_REG_TEMP_MIN(i)); - data->temp_max[i] = - lm85_read_value(client, LM85_REG_TEMP_MAX(i)); - } - - data->vid = lm85_read_value(client, LM85_REG_VID); - - for (i = 0; i <= 2; ++i) { - int val ; - data->autofan[i].config = - lm85_read_value(client, LM85_REG_AFAN_CONFIG(i)); - val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i)); - data->autofan[i].freq = val & 0x07 ; - data->zone[i].range = (val >> 4) & 0x0f ; - data->autofan[i].min_pwm = - lm85_read_value(client, LM85_REG_AFAN_MINPWM(i)); - data->zone[i].limit = - lm85_read_value(client, LM85_REG_AFAN_LIMIT(i)); - data->zone[i].critical = - lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i)); - } - - i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); - data->smooth[0] = i & 0x0f ; - data->syncpwm3 = i & 0x10 ; /* Save PWM3 config */ - data->autofan[0].min_off = (i & 0x20) != 0 ; - data->autofan[1].min_off = (i & 0x40) != 0 ; - data->autofan[2].min_off = (i & 0x80) != 0 ; - i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2); - data->smooth[1] = (i>>4) & 0x0f ; - data->smooth[2] = i & 0x0f ; - - i = lm85_read_value(client, LM85_REG_AFAN_HYST1); - data->zone[0].hyst = (i>>4) & 0x0f ; - data->zone[1].hyst = i & 0x0f ; - - i = lm85_read_value(client, LM85_REG_AFAN_HYST2); - data->zone[2].hyst = (i>>4) & 0x0f ; - - if ( (data->type == lm85b) || (data->type == lm85c) ) { - data->tach_mode = lm85_read_value(client, - LM85_REG_TACH_MODE ); - data->spinup_ctl = lm85_read_value(client, - LM85_REG_SPINUP_CTL ); - } else if ( (data->type == adt7463) || (data->type == adm1027) ) { - if ( data->type == adt7463 ) { - for (i = 0; i <= 2; ++i) { - data->oppoint[i] = lm85_read_value(client, - ADT7463_REG_OPPOINT(i) ); - } - data->tmin_ctl = lm85_read_value(client, - ADT7463_REG_TMIN_CTL1 ); - data->therm_limit = lm85_read_value(client, - ADT7463_REG_THERM_LIMIT ); - } - for (i = 0; i <= 2; ++i) { - data->temp_offset[i] = lm85_read_value(client, - ADM1027_REG_TEMP_OFFSET(i) ); - } - data->tach_mode = lm85_read_value(client, - ADM1027_REG_CONFIG3 ); - data->fan_ppr = lm85_read_value(client, - ADM1027_REG_FAN_PPR ); - } - - data->last_config = jiffies; - }; /* last_config */ - - data->valid = 1; - - up(&data->update_lock); - - return data; -} - - -static int __init sm_lm85_init(void) -{ - return i2c_add_driver(&lm85_driver); -} - -static void __exit sm_lm85_exit(void) -{ - i2c_del_driver(&lm85_driver); -} - -/* Thanks to Richard Barrington for adding the LM85 to sensors-detect. - * Thanks to Margit Schubert-While for help with - * post 2.7.0 CVS changes. - */ -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Philip Pokorny , Margit Schubert-While , Justin Thiessen - * Philip Edelbrock - * Stephen Rousset - * Dan Eaton - * Copyright (C) 2004 Jean Delvare - * - * Original port to Linux 2.6 by Jeff Oliver. - * - * The LM87 is a sensor chip made by National Semiconductor. It monitors up - * to 8 voltages (including its own power source), up to three temperatures - * (its own plus up to two external ones) and up to two fans. The default - * configuration is 6 voltages, two temperatures and two fans (see below). - * Voltages are scaled internally with ratios such that the nominal value of - * each voltage correspond to a register value of 192 (which means a - * resolution of about 0.5% of the nominal value). Temperature values are - * reported with a 1 deg resolution and a 3-4 deg accuracy. Complete - * datasheet can be obtained from National's website at: - * http://www.national.com/pf/LM/LM87.html - * - * Some functions share pins, so not all functions are available at the same - * time. Which are depends on the hardware setup. This driver assumes that - * the BIOS configured the chip correctly. In that respect, it differs from - * the original driver (from lm_sensors for Linux 2.4), which would force the - * LM87 to an arbitrary, compile-time chosen mode, regardless of the actual - * chipset wiring. - * For reference, here is the list of exclusive functions: - * - in0+in5 (default) or temp3 - * - fan1 (default) or in6 - * - fan2 (default) or in7 - * - VID lines (default) or IRQ lines (not handled by this driver) - * - * The LM87 additionally features an analog output, supposedly usable to - * control the speed of a fan. All new chips use pulse width modulation - * instead. The LM87 is the only hardware monitoring chipset I know of - * which uses amplitude modulation. Be careful when using this feature. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Addresses to scan - * LM87 has three possible addresses: 0x2c, 0x2d and 0x2e. - */ - -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(lm87); - -/* - * The LM87 registers - */ - -/* nr in 0..5 */ -#define LM87_REG_IN(nr) (0x20 + (nr)) -#define LM87_REG_IN_MAX(nr) (0x2B + (nr) * 2) -#define LM87_REG_IN_MIN(nr) (0x2C + (nr) * 2) -/* nr in 0..1 */ -#define LM87_REG_AIN(nr) (0x28 + (nr)) -#define LM87_REG_AIN_MIN(nr) (0x1A + (nr)) -#define LM87_REG_AIN_MAX(nr) (0x3B + (nr)) - -static u8 LM87_REG_TEMP[3] = { 0x27, 0x26, 0x20 }; -static u8 LM87_REG_TEMP_HIGH[3] = { 0x39, 0x37, 0x2B }; -static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; - -#define LM87_REG_TEMP_HW_INT_LOCK 0x13 -#define LM87_REG_TEMP_HW_EXT_LOCK 0x14 -#define LM87_REG_TEMP_HW_INT 0x17 -#define LM87_REG_TEMP_HW_EXT 0x18 - -/* nr in 0..1 */ -#define LM87_REG_FAN(nr) (0x28 + (nr)) -#define LM87_REG_FAN_MIN(nr) (0x3B + (nr)) -#define LM87_REG_AOUT 0x19 - -#define LM87_REG_CONFIG 0x40 -#define LM87_REG_CHANNEL_MODE 0x16 -#define LM87_REG_VID_FAN_DIV 0x47 -#define LM87_REG_VID4 0x49 - -#define LM87_REG_ALARMS1 0x41 -#define LM87_REG_ALARMS2 0x42 - -#define LM87_REG_COMPANY_ID 0x3E -#define LM87_REG_REVISION 0x3F - -/* - * Conversions and various macros - * The LM87 uses signed 8-bit values for temperatures. - */ - -#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) -#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ - (val) * 192 >= (scale) * 255 ? 255 : \ - ((val) * 192 + (scale)/2) / (scale)) - -#define TEMP_FROM_REG(reg) ((reg) * 1000) -#define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \ - (val) >= 126500 ? 127 : \ - (((val) < 0 ? (val)-500 : (val)+500) / 1000)) - -#define FAN_FROM_REG(reg,div) ((reg) == 255 || (reg) == 0 ? 0 : \ - 1350000 + (reg)*(div) / 2) / ((reg)*(div)) -#define FAN_TO_REG(val,div) ((val)*(div) * 255 <= 1350000 ? 255 : \ - (1350000 + (val)*(div) / 2) / ((val)*(div))) - -#define FAN_DIV_FROM_REG(reg) (1 << (reg)) - -/* analog out is 9.80mV/LSB */ -#define AOUT_FROM_REG(reg) (((reg) * 98 + 5) / 10) -#define AOUT_TO_REG(val) ((val) <= 0 ? 0 : \ - (val) >= 2500 ? 255 : \ - ((val) * 10 + 49) / 98) - -/* nr in 0..1 */ -#define CHAN_NO_FAN(nr) (1 << (nr)) -#define CHAN_TEMP3 (1 << 2) -#define CHAN_VCC_5V (1 << 3) -#define CHAN_NO_VID (1 << 8) - -/* - * Functions declaration - */ - -static int lm87_attach_adapter(struct i2c_adapter *adapter); -static int lm87_detect(struct i2c_adapter *adapter, int address, int kind); -static void lm87_init_client(struct i2c_client *client); -static int lm87_detach_client(struct i2c_client *client); -static struct lm87_data *lm87_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm87_driver = { - .owner = THIS_MODULE, - .name = "lm87", - .id = I2C_DRIVERID_LM87, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm87_attach_adapter, - .detach_client = lm87_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm87_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 channel; /* register value */ - - u8 in[8]; /* register value */ - u8 in_max[8]; /* register value */ - u8 in_min[8]; /* register value */ - u16 in_scale[8]; - - s8 temp[3]; /* register value */ - s8 temp_high[3]; /* register value */ - s8 temp_low[3]; /* register value */ - s8 temp_crit_int; /* min of two register values */ - s8 temp_crit_ext; /* min of two register values */ - - u8 fan[2]; /* register value */ - u8 fan_min[2]; /* register value */ - u8 fan_div[2]; /* register value, shifted right */ - u8 aout; /* register value */ - - u16 alarms; /* register values, combined */ - u8 vid; /* register values, combined */ - u8 vrm; -}; - -/* - * Sysfs stuff - */ - -static inline int lm87_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -#define show_in(offset) \ -static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ - data->in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ - data->in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ - data->in_scale[offset])); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset##_input, NULL); -show_in(0); -show_in(1); -show_in(2); -show_in(3); -show_in(4); -show_in(5); -show_in(6); -show_in(7); - -static void set_in_min(struct device *dev, const char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]); - lm87_write_value(client, nr<6 ? LM87_REG_IN_MIN(nr) : - LM87_REG_AIN_MIN(nr-6), data->in_min[nr]); - up(&data->update_lock); -} - -static void set_in_max(struct device *dev, const char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]); - lm87_write_value(client, nr<6 ? LM87_REG_IN_MAX(nr) : - LM87_REG_AIN_MAX(nr-6), data->in_max[nr]); - up(&data->update_lock); -} - -#define set_in(offset) \ -static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_in_min(dev, buf, offset); \ - return count; \ -} \ -static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_in_max(dev, buf, offset); \ - return count; \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); -set_in(0); -set_in(1); -set_in(2); -set_in(3); -set_in(4); -set_in(5); -set_in(6); -set_in(7); - -#define show_temp(offset) \ -static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ -} \ -static ssize_t show_temp##offset##_low(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[offset-1])); \ -} \ -static ssize_t show_temp##offset##_high(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[offset-1])); \ -}\ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_temp##offset##_input, NULL); -show_temp(1); -show_temp(2); -show_temp(3); - -static void set_temp_low(struct device *dev, const char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_low[nr] = TEMP_TO_REG(val); - lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]); - up(&data->update_lock); -} - -static void set_temp_high(struct device *dev, const char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_high[nr] = TEMP_TO_REG(val); - lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]); - up(&data->update_lock); -} - -#define set_temp(offset) \ -static ssize_t set_temp##offset##_low(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_temp_low(dev, buf, offset-1); \ - return count; \ -} \ -static ssize_t set_temp##offset##_high(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_temp_high(dev, buf, offset-1); \ - return count; \ -} \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp##offset##_high, set_temp##offset##_high); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp##offset##_low, set_temp##offset##_low); -set_temp(1); -set_temp(2); -set_temp(3); - -static ssize_t show_temp_crit_int(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_int)); -} - -static ssize_t show_temp_crit_ext(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_ext)); -} - -static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit_int, NULL); -static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit_ext, NULL); -static DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit_ext, NULL); - -#define show_fan(offset) \ -static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[offset-1], \ - FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ -} \ -static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[offset-1], \ - FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ -} \ -static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[offset-1])); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan##offset##_input, NULL); -show_fan(1); -show_fan(2); - -static void set_fan_min(struct device *dev, const char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, - FAN_DIV_FROM_REG(data->fan_div[nr])); - lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan clock divider. This follows the principle - of least suprise; the user doesn't expect the fan minimum to change just - because the divider changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - unsigned long min; - u8 reg; - - down(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], - FAN_DIV_FROM_REG(data->fan_div[nr])); - - switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; - default: - up(&data->update_lock); - return -EINVAL; - } - - reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV); - switch (nr) { - case 0: - reg = (reg & 0xCF) | (data->fan_div[0] << 4); - break; - case 1: - reg = (reg & 0x3F) | (data->fan_div[1] << 6); - break; - } - lm87_write_value(client, LM87_REG_VID_FAN_DIV, reg); - - data->fan_min[nr] = FAN_TO_REG(min, val); - lm87_write_value(client, LM87_REG_FAN_MIN(nr), - data->fan_min[nr]); - up(&data->update_lock); - - return count; -} - -#define set_fan(offset) \ -static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - set_fan_min(dev, buf, offset-1); \ - return count; \ -} \ -static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset-1); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan##offset##_min, set_fan##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan##offset##_div, set_fan##offset##_div); -set_fan(1); -set_fan(2); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", data->vrm); -} -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - data->vrm = simple_strtoul(buf, NULL, 10); - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); - -static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm87_data *data = lm87_update_device(dev); - return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); -} -static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->aout = AOUT_TO_REG(val); - lm87_write_value(client, LM87_REG_AOUT, data->aout); - up(&data->update_lock); - return count; -} -static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); - -/* - * Real code - */ - -static int lm87_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm87_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm87_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm87_data)); - - /* The common I2C client data is placed right before the - LM87-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm87_driver; - new_client->flags = 0; - - /* Default to an LM87 if forced */ - if (kind == 0) - kind = lm87; - - /* Now, we do the remaining detection. */ - if (kind < 0) { - u8 rev = lm87_read_value(new_client, LM87_REG_REVISION); - - if (rev < 0x01 || rev > 0x08 - || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80) - || lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02) { - dev_dbg(&adapter->dev, - "LM87 detection failed at 0x%02x.\n", - address); - goto exit_free; - } - } - - /* We can fill in the remaining client fields */ - strlcpy(new_client->name, "lm87", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the LM87 chip */ - lm87_init_client(new_client); - - data->in_scale[0] = 2500; - data->in_scale[1] = 2700; - data->in_scale[2] = (data->channel & CHAN_VCC_5V) ? 5000 : 3300; - data->in_scale[3] = 5000; - data->in_scale[4] = 12000; - data->in_scale[5] = 2700; - data->in_scale[6] = 1875; - data->in_scale[7] = 1875; - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - - if (data->channel & CHAN_NO_FAN(0)) { - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in6_max); - } else { - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - } - if (data->channel & CHAN_NO_FAN(1)) { - device_create_file(&new_client->dev, &dev_attr_in7_input); - device_create_file(&new_client->dev, &dev_attr_in7_min); - device_create_file(&new_client->dev, &dev_attr_in7_max); - } else { - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - } - - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - - if (data->channel & CHAN_TEMP3) { - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp3_crit); - } else { - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in5_max); - } - - if (!(data->channel & CHAN_NO_VID)) { - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_vrm); - } - - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_aout_output); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static void lm87_init_client(struct i2c_client *client) -{ - struct lm87_data *data = i2c_get_clientdata(client); - u8 config; - - data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE); - data->vrm = i2c_which_vrm(); - - config = lm87_read_value(client, LM87_REG_CONFIG); - if (!(config & 0x01)) { - int i; - - /* Limits are left uninitialized after power-up */ - for (i = 1; i < 6; i++) { - lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00); - lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF); - } - for (i = 0; i < 2; i++) { - lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F); - lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00); - lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00); - lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF); - } - if (data->channel & CHAN_TEMP3) { - lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F); - lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00); - } else { - lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00); - lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF); - } - } - if ((config & 0x81) != 0x01) { - /* Start monitoring */ - lm87_write_value(client, LM87_REG_CONFIG, - (config & 0xF7) | 0x01); - } -} - -static int lm87_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - -static struct lm87_data *lm87_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - int i, j; - - dev_dbg(&client->dev, "Updating data.\n"); - - i = (data->channel & CHAN_TEMP3) ? 1 : 0; - j = (data->channel & CHAN_TEMP3) ? 5 : 6; - for (; i < j; i++) { - data->in[i] = lm87_read_value(client, - LM87_REG_IN(i)); - data->in_min[i] = lm87_read_value(client, - LM87_REG_IN_MIN(i)); - data->in_max[i] = lm87_read_value(client, - LM87_REG_IN_MAX(i)); - } - - for (i = 0; i < 2; i++) { - if (data->channel & CHAN_NO_FAN(i)) { - data->in[6+i] = lm87_read_value(client, - LM87_REG_AIN(i)); - data->in_max[6+i] = lm87_read_value(client, - LM87_REG_AIN_MAX(i)); - data->in_min[6+i] = lm87_read_value(client, - LM87_REG_AIN_MIN(i)); - - } else { - data->fan[i] = lm87_read_value(client, - LM87_REG_FAN(i)); - data->fan_min[i] = lm87_read_value(client, - LM87_REG_FAN_MIN(i)); - } - } - - j = (data->channel & CHAN_TEMP3) ? 3 : 2; - for (i = 0 ; i < j; i++) { - data->temp[i] = lm87_read_value(client, - LM87_REG_TEMP[i]); - data->temp_high[i] = lm87_read_value(client, - LM87_REG_TEMP_HIGH[i]); - data->temp_low[i] = lm87_read_value(client, - LM87_REG_TEMP_LOW[i]); - } - - i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK); - j = lm87_read_value(client, LM87_REG_TEMP_HW_INT); - data->temp_crit_int = min(i, j); - - i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK); - j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT); - data->temp_crit_ext = min(i, j); - - i = lm87_read_value(client, LM87_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->vid = (i & 0x0F) - | (lm87_read_value(client, LM87_REG_VID4) & 0x01) - << 4; - - data->alarms = lm87_read_value(client, LM87_REG_ALARMS1) - | (lm87_read_value(client, LM87_REG_ALARMS2) - << 8); - data->aout = lm87_read_value(client, LM87_REG_AOUT); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm87_init(void) -{ - return i2c_add_driver(&lm87_driver); -} - -static void __exit sensors_lm87_exit(void) -{ - i2c_del_driver(&lm87_driver); -} - -MODULE_AUTHOR("Jean Delvare and others"); -MODULE_DESCRIPTION("LM87 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm87_init); -module_exit(sensors_lm87_exit); diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c deleted file mode 100644 index a67dcadf7cb..00000000000 --- a/drivers/i2c/chips/lm90.c +++ /dev/null @@ -1,655 +0,0 @@ -/* - * lm90.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2005 Jean Delvare - * - * Based on the lm83 driver. The LM90 is a sensor chip made by National - * Semiconductor. It reports up to two temperatures (its own plus up to - * one external one) with a 0.125 deg resolution (1 deg for local - * temperature) and a 3-4 deg accuracy. Complete datasheet can be - * obtained from National's website at: - * http://www.national.com/pf/LM/LM90.html - * - * This driver also supports the LM89 and LM99, two other sensor chips - * made by National Semiconductor. Both have an increased remote - * temperature measurement accuracy (1 degree), and the LM99 - * additionally shifts remote temperatures (measured and limits) by 16 - * degrees, which allows for higher temperatures measurement. The - * driver doesn't handle it since it can be done easily in user-space. - * Complete datasheets can be obtained from National's website at: - * http://www.national.com/pf/LM/LM89.html - * http://www.national.com/pf/LM/LM99.html - * Note that there is no way to differentiate between both chips. - * - * This driver also supports the LM86, another sensor chip made by - * National Semiconductor. It is exactly similar to the LM90 except it - * has a higher accuracy. - * Complete datasheet can be obtained from National's website at: - * http://www.national.com/pf/LM/LM86.html - * - * This driver also supports the ADM1032, a sensor chip made by Analog - * Devices. That chip is similar to the LM90, with a few differences - * that are not handled by this driver. Complete datasheet can be - * obtained from Analog's website at: - * http://products.analog.com/products/info.asp?product=ADM1032 - * Among others, it has a higher accuracy than the LM90, much like the - * LM86 does. - * - * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor - * chips made by Maxim. These chips are similar to the LM86. Complete - * datasheet can be obtained at Maxim's website at: - * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 - * Note that there is no easy way to differentiate between the three - * variants. The extra address and features of the MAX6659 are not - * supported by this driver. - * - * This driver also supports the ADT7461 chip from Analog Devices but - * only in its "compatability mode". If an ADT7461 chip is found but - * is configured in non-compatible mode (where its temperature - * register values are decoded differently) it is ignored by this - * driver. Complete datasheet can be obtained from Analog's website - * at: - * http://products.analog.com/products/info.asp?product=ADT7461 - * - * Since the LM90 was the first chipset supported by this driver, most - * comments will refer to this chipset, but are actually general and - * concern all supported chipsets, unless mentioned otherwise. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Addresses to scan - * Address is fully defined internally and cannot be changed except for - * MAX6659. - * LM86, LM89, LM90, LM99, ADM1032, MAX6657 and MAX6658 have address 0x4c. - * LM89-1, and LM99-1 have address 0x4d. - * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported). - * ADT7461 always has address 0x4c. - */ - -static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461); - -/* - * The LM90 registers - */ - -#define LM90_REG_R_MAN_ID 0xFE -#define LM90_REG_R_CHIP_ID 0xFF -#define LM90_REG_R_CONFIG1 0x03 -#define LM90_REG_W_CONFIG1 0x09 -#define LM90_REG_R_CONFIG2 0xBF -#define LM90_REG_W_CONFIG2 0xBF -#define LM90_REG_R_CONVRATE 0x04 -#define LM90_REG_W_CONVRATE 0x0A -#define LM90_REG_R_STATUS 0x02 -#define LM90_REG_R_LOCAL_TEMP 0x00 -#define LM90_REG_R_LOCAL_HIGH 0x05 -#define LM90_REG_W_LOCAL_HIGH 0x0B -#define LM90_REG_R_LOCAL_LOW 0x06 -#define LM90_REG_W_LOCAL_LOW 0x0C -#define LM90_REG_R_LOCAL_CRIT 0x20 -#define LM90_REG_W_LOCAL_CRIT 0x20 -#define LM90_REG_R_REMOTE_TEMPH 0x01 -#define LM90_REG_R_REMOTE_TEMPL 0x10 -#define LM90_REG_R_REMOTE_OFFSH 0x11 -#define LM90_REG_W_REMOTE_OFFSH 0x11 -#define LM90_REG_R_REMOTE_OFFSL 0x12 -#define LM90_REG_W_REMOTE_OFFSL 0x12 -#define LM90_REG_R_REMOTE_HIGHH 0x07 -#define LM90_REG_W_REMOTE_HIGHH 0x0D -#define LM90_REG_R_REMOTE_HIGHL 0x13 -#define LM90_REG_W_REMOTE_HIGHL 0x13 -#define LM90_REG_R_REMOTE_LOWH 0x08 -#define LM90_REG_W_REMOTE_LOWH 0x0E -#define LM90_REG_R_REMOTE_LOWL 0x14 -#define LM90_REG_W_REMOTE_LOWL 0x14 -#define LM90_REG_R_REMOTE_CRIT 0x19 -#define LM90_REG_W_REMOTE_CRIT 0x19 -#define LM90_REG_R_TCRIT_HYST 0x21 -#define LM90_REG_W_TCRIT_HYST 0x21 - -/* - * Conversions and various macros - * For local temperatures and limits, critical limits and the hysteresis - * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius. - * For remote temperatures and limits, it uses signed 11-bit values with - * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. - */ - -#define TEMP1_FROM_REG(val) ((val) * 1000) -#define TEMP1_TO_REG(val) ((val) <= -128000 ? -128 : \ - (val) >= 127000 ? 127 : \ - (val) < 0 ? ((val) - 500) / 1000 : \ - ((val) + 500) / 1000) -#define TEMP2_FROM_REG(val) ((val) / 32 * 125) -#define TEMP2_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ - (val) >= 127875 ? 0x7FE0 : \ - (val) < 0 ? ((val) - 62) / 125 * 32 : \ - ((val) + 62) / 125 * 32) -#define HYST_TO_REG(val) ((val) <= 0 ? 0 : (val) >= 30500 ? 31 : \ - ((val) + 500) / 1000) - -/* - * ADT7461 is almost identical to LM90 except that attempts to write - * values that are outside the range 0 < temp < 127 are treated as - * the boundary value. - */ - -#define TEMP1_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ - (val) >= 127000 ? 127 : \ - ((val) + 500) / 1000) -#define TEMP2_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ - (val) >= 127750 ? 0x7FC0 : \ - ((val) + 125) / 250 * 64) - -/* - * Functions declaration - */ - -static int lm90_attach_adapter(struct i2c_adapter *adapter); -static int lm90_detect(struct i2c_adapter *adapter, int address, - int kind); -static void lm90_init_client(struct i2c_client *client); -static int lm90_detach_client(struct i2c_client *client); -static struct lm90_data *lm90_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm90_driver = { - .owner = THIS_MODULE, - .name = "lm90", - .id = I2C_DRIVERID_LM90, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm90_attach_adapter, - .detach_client = lm90_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm90_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - int kind; - - /* registers values */ - s8 temp8[5]; /* 0: local input - 1: local low limit - 2: local high limit - 3: local critical limit - 4: remote critical limit */ - s16 temp11[3]; /* 0: remote input - 1: remote low limit - 2: remote high limit */ - u8 temp_hyst; - u8 alarms; /* bitvector */ -}; - -/* - * Sysfs stuff - */ - -static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm90_data *data = lm90_update_device(dev); - return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index])); -} - -static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - static const u8 reg[4] = { - LM90_REG_W_LOCAL_LOW, - LM90_REG_W_LOCAL_HIGH, - LM90_REG_W_LOCAL_CRIT, - LM90_REG_W_REMOTE_CRIT, - }; - - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - int nr = attr->index; - - down(&data->update_lock); - if (data->kind == adt7461) - data->temp8[nr] = TEMP1_TO_REG_ADT7461(val); - else - data->temp8[nr] = TEMP1_TO_REG(val); - i2c_smbus_write_byte_data(client, reg[nr - 1], data->temp8[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm90_data *data = lm90_update_device(dev); - return sprintf(buf, "%d\n", TEMP2_FROM_REG(data->temp11[attr->index])); -} - -static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - static const u8 reg[4] = { - LM90_REG_W_REMOTE_LOWH, - LM90_REG_W_REMOTE_LOWL, - LM90_REG_W_REMOTE_HIGHH, - LM90_REG_W_REMOTE_HIGHL, - }; - - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - int nr = attr->index; - - down(&data->update_lock); - if (data->kind == adt7461) - data->temp11[nr] = TEMP2_TO_REG_ADT7461(val); - else - data->temp11[nr] = TEMP2_TO_REG(val); - i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], - data->temp11[nr] >> 8); - i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], - data->temp11[nr] & 0xff); - up(&data->update_lock); - return count; -} - -static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct lm90_data *data = lm90_update_device(dev); - return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index]) - - TEMP1_FROM_REG(data->temp_hyst)); -} - -static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - long hyst; - - down(&data->update_lock); - hyst = TEMP1_FROM_REG(data->temp8[3]) - val; - i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, - HYST_TO_REG(hyst)); - up(&data->update_lock); - return count; -} - -static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, - char *buf) -{ - struct lm90_data *data = lm90_update_device(dev); - return sprintf(buf, "%d\n", data->alarms); -} - -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); -static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 1); -static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 1); -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 2); -static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 2); -static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 3); -static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 4); -static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, - set_temphyst, 3); -static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* - * Real code - */ - -static int lm90_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm90_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm90_data *data; - int err = 0; - const char *name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct lm90_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm90_data)); - - /* The common I2C client data is placed right before the - LM90-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm90_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - - /* Default to an LM90 if forced */ - if (kind == 0) - kind = lm90; - - if (kind < 0) { /* detection and identification */ - u8 man_id, chip_id, reg_config1, reg_convrate; - - man_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CHIP_ID); - reg_config1 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG1); - reg_convrate = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONVRATE); - - if (man_id == 0x01) { /* National Semiconductor */ - u8 reg_config2; - - reg_config2 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG2); - - if ((reg_config1 & 0x2A) == 0x00 - && (reg_config2 & 0xF8) == 0x00 - && reg_convrate <= 0x09) { - if (address == 0x4C - && (chip_id & 0xF0) == 0x20) { /* LM90 */ - kind = lm90; - } else - if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */ - kind = lm99; - } else - if (address == 0x4C - && (chip_id & 0xF0) == 0x10) { /* LM86 */ - kind = lm86; - } - } - } else - if (man_id == 0x41) { /* Analog Devices */ - if (address == 0x4C - && (chip_id & 0xF0) == 0x40 /* ADM1032 */ - && (reg_config1 & 0x3F) == 0x00 - && reg_convrate <= 0x0A) { - kind = adm1032; - } else - if (address == 0x4c - && chip_id == 0x51 /* ADT7461 */ - && (reg_config1 & 0x1F) == 0x00 /* check compat mode */ - && reg_convrate <= 0x0A) { - kind = adt7461; - } - } else - if (man_id == 0x4D) { /* Maxim */ - /* - * The Maxim variants do NOT have a chip_id register. - * Reading from that address will return the last read - * value, which in our case is those of the man_id - * register. Likewise, the config1 register seems to - * lack a low nibble, so the value will be those of the - * previous read, so in our case those of the man_id - * register. - */ - if (chip_id == man_id - && (reg_config1 & 0x1F) == (man_id & 0x0F) - && reg_convrate <= 0x09) { - kind = max6657; - } - } - - if (kind <= 0) { /* identification failed */ - dev_info(&adapter->dev, - "Unsupported chip (man_id=0x%02X, " - "chip_id=0x%02X).\n", man_id, chip_id); - goto exit_free; - } - } - - if (kind == lm90) { - name = "lm90"; - } else if (kind == adm1032) { - name = "adm1032"; - } else if (kind == lm99) { - name = "lm99"; - } else if (kind == lm86) { - name = "lm86"; - } else if (kind == max6657) { - name = "max6657"; - } else if (kind == adt7461) { - name = "adt7461"; - } - - /* We can fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - data->kind = kind; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the LM90 chip */ - lm90_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_crit_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit_hyst.dev_attr); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static void lm90_init_client(struct i2c_client *client) -{ - u8 config; - - /* - * Start the conversions. - */ - i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, - 5); /* 2 Hz */ - config = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1); - if (config & 0x40) - i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, - config & 0xBF); /* run */ -} - -static int lm90_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - -static struct lm90_data *lm90_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm90_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - u8 oldh, newh; - - dev_dbg(&client->dev, "Updating lm90 data.\n"); - data->temp8[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_TEMP); - data->temp8[1] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_LOW); - data->temp8[2] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_HIGH); - data->temp8[3] = i2c_smbus_read_byte_data(client, - LM90_REG_R_LOCAL_CRIT); - data->temp8[4] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_CRIT); - data->temp_hyst = i2c_smbus_read_byte_data(client, - LM90_REG_R_TCRIT_HYST); - - /* - * There is a trick here. We have to read two registers to - * have the remote sensor temperature, but we have to beware - * a conversion could occur inbetween the readings. The - * datasheet says we should either use the one-shot - * conversion register, which we don't want to do (disables - * hardware monitoring) or monitor the busy bit, which is - * impossible (we can't read the values and monitor that bit - * at the exact same time). So the solution used here is to - * read the high byte once, then the low byte, then the high - * byte again. If the new high byte matches the old one, - * then we have a valid reading. Else we have to read the low - * byte again, and now we believe we have a correct reading. - */ - oldh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - data->temp11[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); - newh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - if (newh != oldh) { - data->temp11[0] = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPL); -#ifdef DEBUG - oldh = i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_TEMPH); - /* oldh is actually newer */ - if (newh != oldh) - dev_warn(&client->dev, "Remote temperature may be " - "wrong.\n"); -#endif - } - data->temp11[0] |= (newh << 8); - - data->temp11[1] = (i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWH) << 8) + - i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_LOWL); - data->temp11[2] = (i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_HIGHH) << 8) + - i2c_smbus_read_byte_data(client, - LM90_REG_R_REMOTE_HIGHL); - data->alarms = i2c_smbus_read_byte_data(client, - LM90_REG_R_STATUS); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_lm90_init(void) -{ - return i2c_add_driver(&lm90_driver); -} - -static void __exit sensors_lm90_exit(void) -{ - i2c_del_driver(&lm90_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM90/ADM1032 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm90_init); -module_exit(sensors_lm90_exit); diff --git a/drivers/i2c/chips/lm92.c b/drivers/i2c/chips/lm92.c deleted file mode 100644 index 215c8e40ffd..00000000000 --- a/drivers/i2c/chips/lm92.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * lm92 - Hardware monitoring driver - * Copyright (C) 2005 Jean Delvare - * - * Based on the lm90 driver, with some ideas taken from the lm_sensors - * lm92 driver as well. - * - * The LM92 is a sensor chip made by National Semiconductor. It reports - * its own temperature with a 0.0625 deg resolution and a 0.33 deg - * accuracy. Complete datasheet can be obtained from National's website - * at: - * http://www.national.com/pf/LM/LM92.html - * - * This driver also supports the MAX6635 sensor chip made by Maxim. - * This chip is compatible with the LM92, but has a lesser accuracy - * (1.0 deg). Complete datasheet can be obtained from Maxim's website - * at: - * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074 - * - * Since the LM92 was the first chipset supported by this driver, most - * comments will refer to this chipset, but are actually general and - * concern all supported chipsets, unless mentioned otherwise. - * - * Support could easily be added for the National Semiconductor LM76 - * and Maxim MAX6633 and MAX6634 chips, which are mostly compatible - * with the LM92. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - - -/* The LM92 and MAX6635 have 2 two-state pins for address selection, - resulting in 4 possible addresses. */ -static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, - I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm92); - -/* The LM92 registers */ -#define LM92_REG_CONFIG 0x01 /* 8-bit, RW */ -#define LM92_REG_TEMP 0x00 /* 16-bit, RO */ -#define LM92_REG_TEMP_HYST 0x02 /* 16-bit, RW */ -#define LM92_REG_TEMP_CRIT 0x03 /* 16-bit, RW */ -#define LM92_REG_TEMP_LOW 0x04 /* 16-bit, RW */ -#define LM92_REG_TEMP_HIGH 0x05 /* 16-bit, RW */ -#define LM92_REG_MAN_ID 0x07 /* 16-bit, RO, LM92 only */ - -/* The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius, - left-justified in 16-bit registers. No rounding is done, with such - a resolution it's just not worth it. Note that the MAX6635 doesn't - make use of the 4 lower bits for limits (i.e. effective resolution - for limits is 1 degree Celsius). */ -static inline int TEMP_FROM_REG(s16 reg) -{ - return reg / 8 * 625 / 10; -} - -static inline s16 TEMP_TO_REG(int val) -{ - if (val <= -60000) - return -60000 * 10 / 625 * 8; - if (val >= 160000) - return 160000 * 10 / 625 * 8; - return val * 10 / 625 * 8; -} - -/* Alarm flags are stored in the 3 LSB of the temperature register */ -static inline u8 ALARMS_FROM_REG(s16 reg) -{ - return reg & 0x0007; -} - -/* Driver data (common to all clients) */ -static struct i2c_driver lm92_driver; - -/* Client data (each client gets its own) */ -struct lm92_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst; -}; - - -/* - * Sysfs attributes and callback functions - */ - -static struct lm92_data *lm92_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm92_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) - || !data->valid) { - dev_dbg(&client->dev, "Updating lm92 data\n"); - data->temp1_input = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP)); - data->temp1_hyst = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HYST)); - data->temp1_crit = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_CRIT)); - data->temp1_min = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_LOW)); - data->temp1_max = swab16(i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HIGH)); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -#define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm92_data *data = lm92_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ -} -show_temp(temp1_input); -show_temp(temp1_crit); -show_temp(temp1_min); -show_temp(temp1_max); - -#define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm92_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(val); \ - i2c_smbus_write_word_data(client, reg, swab16(data->value)); \ - up(&data->update_lock); \ - return count; \ -} -set_temp(temp1_crit, LM92_REG_TEMP_CRIT); -set_temp(temp1_min, LM92_REG_TEMP_LOW); -set_temp(temp1_max, LM92_REG_TEMP_HIGH); - -static ssize_t show_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit) - - TEMP_FROM_REG(data->temp1_hyst)); -} -static ssize_t show_temp1_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max) - - TEMP_FROM_REG(data->temp1_hyst)); -} -static ssize_t show_temp1_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min) - + TEMP_FROM_REG(data->temp1_hyst)); -} - -static ssize_t set_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm92_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val; - i2c_smbus_write_word_data(client, LM92_REG_TEMP_HYST, - swab16(TEMP_TO_REG(data->temp1_hyst))); - up(&data->update_lock); - return count; -} - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lm92_data *data = lm92_update_device(dev); - return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input)); -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit, - set_temp1_crit); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst, - set_temp1_crit_hyst); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min, - set_temp1_min); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max, - set_temp1_max); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - - -/* - * Detection and registration - */ - -static void lm92_init_client(struct i2c_client *client) -{ - u8 config; - - /* Start the conversions if needed */ - config = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); - if (config & 0x01) - i2c_smbus_write_byte_data(client, LM92_REG_CONFIG, - config & 0xFE); -} - -/* The MAX6635 has no identification register, so we have to use tricks - to identify it reliably. This is somewhat slow. - Note that we do NOT rely on the 2 MSB of the configuration register - always reading 0, as suggested by the datasheet, because it was once - reported not to be true. */ -static int max6635_check(struct i2c_client *client) -{ - u16 temp_low, temp_high, temp_hyst, temp_crit; - u8 conf; - int i; - - /* No manufacturer ID register, so a read from this address will - always return the last read value. */ - temp_low = i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW); - if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_low) - return 0; - temp_high = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HIGH); - if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_high) - return 0; - - /* Limits are stored as integer values (signed, 9-bit). */ - if ((temp_low & 0x7f00) || (temp_high & 0x7f00)) - return 0; - temp_hyst = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HYST); - temp_crit = i2c_smbus_read_word_data(client, LM92_REG_TEMP_CRIT); - if ((temp_hyst & 0x7f00) || (temp_crit & 0x7f00)) - return 0; - - /* Registers addresses were found to cycle over 16-byte boundaries. - We don't test all registers with all offsets so as to save some - reads and time, but this should still be sufficient to dismiss - non-MAX6635 chips. */ - conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); - for (i=16; i<96; i*=2) { - if (temp_hyst != i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HYST + i - 16) - || temp_crit != i2c_smbus_read_word_data(client, - LM92_REG_TEMP_CRIT + i) - || temp_low != i2c_smbus_read_word_data(client, - LM92_REG_TEMP_LOW + i + 16) - || temp_high != i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HIGH + i + 32) - || conf != i2c_smbus_read_byte_data(client, - LM92_REG_CONFIG + i)) - return 0; - } - - return 1; -} - -/* The following function does more than just detection. If detection - succeeds, it also registers the new chip. */ -static int lm92_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct lm92_data *data; - int err = 0; - char *name; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA - | I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct lm92_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct lm92_data)); - - /* Fill in enough client fields so that we can read from the chip, - which is required for identication */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm92_driver; - new_client->flags = 0; - - /* A negative kind means that the driver was loaded with no force - parameter (default), so we must identify the chip. */ - if (kind < 0) { - u8 config = i2c_smbus_read_byte_data(new_client, - LM92_REG_CONFIG); - u16 man_id = i2c_smbus_read_word_data(new_client, - LM92_REG_MAN_ID); - - if ((config & 0xe0) == 0x00 - && man_id == 0x0180) { - pr_info("lm92: Found National Semiconductor LM92 chip\n"); - kind = lm92; - } else - if (max6635_check(new_client)) { - pr_info("lm92: Found Maxim MAX6635 chip\n"); - kind = lm92; /* No separate prefix */ - } - else - goto exit_free; - } else - if (kind == 0) /* Default to an LM92 if forced */ - kind = lm92; - - /* Give it the proper name */ - if (kind == lm92) { - name = "lm92"; - } else { /* Supposedly cannot happen */ - dev_dbg(&new_client->dev, "Kind out of range?\n"); - goto exit_free; - } - - /* Fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the i2c subsystem a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the chipset */ - lm92_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int lm92_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, lm92_detect); -} - -static int lm92_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - - -/* - * Module and driver stuff - */ - -static struct i2c_driver lm92_driver = { - .owner = THIS_MODULE, - .name = "lm92", - .id = I2C_DRIVERID_LM92, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm92_attach_adapter, - .detach_client = lm92_detach_client, -}; - -static int __init sensors_lm92_init(void) -{ - return i2c_add_driver(&lm92_driver); -} - -static void __exit sensors_lm92_exit(void) -{ - i2c_del_driver(&lm92_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM92/MAX6635 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_lm92_init); -module_exit(sensors_lm92_exit); diff --git a/drivers/i2c/chips/max1619.c b/drivers/i2c/chips/max1619.c deleted file mode 100644 index bf553dcd97d..00000000000 --- a/drivers/i2c/chips/max1619.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * max1619.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2004 Alexey Fisher - * Jean Delvare - * - * Based on the lm90 driver. The MAX1619 is a sensor chip made by Maxim. - * It reports up to two temperatures (its own plus up to - * one external one). Complete datasheet can be - * obtained from Maxim's website at: - * http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include - - -static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, - 0x29, 0x2a, 0x2b, - 0x4c, 0x4d, 0x4e, - I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(max1619); - -/* - * The MAX1619 registers - */ - -#define MAX1619_REG_R_MAN_ID 0xFE -#define MAX1619_REG_R_CHIP_ID 0xFF -#define MAX1619_REG_R_CONFIG 0x03 -#define MAX1619_REG_W_CONFIG 0x09 -#define MAX1619_REG_R_CONVRATE 0x04 -#define MAX1619_REG_W_CONVRATE 0x0A -#define MAX1619_REG_R_STATUS 0x02 -#define MAX1619_REG_R_LOCAL_TEMP 0x00 -#define MAX1619_REG_R_REMOTE_TEMP 0x01 -#define MAX1619_REG_R_REMOTE_HIGH 0x07 -#define MAX1619_REG_W_REMOTE_HIGH 0x0D -#define MAX1619_REG_R_REMOTE_LOW 0x08 -#define MAX1619_REG_W_REMOTE_LOW 0x0E -#define MAX1619_REG_R_REMOTE_CRIT 0x10 -#define MAX1619_REG_W_REMOTE_CRIT 0x12 -#define MAX1619_REG_R_TCRIT_HYST 0x11 -#define MAX1619_REG_W_TCRIT_HYST 0x13 - -/* - * Conversions and various macros - */ - -#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000) -#define TEMP_TO_REG(val) ((val < 0 ? val+0x100*1000 : val) / 1000) - -/* - * Functions declaration - */ - -static int max1619_attach_adapter(struct i2c_adapter *adapter); -static int max1619_detect(struct i2c_adapter *adapter, int address, - int kind); -static void max1619_init_client(struct i2c_client *client); -static int max1619_detach_client(struct i2c_client *client); -static struct max1619_data *max1619_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver max1619_driver = { - .owner = THIS_MODULE, - .name = "max1619", - .flags = I2C_DF_NOTIFY, - .attach_adapter = max1619_attach_adapter, - .detach_client = max1619_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct max1619_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - u8 temp_input1; /* local */ - u8 temp_input2, temp_low2, temp_high2; /* remote */ - u8 temp_crit2; - u8 temp_hyst2; - u8 alarms; -}; - -/* - * Sysfs stuff - */ - -#define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct max1619_data *data = max1619_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ -} -show_temp(temp_input1); -show_temp(temp_input2); -show_temp(temp_low2); -show_temp(temp_high2); -show_temp(temp_crit2); -show_temp(temp_hyst2); - -#define set_temp2(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct max1619_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->value = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, reg, data->value); \ - up(&data->update_lock); \ - return count; \ -} - -set_temp2(temp_low2, MAX1619_REG_W_REMOTE_LOW); -set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH); -set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT); -set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST); - -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct max1619_data *data = max1619_update_device(dev); - return sprintf(buf, "%d\n", data->alarms); -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, - set_temp_low2); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, - set_temp_high2); -static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, - set_temp_crit2); -static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2, - set_temp_hyst2); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* - * Real code - */ - -static int max1619_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, max1619_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct max1619_data *data; - int err = 0; - const char *name = ""; - u8 reg_config=0, reg_convrate=0, reg_status=0; - u8 man_id, chip_id; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct max1619_data)); - - /* The common I2C client data is placed right before the - MAX1619-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &max1619_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - if (kind < 0) { /* detection */ - reg_config = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CONFIG); - reg_convrate = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CONVRATE); - reg_status = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_STATUS); - if ((reg_config & 0x03) != 0x00 - || reg_convrate > 0x07 || (reg_status & 0x61 ) !=0x00) { - dev_dbg(&adapter->dev, - "MAX1619 detection failed at 0x%02x.\n", - address); - goto exit_free; - } - } - - if (kind <= 0) { /* identification */ - - man_id = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CHIP_ID); - - if ((man_id == 0x4D) && (chip_id == 0x04)){ - kind = max1619; - } - } - - if (kind <= 0) { /* identification failed */ - dev_info(&adapter->dev, - "Unsupported chip (man_id=0x%02X, " - "chip_id=0x%02X).\n", man_id, chip_id); - goto exit_free; - } - - - if (kind == max1619){ - name = "max1619"; - } - - /* We can fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the MAX1619 chip */ - max1619_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static void max1619_init_client(struct i2c_client *client) -{ - u8 config; - - /* - * Start the conversions. - */ - i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, - 5); /* 2 Hz */ - config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); - if (config & 0x40) - i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, - config & 0xBF); /* run */ -} - -static int max1619_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - -static struct max1619_data *max1619_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct max1619_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - dev_dbg(&client->dev, "Updating max1619 data.\n"); - data->temp_input1 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_LOCAL_TEMP); - data->temp_input2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_TEMP); - data->temp_high2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_HIGH); - data->temp_low2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_LOW); - data->temp_crit2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_CRIT); - data->temp_hyst2 = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_TCRIT_HYST); - data->alarms = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_STATUS); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_max1619_init(void) -{ - return i2c_add_driver(&max1619_driver); -} - -static void __exit sensors_max1619_exit(void) -{ - i2c_del_driver(&max1619_driver); -} - -MODULE_AUTHOR("Alexey Fisher and" - "Jean Delvare "); -MODULE_DESCRIPTION("MAX1619 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_max1619_init); -module_exit(sensors_max1619_exit); diff --git a/drivers/i2c/chips/pc87360.c b/drivers/i2c/chips/pc87360.c deleted file mode 100644 index 876c68f3af3..00000000000 --- a/drivers/i2c/chips/pc87360.c +++ /dev/null @@ -1,1348 +0,0 @@ -/* - * pc87360.c - Part of lm_sensors, Linux kernel modules - * for hardware monitoring - * Copyright (C) 2004 Jean Delvare - * - * Copied from smsc47m1.c: - * Copyright (C) 2002 Mark D. Studebaker - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Supports the following chips: - * - * Chip #vin #fan #pwm #temp devid - * PC87360 - 2 2 - 0xE1 - * PC87363 - 2 2 - 0xE8 - * PC87364 - 3 3 - 0xE4 - * PC87365 11 3 3 2 0xE5 - * PC87366 11 3 3 3-4 0xE9 - * - * This driver assumes that no more than one chip is present, and one of - * the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; -static struct i2c_force_data forces[] = {{ NULL }}; -static u8 devid; -static unsigned int extra_isa[3]; -static u8 confreg[4]; - -enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 }; -static struct i2c_address_data addr_data = { - .normal_i2c = normal_i2c, - .normal_isa = normal_isa, - .forces = forces, -}; - -static int init = 1; -module_param(init, int, 0); -MODULE_PARM_DESC(init, - "Chip initialization level:\n" - " 0: None\n" - "*1: Forcibly enable internal voltage and temperature channels, except in9\n" - " 2: Forcibly enable all voltage and temperature channels, except in9\n" - " 3: Forcibly enable all voltage and temperature channels, including in9"); - -/* - * Super-I/O registers and operations - */ - -#define DEV 0x07 /* Register: Logical device select */ -#define DEVID 0x20 /* Register: Device ID */ -#define ACT 0x30 /* Register: Device activation */ -#define BASE 0x60 /* Register: Base address */ - -#define FSCM 0x09 /* Logical device: fans */ -#define VLM 0x0d /* Logical device: voltages */ -#define TMS 0x0e /* Logical device: temperatures */ -static const u8 logdev[3] = { FSCM, VLM, TMS }; - -#define LD_FAN 0 -#define LD_IN 1 -#define LD_TEMP 2 - -static inline void superio_outb(int sioaddr, int reg, int val) -{ - outb(reg, sioaddr); - outb(val, sioaddr+1); -} - -static inline int superio_inb(int sioaddr, int reg) -{ - outb(reg, sioaddr); - return inb(sioaddr+1); -} - -static inline void superio_exit(int sioaddr) -{ - outb(0x02, sioaddr); - outb(0x02, sioaddr+1); -} - -/* - * Logical devices - */ - -#define PC87360_EXTENT 0x10 -#define PC87365_REG_BANK 0x09 -#define NO_BANK 0xff - -/* - * Fan registers and conversions - */ - -/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */ -#define PC87360_REG_PRESCALE(nr) (0x00 + 2 * (nr)) -#define PC87360_REG_PWM(nr) (0x01 + 2 * (nr)) -#define PC87360_REG_FAN_MIN(nr) (0x06 + 3 * (nr)) -#define PC87360_REG_FAN(nr) (0x07 + 3 * (nr)) -#define PC87360_REG_FAN_STATUS(nr) (0x08 + 3 * (nr)) - -#define FAN_FROM_REG(val,div) ((val) == 0 ? 0: \ - 480000 / ((val)*(div))) -#define FAN_TO_REG(val,div) ((val) <= 100 ? 0 : \ - 480000 / ((val)*(div))) -#define FAN_DIV_FROM_REG(val) (1 << ((val >> 5) & 0x03)) -#define FAN_STATUS_FROM_REG(val) ((val) & 0x07) - -#define FAN_CONFIG_MONITOR(val,nr) (((val) >> (2 + nr * 3)) & 1) -#define FAN_CONFIG_CONTROL(val,nr) (((val) >> (3 + nr * 3)) & 1) -#define FAN_CONFIG_INVERT(val,nr) (((val) >> (4 + nr * 3)) & 1) - -#define PWM_FROM_REG(val,inv) ((inv) ? 255 - (val) : (val)) -static inline u8 PWM_TO_REG(int val, int inv) -{ - if (inv) - val = 255 - val; - if (val < 0) - return 0; - if (val > 255) - return 255; - return val; -} - -/* - * Voltage registers and conversions - */ - -#define PC87365_REG_IN_CONVRATE 0x07 -#define PC87365_REG_IN_CONFIG 0x08 -#define PC87365_REG_IN 0x0B -#define PC87365_REG_IN_MIN 0x0D -#define PC87365_REG_IN_MAX 0x0C -#define PC87365_REG_IN_STATUS 0x0A -#define PC87365_REG_IN_ALARMS1 0x00 -#define PC87365_REG_IN_ALARMS2 0x01 -#define PC87365_REG_VID 0x06 - -#define IN_FROM_REG(val,ref) (((val) * (ref) + 128) / 256) -#define IN_TO_REG(val,ref) ((val) < 0 ? 0 : \ - (val)*256 >= (ref)*255 ? 255: \ - ((val) * 256 + (ref)/2) / (ref)) - -/* - * Temperature registers and conversions - */ - -#define PC87365_REG_TEMP_CONFIG 0x08 -#define PC87365_REG_TEMP 0x0B -#define PC87365_REG_TEMP_MIN 0x0D -#define PC87365_REG_TEMP_MAX 0x0C -#define PC87365_REG_TEMP_CRIT 0x0E -#define PC87365_REG_TEMP_STATUS 0x0A -#define PC87365_REG_TEMP_ALARMS 0x00 - -#define TEMP_FROM_REG(val) ((val) * 1000) -#define TEMP_TO_REG(val) ((val) < -55000 ? -55 : \ - (val) > 127000 ? 127 : \ - (val) < 0 ? ((val) - 500) / 1000 : \ - ((val) + 500) / 1000) - -/* - * Client data (each client gets its own) - */ - -struct pc87360_data { - struct i2c_client client; - struct semaphore lock; - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - int address[3]; - - u8 fannr, innr, tempnr; - - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 fan_status[3]; /* Register value */ - u8 pwm[3]; /* Register value */ - u16 fan_conf; /* Configuration register values, combined */ - - u16 in_vref; /* 1 mV/bit */ - u8 in[14]; /* Register value */ - u8 in_min[14]; /* Register value */ - u8 in_max[14]; /* Register value */ - u8 in_crit[3]; /* Register value */ - u8 in_status[14]; /* Register value */ - u16 in_alarms; /* Register values, combined, masked */ - u8 vid_conf; /* Configuration register value */ - u8 vrm; - u8 vid; /* Register value */ - - s8 temp[3]; /* Register value */ - s8 temp_min[3]; /* Register value */ - s8 temp_max[3]; /* Register value */ - s8 temp_crit[3]; /* Register value */ - u8 temp_status[3]; /* Register value */ - u8 temp_alarms; /* Register value, masked */ -}; - -/* - * Functions declaration - */ - -static int pc87360_attach_adapter(struct i2c_adapter *adapter); -static int pc87360_detect(struct i2c_adapter *adapter, int address, int kind); -static int pc87360_detach_client(struct i2c_client *client); - -static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg); -static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg, u8 value); -static void pc87360_init_client(struct i2c_client *client, int use_thermistors); -static struct pc87360_data *pc87360_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver pc87360_driver = { - .owner = THIS_MODULE, - .name = "pc87360", - .flags = I2C_DF_NOTIFY, - .attach_adapter = pc87360_attach_adapter, - .detach_client = pc87360_detach_client, -}; - -/* - * Sysfs stuff - */ - -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pc87360_data *data = i2c_get_clientdata(client); - long fan_min = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[nr])); - - /* If it wouldn't fit, change clock divisor */ - while (fan_min > 255 - && (data->fan_status[nr] & 0x60) != 0x60) { - fan_min >>= 1; - data->fan[nr] >>= 1; - data->fan_status[nr] += 0x20; - } - data->fan_min[nr] = fan_min > 255 ? 255 : fan_min; - pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(nr), - data->fan_min[nr]); - - /* Write new divider, preserve alarm bits */ - pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(nr), - data->fan_status[nr] & 0xF9); - up(&data->update_lock); - - return count; -} - -#define show_and_set_fan(offset) \ -static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[offset-1], \ - FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \ -} \ -static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[offset-1], \ - FAN_DIV_FROM_REG(data->fan_status[offset-1]))); \ -} \ -static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", \ - FAN_DIV_FROM_REG(data->fan_status[offset-1])); \ -} \ -static ssize_t show_fan##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", \ - FAN_STATUS_FROM_REG(data->fan_status[offset-1])); \ -} \ -static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset-1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan##offset##_input, NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IWUSR | S_IRUGO, \ - show_fan##offset##_min, set_fan##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ - show_fan##offset##_div, NULL); \ -static DEVICE_ATTR(fan##offset##_status, S_IRUGO, \ - show_fan##offset##_status, NULL); -show_and_set_fan(1) -show_and_set_fan(2) -show_and_set_fan(3) - -#define show_and_set_pwm(offset) \ -static ssize_t show_pwm##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", \ - PWM_FROM_REG(data->pwm[offset-1], \ - FAN_CONFIG_INVERT(data->fan_conf, \ - offset-1))); \ -} \ -static ssize_t set_pwm##offset(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->pwm[offset-1] = PWM_TO_REG(val, \ - FAN_CONFIG_INVERT(data->fan_conf, offset-1)); \ - pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(offset-1), \ - data->pwm[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \ - show_pwm##offset, set_pwm##offset); -show_and_set_pwm(1) -show_and_set_pwm(2) -show_and_set_pwm(3) - -#define show_and_set_in(offset) \ -static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ - data->in_vref)); \ -} \ -static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ - data->in_vref)); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ - data->in_vref)); \ -} \ -static ssize_t show_in##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", data->in_status[offset]); \ -} \ -static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_min[offset] = IN_TO_REG(val, data->in_vref); \ - pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MIN, \ - data->in_min[offset]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_max[offset] = IN_TO_REG(val, \ - data->in_vref); \ - pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MAX, \ - data->in_max[offset]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset##_input, NULL); \ -static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ - show_in##offset##_max, set_in##offset##_max); \ -static DEVICE_ATTR(in##offset##_status, S_IRUGO, \ - show_in##offset##_status, NULL); -show_and_set_in(0) -show_and_set_in(1) -show_and_set_in(2) -show_and_set_in(3) -show_and_set_in(4) -show_and_set_in(5) -show_and_set_in(6) -show_and_set_in(7) -show_and_set_in(8) -show_and_set_in(9) -show_and_set_in(10) - -#define show_and_set_therm(offset) \ -static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset+7], \ - data->in_vref)); \ -} \ -static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset+7], \ - data->in_vref)); \ -} \ -static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset+7], \ - data->in_vref)); \ -} \ -static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[offset-4], \ - data->in_vref)); \ -} \ -static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%u\n", data->in_status[offset+7]); \ -} \ -static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_min[offset+7] = IN_TO_REG(val, data->in_vref); \ - pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MIN, \ - data->in_min[offset+7]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_max[offset+7] = IN_TO_REG(val, data->in_vref); \ - pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MAX, \ - data->in_max[offset+7]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_crit[offset-4] = IN_TO_REG(val, data->in_vref); \ - pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_CRIT, \ - data->in_crit[offset-4]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_temp##offset##_input, NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ - show_temp##offset##_min, set_temp##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ - show_temp##offset##_max, set_temp##offset##_max); \ -static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \ - show_temp##offset##_crit, set_temp##offset##_crit); \ -static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \ - show_temp##offset##_status, NULL); -show_and_set_therm(4) -show_and_set_therm(5) -show_and_set_therm(6) - -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->vrm); -} -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pc87360_data *data = i2c_get_clientdata(client); - data->vrm = simple_strtoul(buf, NULL, 10); - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); - -static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->in_alarms); -} -static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); - -#define show_and_set_temp(offset) \ -static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ -} \ -static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ -} \ -static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ -}\ -static ssize_t show_temp##offset##_crit(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[offset-1])); \ -}\ -static ssize_t show_temp##offset##_status(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct pc87360_data *data = pc87360_update_device(dev); \ - return sprintf(buf, "%d\n", data->temp_status[offset-1]); \ -}\ -static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp_min[offset-1] = TEMP_TO_REG(val); \ - pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MIN, \ - data->temp_min[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp_max[offset-1] = TEMP_TO_REG(val); \ - pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MAX, \ - data->temp_max[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_crit(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct pc87360_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp_crit[offset-1] = TEMP_TO_REG(val); \ - pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_CRIT, \ - data->temp_crit[offset-1]); \ - up(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_temp##offset##_input, NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ - show_temp##offset##_min, set_temp##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ - show_temp##offset##_max, set_temp##offset##_max); \ -static DEVICE_ATTR(temp##offset##_crit, S_IWUSR | S_IRUGO, \ - show_temp##offset##_crit, set_temp##offset##_crit); \ -static DEVICE_ATTR(temp##offset##_status, S_IRUGO, \ - show_temp##offset##_status, NULL); -show_and_set_temp(1) -show_and_set_temp(2) -show_and_set_temp(3) - -static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->temp_alarms); -} -static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL); - -/* - * Device detection, registration and update - */ - -static int pc87360_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, pc87360_detect); -} - -static int pc87360_find(int sioaddr, u8 *devid, int *address) -{ - u16 val; - int i; - int nrdev; /* logical device count */ - - /* No superio_enter */ - - /* Identify device */ - val = superio_inb(sioaddr, DEVID); - switch (val) { - case 0xE1: /* PC87360 */ - case 0xE8: /* PC87363 */ - case 0xE4: /* PC87364 */ - nrdev = 1; - break; - case 0xE5: /* PC87365 */ - case 0xE9: /* PC87366 */ - nrdev = 3; - break; - default: - superio_exit(sioaddr); - return -ENODEV; - } - /* Remember the device id */ - *devid = val; - - for (i = 0; i < nrdev; i++) { - /* select logical device */ - superio_outb(sioaddr, DEV, logdev[i]); - - val = superio_inb(sioaddr, ACT); - if (!(val & 0x01)) { - printk(KERN_INFO "pc87360: Device 0x%02x not " - "activated\n", logdev[i]); - continue; - } - - val = (superio_inb(sioaddr, BASE) << 8) - | superio_inb(sioaddr, BASE + 1); - if (!val) { - printk(KERN_INFO "pc87360: Base address not set for " - "device 0x%02x\n", logdev[i]); - continue; - } - - address[i] = val; - - if (i==0) { /* Fans */ - confreg[0] = superio_inb(sioaddr, 0xF0); - confreg[1] = superio_inb(sioaddr, 0xF1); - -#ifdef DEBUG - printk(KERN_DEBUG "pc87360: Fan 1: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>2)&1, - (confreg[0]>>3)&1, (confreg[0]>>4)&1); - printk(KERN_DEBUG "pc87360: Fan 2: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>5)&1, - (confreg[0]>>6)&1, (confreg[0]>>7)&1); - printk(KERN_DEBUG "pc87360: Fan 3: mon=%d " - "ctrl=%d inv=%d\n", confreg[1]&1, - (confreg[1]>>1)&1, (confreg[1]>>2)&1); -#endif - } else if (i==1) { /* Voltages */ - /* Are we using thermistors? */ - if (*devid == 0xE9) { /* PC87366 */ - /* These registers are not logical-device - specific, just that we won't need them if - we don't use the VLM device */ - confreg[2] = superio_inb(sioaddr, 0x2B); - confreg[3] = superio_inb(sioaddr, 0x25); - - if (confreg[2] & 0x40) { - printk(KERN_INFO "pc87360: Using " - "thermistors for temperature " - "monitoring\n"); - } - if (confreg[3] & 0xE0) { - printk(KERN_INFO "pc87360: VID " - "inputs routed (mode %u)\n", - confreg[3] >> 5); - } - } - } - } - - superio_exit(sioaddr); - return 0; -} - -/* We don't really care about the address. - Read from extra_isa instead. */ -int pc87360_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i; - struct i2c_client *new_client; - struct pc87360_data *data; - int err = 0; - const char *name = "pc87360"; - int use_thermistors = 0; - - if (!i2c_is_isa_adapter(adapter)) - return -ENODEV; - - if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL))) - return -ENOMEM; - memset(data, 0x00, sizeof(struct pc87360_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->adapter = adapter; - new_client->driver = &pc87360_driver; - new_client->flags = 0; - - data->fannr = 2; - data->innr = 0; - data->tempnr = 0; - - switch (devid) { - case 0xe8: - name = "pc87363"; - break; - case 0xe4: - name = "pc87364"; - data->fannr = 3; - break; - case 0xe5: - name = "pc87365"; - data->fannr = extra_isa[0] ? 3 : 0; - data->innr = extra_isa[1] ? 11 : 0; - data->tempnr = extra_isa[2] ? 2 : 0; - break; - case 0xe9: - name = "pc87366"; - data->fannr = extra_isa[0] ? 3 : 0; - data->innr = extra_isa[1] ? 14 : 0; - data->tempnr = extra_isa[2] ? 3 : 0; - break; - } - - strcpy(new_client->name, name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - for (i = 0; i < 3; i++) { - if (((data->address[i] = extra_isa[i])) - && !request_region(extra_isa[i], PC87360_EXTENT, - pc87360_driver.name)) { - dev_err(&new_client->dev, "Region 0x%x-0x%x already " - "in use!\n", extra_isa[i], - extra_isa[i]+PC87360_EXTENT-1); - for (i--; i >= 0; i--) - release_region(extra_isa[i], PC87360_EXTENT); - err = -EBUSY; - goto ERROR1; - } - } - - /* Retrieve the fans configuration from Super-I/O space */ - if (data->fannr) - data->fan_conf = confreg[0] | (confreg[1] << 8); - - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - /* Use the correct reference voltage - Unless both the VLM and the TMS logical devices agree to - use an external Vref, the internal one is used. */ - if (data->innr) { - i = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG); - if (data->tempnr) { - i &= pc87360_read_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG); - } - data->in_vref = (i&0x02) ? 3025 : 2966; - dev_dbg(&new_client->dev, "Using %s reference voltage\n", - (i&0x02) ? "external" : "internal"); - - data->vid_conf = confreg[3]; - data->vrm = 90; - } - - /* Fan clock dividers may be needed before any data is read */ - for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i)) - data->fan_status[i] = pc87360_read_value(data, - LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(i)); - } - - if (init > 0) { - if (devid == 0xe9 && data->address[1]) /* PC87366 */ - use_thermistors = confreg[2] & 0x40; - - pc87360_init_client(new_client, use_thermistors); - } - - /* Register sysfs hooks */ - if (data->innr) { - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_in7_input); - device_create_file(&new_client->dev, &dev_attr_in8_input); - device_create_file(&new_client->dev, &dev_attr_in9_input); - device_create_file(&new_client->dev, &dev_attr_in10_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in7_min); - device_create_file(&new_client->dev, &dev_attr_in8_min); - device_create_file(&new_client->dev, &dev_attr_in9_min); - device_create_file(&new_client->dev, &dev_attr_in10_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_in6_max); - device_create_file(&new_client->dev, &dev_attr_in7_max); - device_create_file(&new_client->dev, &dev_attr_in8_max); - device_create_file(&new_client->dev, &dev_attr_in9_max); - device_create_file(&new_client->dev, &dev_attr_in10_max); - device_create_file(&new_client->dev, &dev_attr_in0_status); - device_create_file(&new_client->dev, &dev_attr_in1_status); - device_create_file(&new_client->dev, &dev_attr_in2_status); - device_create_file(&new_client->dev, &dev_attr_in3_status); - device_create_file(&new_client->dev, &dev_attr_in4_status); - device_create_file(&new_client->dev, &dev_attr_in5_status); - device_create_file(&new_client->dev, &dev_attr_in6_status); - device_create_file(&new_client->dev, &dev_attr_in7_status); - device_create_file(&new_client->dev, &dev_attr_in8_status); - device_create_file(&new_client->dev, &dev_attr_in9_status); - device_create_file(&new_client->dev, &dev_attr_in10_status); - - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_vrm); - device_create_file(&new_client->dev, &dev_attr_alarms_in); - } - - if (data->tempnr) { - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_status); - device_create_file(&new_client->dev, &dev_attr_temp2_status); - - device_create_file(&new_client->dev, &dev_attr_alarms_temp); - } - if (data->tempnr == 3) { - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp3_crit); - device_create_file(&new_client->dev, &dev_attr_temp3_status); - } - if (data->innr == 14) { - device_create_file(&new_client->dev, &dev_attr_temp4_input); - device_create_file(&new_client->dev, &dev_attr_temp5_input); - device_create_file(&new_client->dev, &dev_attr_temp6_input); - device_create_file(&new_client->dev, &dev_attr_temp4_min); - device_create_file(&new_client->dev, &dev_attr_temp5_min); - device_create_file(&new_client->dev, &dev_attr_temp6_min); - device_create_file(&new_client->dev, &dev_attr_temp4_max); - device_create_file(&new_client->dev, &dev_attr_temp5_max); - device_create_file(&new_client->dev, &dev_attr_temp6_max); - device_create_file(&new_client->dev, &dev_attr_temp4_crit); - device_create_file(&new_client->dev, &dev_attr_temp5_crit); - device_create_file(&new_client->dev, &dev_attr_temp6_crit); - device_create_file(&new_client->dev, &dev_attr_temp4_status); - device_create_file(&new_client->dev, &dev_attr_temp5_status); - device_create_file(&new_client->dev, &dev_attr_temp6_status); - } - - if (data->fannr) { - if (FAN_CONFIG_MONITOR(data->fan_conf, 0)) { - device_create_file(&new_client->dev, - &dev_attr_fan1_input); - device_create_file(&new_client->dev, - &dev_attr_fan1_min); - device_create_file(&new_client->dev, - &dev_attr_fan1_div); - device_create_file(&new_client->dev, - &dev_attr_fan1_status); - } - - if (FAN_CONFIG_MONITOR(data->fan_conf, 1)) { - device_create_file(&new_client->dev, - &dev_attr_fan2_input); - device_create_file(&new_client->dev, - &dev_attr_fan2_min); - device_create_file(&new_client->dev, - &dev_attr_fan2_div); - device_create_file(&new_client->dev, - &dev_attr_fan2_status); - } - - if (FAN_CONFIG_CONTROL(data->fan_conf, 0)) - device_create_file(&new_client->dev, &dev_attr_pwm1); - if (FAN_CONFIG_CONTROL(data->fan_conf, 1)) - device_create_file(&new_client->dev, &dev_attr_pwm2); - } - if (data->fannr == 3) { - if (FAN_CONFIG_MONITOR(data->fan_conf, 2)) { - device_create_file(&new_client->dev, - &dev_attr_fan3_input); - device_create_file(&new_client->dev, - &dev_attr_fan3_min); - device_create_file(&new_client->dev, - &dev_attr_fan3_div); - device_create_file(&new_client->dev, - &dev_attr_fan3_status); - } - - if (FAN_CONFIG_CONTROL(data->fan_conf, 2)) - device_create_file(&new_client->dev, &dev_attr_pwm3); - } - - return 0; - -ERROR2: - for (i = 0; i < 3; i++) { - if (data->address[i]) { - release_region(data->address[i], PC87360_EXTENT); - } - } -ERROR1: - kfree(data); - return err; -} - -static int pc87360_detach_client(struct i2c_client *client) -{ - struct pc87360_data *data = i2c_get_clientdata(client); - int i; - - if ((i = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return i; - } - - for (i = 0; i < 3; i++) { - if (data->address[i]) { - release_region(data->address[i], PC87360_EXTENT); - } - } - kfree(data); - - return 0; -} - -/* ldi is the logical device index - bank is for voltages and temperatures only */ -static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg) -{ - int res; - - down(&(data->lock)); - if (bank != NO_BANK) - outb_p(bank, data->address[ldi] + PC87365_REG_BANK); - res = inb_p(data->address[ldi] + reg); - up(&(data->lock)); - - return res; -} - -static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg, u8 value) -{ - down(&(data->lock)); - if (bank != NO_BANK) - outb_p(bank, data->address[ldi] + PC87365_REG_BANK); - outb_p(value, data->address[ldi] + reg); - up(&(data->lock)); -} - -static void pc87360_init_client(struct i2c_client *client, int use_thermistors) -{ - struct pc87360_data *data = i2c_get_clientdata(client); - int i, nr; - const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; - const u8 init_temp[3] = { 2, 2, 1 }; - u8 reg; - - if (init >= 2 && data->innr) { - reg = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONVRATE); - dev_info(&client->dev, "VLM conversion set to" - "1s period, 160us delay\n"); - pc87360_write_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONVRATE, - (reg & 0xC0) | 0x11); - } - - nr = data->innr < 11 ? data->innr : 11; - for (i=0; i= init_in[i]) { - /* Forcibly enable voltage channel */ - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - if (!(reg & 0x01)) { - dev_dbg(&client->dev, "Forcibly " - "enabling in%d\n", i); - pc87360_write_value(data, LD_IN, i, - PC87365_REG_IN_STATUS, - (reg & 0x68) | 0x87); - } - } - } - - /* We can't blindly trust the Super-I/O space configuration bit, - most BIOS won't set it properly */ - for (i=11; iinnr; i++) { - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_TEMP_STATUS); - use_thermistors = use_thermistors || (reg & 0x01); - } - - i = use_thermistors ? 2 : 0; - for (; itempnr; i++) { - if (init >= init_temp[i]) { - /* Forcibly enable temperature channel */ - reg = pc87360_read_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS); - if (!(reg & 0x01)) { - dev_dbg(&client->dev, "Forcibly " - "enabling temp%d\n", i+1); - pc87360_write_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS, - 0xCF); - } - } - } - - if (use_thermistors) { - for (i=11; iinnr; i++) { - if (init >= init_in[i]) { - /* The pin may already be used by thermal - diodes */ - reg = pc87360_read_value(data, LD_TEMP, - (i-11)/2, PC87365_REG_TEMP_STATUS); - if (reg & 0x01) { - dev_dbg(&client->dev, "Skipping " - "temp%d, pin already in use " - "by temp%d\n", i-7, (i-11)/2); - continue; - } - - /* Forcibly enable thermistor channel */ - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - if (!(reg & 0x01)) { - dev_dbg(&client->dev, "Forcibly " - "enabling temp%d\n", i-7); - pc87360_write_value(data, LD_IN, i, - PC87365_REG_TEMP_STATUS, - (reg & 0x60) | 0x8F); - } - } - } - } - - if (data->innr) { - reg = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG); - if (reg & 0x01) { - dev_dbg(&client->dev, "Forcibly " - "enabling monitoring (VLM)\n"); - pc87360_write_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG, - reg & 0xFE); - } - } - - if (data->tempnr) { - reg = pc87360_read_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG); - if (reg & 0x01) { - dev_dbg(&client->dev, "Forcibly enabling " - "monitoring (TMS)\n"); - pc87360_write_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG, - reg & 0xFE); - } - - if (init >= 2) { - /* Chip config as documented by National Semi. */ - pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08); - /* We voluntarily omit the bank here, in case the - sequence itself matters. It shouldn't be a problem, - since nobody else is supposed to access the - device at that point. */ - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05); - } - } -} - -static void pc87360_autodiv(struct i2c_client *client, int nr) -{ - struct pc87360_data *data = i2c_get_clientdata(client); - u8 old_min = data->fan_min[nr]; - - /* Increase clock divider if needed and possible */ - if ((data->fan_status[nr] & 0x04) /* overflow flag */ - || (data->fan[nr] >= 224)) { /* next to overflow */ - if ((data->fan_status[nr] & 0x60) != 0x60) { - data->fan_status[nr] += 0x20; - data->fan_min[nr] >>= 1; - data->fan[nr] >>= 1; - dev_dbg(&client->dev, "Increasing " - "clock divider to %d for fan %d\n", - FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1); - } - } else { - /* Decrease clock divider if possible */ - while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */ - && data->fan[nr] < 85 /* bad accuracy */ - && (data->fan_status[nr] & 0x60) != 0x00) { - data->fan_status[nr] -= 0x20; - data->fan_min[nr] <<= 1; - data->fan[nr] <<= 1; - dev_dbg(&client->dev, "Decreasing " - "clock divider to %d for fan %d\n", - FAN_DIV_FROM_REG(data->fan_status[nr]), - nr+1); - } - } - - /* Write new fan min if it changed */ - if (old_min != data->fan_min[nr]) { - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(nr), - data->fan_min[nr]); - } -} - -static struct pc87360_data *pc87360_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pc87360_data *data = i2c_get_clientdata(client); - u8 i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { - dev_dbg(&client->dev, "Data update\n"); - - /* Fans */ - for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { - data->fan_status[i] = - pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_FAN_STATUS(i)); - data->fan[i] = pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_FAN(i)); - data->fan_min[i] = pc87360_read_value(data, - LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(i)); - /* Change clock divider if needed */ - pc87360_autodiv(client, i); - /* Clear bits and write new divider */ - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(i), - data->fan_status[i]); - } - if (FAN_CONFIG_CONTROL(data->fan_conf, i)) - data->pwm[i] = pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_PWM(i)); - } - - /* Voltages */ - for (i = 0; i < data->innr; i++) { - data->in_status[i] = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - /* Clear bits */ - pc87360_write_value(data, LD_IN, i, - PC87365_REG_IN_STATUS, - data->in_status[i]); - if ((data->in_status[i] & 0x81) == 0x81) { - data->in[i] = pc87360_read_value(data, LD_IN, - i, PC87365_REG_IN); - } - if (data->in_status[i] & 0x01) { - data->in_min[i] = pc87360_read_value(data, - LD_IN, i, - PC87365_REG_IN_MIN); - data->in_max[i] = pc87360_read_value(data, - LD_IN, i, - PC87365_REG_IN_MAX); - if (i >= 11) - data->in_crit[i-11] = - pc87360_read_value(data, LD_IN, - i, PC87365_REG_TEMP_CRIT); - } - } - if (data->innr) { - data->in_alarms = pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_IN_ALARMS1) - | ((pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_IN_ALARMS2) - & 0x07) << 8); - data->vid = (data->vid_conf & 0xE0) ? - pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_VID) : 0x1F; - } - - /* Temperatures */ - for (i = 0; i < data->tempnr; i++) { - data->temp_status[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_STATUS); - /* Clear bits */ - pc87360_write_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS, - data->temp_status[i]); - if ((data->temp_status[i] & 0x81) == 0x81) { - data->temp[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP); - } - if (data->temp_status[i] & 0x01) { - data->temp_min[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_MIN); - data->temp_max[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_MAX); - data->temp_crit[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_CRIT); - } - } - if (data->tempnr) { - data->temp_alarms = pc87360_read_value(data, LD_TEMP, - NO_BANK, PC87365_REG_TEMP_ALARMS) - & 0x3F; - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init pc87360_init(void) -{ - int i; - - if (pc87360_find(0x2e, &devid, extra_isa) - && pc87360_find(0x4e, &devid, extra_isa)) { - printk(KERN_WARNING "pc87360: PC8736x not detected, " - "module not inserted.\n"); - return -ENODEV; - } - - /* Arbitrarily pick one of the addresses */ - for (i = 0; i < 3; i++) { - if (extra_isa[i] != 0x0000) { - normal_isa[0] = extra_isa[i]; - break; - } - } - - if (normal_isa[0] == 0x0000) { - printk(KERN_WARNING "pc87360: No active logical device, " - "module not inserted.\n"); - return -ENODEV; - } - - return i2c_add_driver(&pc87360_driver); -} - -static void __exit pc87360_exit(void) -{ - i2c_del_driver(&pc87360_driver); -} - - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("PC8736x hardware monitor"); -MODULE_LICENSE("GPL"); - -module_init(pc87360_init); -module_exit(pc87360_exit); diff --git a/drivers/i2c/chips/sis5595.c b/drivers/i2c/chips/sis5595.c deleted file mode 100644 index 6bbfc8fb4f1..00000000000 --- a/drivers/i2c/chips/sis5595.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - sis5595.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (C) 1998 - 2001 Frodo Looijaard , - Kyösti Mälkki , and - Mark D. Studebaker - Ported to Linux 2.6 by Aurelien Jarno with - the help of Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - SiS southbridge has a LM78-like chip integrated on the same IC. - This driver is a customized copy of lm78.c - - Supports following revisions: - Version PCI ID PCI Revision - 1 1039/0008 AF or less - 2 1039/0008 B0 or greater - - Note: these chips contain a 0008 device which is incompatible with the - 5595. We recognize these by the presence of the listed - "blacklist" PCI ID and refuse to load. - - NOT SUPPORTED PCI ID BLACKLIST PCI ID - 540 0008 0540 - 550 0008 0550 - 5513 0008 5511 - 5581 0008 5597 - 5582 0008 5597 - 5597 0008 5597 - 5598 0008 5597/5598 - 630 0008 0630 - 645 0008 0645 - 730 0008 0730 - 735 0008 0735 -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ -static u16 force_addr; -module_param(force_addr, ushort, 0); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -/* Addresses to scan. - Note that we can't determine the ISA address until we have initialized - our module */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(sis5595); - -/* Many SIS5595 constants specified below */ - -/* Length of ISA address segment */ -#define SIS5595_EXTENT 8 -/* PCI Config Registers */ -#define SIS5595_REVISION_REG 0x08 -#define SIS5595_BASE_REG 0x68 -#define SIS5595_PIN_REG 0x7A -#define SIS5595_ENABLE_REG 0x7B - -/* Where are the ISA address/data registers relative to the base address */ -#define SIS5595_ADDR_REG_OFFSET 5 -#define SIS5595_DATA_REG_OFFSET 6 - -/* The SIS5595 registers */ -#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define SIS5595_REG_IN(nr) (0x20 + (nr)) - -#define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr)) -#define SIS5595_REG_FAN(nr) (0x28 + (nr)) - -/* On the first version of the chip, the temp registers are separate. - On the second version, - TEMP pin is shared with IN4, configured in PCI register 0x7A. - The registers are the same as well. - OVER and HYST are really MAX and MIN. */ - -#define REV2MIN 0xb0 -#define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN(4) : 0x27 -#define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN_MAX(4) : 0x39 -#define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN_MIN(4) : 0x3a - -#define SIS5595_REG_CONFIG 0x40 -#define SIS5595_REG_ALARM1 0x41 -#define SIS5595_REG_ALARM2 0x42 -#define SIS5595_REG_FANDIV 0x47 - -/* Conversions. Limit checking is only done on the TO_REG - variants. */ - -/* IN: mV, (0V to 4.08V) - REG: 16mV/bit */ -static inline u8 IN_TO_REG(unsigned long val) -{ - unsigned long nval = SENSORS_LIMIT(val, 0, 4080); - return (nval + 8) / 16; -} -#define IN_FROM_REG(val) ((val) * 16) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm <= 0) - return 255; - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); -} - -static inline int FAN_FROM_REG(u8 val, int div) -{ - return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); -} - -/* TEMP: mC (-54.12C to +157.53C) - REG: 0.83C/bit + 52.12, two's complement */ -static inline int TEMP_FROM_REG(s8 val) -{ - return val * 830 + 52120; -} -static inline s8 TEMP_TO_REG(int val) -{ - int nval = SENSORS_LIMIT(val, -54120, 157530) ; - return nval<0 ? (nval-5212-415)/830 : (nval-5212+415)/830; -} - -/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) - REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ -static inline u8 DIV_TO_REG(int val) -{ - return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; -} -#define DIV_FROM_REG(val) (1 << (val)) - -/* For the SIS5595, we need to keep some data in memory. That - data is pointed to by sis5595_list[NR]->data. The structure itself is - dynamically allocated, at the time when the new sis5595 client is - allocated. */ -struct sis5595_data { - struct i2c_client client; - struct semaphore lock; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - char maxins; /* == 3 if temp enabled, otherwise == 4 */ - u8 revision; /* Reg. value */ - - u8 in[5]; /* Register value */ - u8 in_max[5]; /* Register value */ - u8 in_min[5]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - s8 temp; /* Register value */ - s8 temp_over; /* Register value */ - s8 temp_hyst; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding, combined */ -}; - -static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ - -static int sis5595_attach_adapter(struct i2c_adapter *adapter); -static int sis5595_detect(struct i2c_adapter *adapter, int address, int kind); -static int sis5595_detach_client(struct i2c_client *client); - -static int sis5595_read_value(struct i2c_client *client, u8 register); -static int sis5595_write_value(struct i2c_client *client, u8 register, u8 value); -static struct sis5595_data *sis5595_update_device(struct device *dev); -static void sis5595_init_client(struct i2c_client *client); - -static struct i2c_driver sis5595_driver = { - .owner = THIS_MODULE, - .name = "sis5595", - .id = I2C_DRIVERID_SIS5595, - .flags = I2C_DF_NOTIFY, - .attach_adapter = sis5595_attach_adapter, - .detach_client = sis5595_detach_client, -}; - -/* 4 Voltages */ -static ssize_t show_in(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); -} - -static ssize_t show_in_min(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); -} - -static ssize_t show_in_max(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); -} - -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val); - sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val); - sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]); - up(&data->update_lock); - return count; -} - -#define show_in_offset(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset, NULL); \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); - -show_in_offset(0); -show_in_offset(1); -show_in_offset(2); -show_in_offset(3); -show_in_offset(4); - -/* Temperature */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); -} - -static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); -} - -static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_over = TEMP_TO_REG(val); - sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over); - up(&data->update_lock); - return count; -} - -static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); -} - -static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_hyst = TEMP_TO_REG(val); - sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, - show_temp_over, set_temp_over); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, - show_temp_hyst, set_temp_hyst); - -/* 2 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])) ); -} - -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])) ); -} - -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - unsigned long min; - unsigned long val = simple_strtoul(buf, NULL, 10); - int reg; - - down(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - reg = sis5595_read_value(client, SIS5595_REG_FANDIV); - - switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; - default: - dev_err(&client->dev, "fan_div value %ld not " - "supported. Choose one of 1, 2, 4 or 8!\n", val); - up(&data->update_lock); - return -EINVAL; - } - - switch (nr) { - case 0: - reg = (reg & 0xcf) | (data->fan_div[nr] << 4); - break; - case 1: - reg = (reg & 0x3f) | (data->fan_div[nr] << 6); - break; - } - sis5595_write_value(client, SIS5595_REG_FANDIV, reg); - data->fan_min[nr] = - FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]); - up(&data->update_lock); - return count; -} - -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); - -show_fan_offset(1); -show_fan_offset(2); - -static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - return set_fan_div(dev, buf, count, 0) ; -} - -static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - return set_fan_div(dev, buf, count, 1) ; -} -static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, - show_fan_1_div, set_fan_1_div); -static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, - show_fan_2_div, set_fan_2_div); - -/* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct sis5595_data *data = sis5595_update_device(dev); - return sprintf(buf, "%d\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* This is called when the module is loaded */ -static int sis5595_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, sis5595_detect); -} - -int sis5595_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int err = 0; - int i; - struct i2c_client *new_client; - struct sis5595_data *data; - char val; - u16 a; - - /* Make sure we are probing the ISA bus!! */ - if (!i2c_is_isa_adapter(adapter)) - goto exit; - - if (force_addr) - address = force_addr & ~(SIS5595_EXTENT - 1); - /* Reserve the ISA region */ - if (!request_region(address, SIS5595_EXTENT, sis5595_driver.name)) { - err = -EBUSY; - goto exit; - } - if (force_addr) { - dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, SIS5595_BASE_REG, address)) - goto exit_release; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a)) - goto exit_release; - if ((a & ~(SIS5595_EXTENT - 1)) != address) - /* doesn't work for some chips? */ - goto exit_release; - } - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) { - goto exit_release; - } - if ((val & 0x80) == 0) { - if (PCIBIOS_SUCCESSFUL != - pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG, - val | 0x80)) - goto exit_release; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) - goto exit_release; - if ((val & 0x80) == 0) - /* doesn't work for some chips! */ - goto exit_release; - } - - if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit_release; - } - memset(data, 0, sizeof(struct sis5595_data)); - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - i2c_set_clientdata(new_client, data); - new_client->adapter = adapter; - new_client->driver = &sis5595_driver; - new_client->flags = 0; - - /* Check revision and pin registers to determine whether 4 or 5 voltages */ - pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision)); - /* 4 voltages, 1 temp */ - data->maxins = 3; - if (data->revision >= REV2MIN) { - pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val); - if (!(val & 0x80)) - /* 5 voltages, no temps */ - data->maxins = 4; - } - - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE); - - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the SIS5595 chip */ - sis5595_init_client(new_client); - - /* A few vars need to be filled upon startup */ - for (i = 0; i < 2; i++) { - data->fan_min[i] = sis5595_read_value(new_client, - SIS5595_REG_FAN_MIN(i)); - } - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - if (data->maxins == 4) { - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - } - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_alarms); - if (data->maxins == 3) { - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - } - return 0; - -exit_free: - kfree(data); -exit_release: - release_region(address, SIS5595_EXTENT); -exit: - return err; -} - -static int sis5595_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - - if (i2c_is_isa_client(client)) - release_region(client->addr, SIS5595_EXTENT); - - kfree(i2c_get_clientdata(client)); - - return 0; -} - - -/* ISA access must be locked explicitly. */ -static int sis5595_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - struct sis5595_data *data = i2c_get_clientdata(client); - down(&data->lock); - outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); - res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET); - up(&data->lock); - return res; -} - -static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - struct sis5595_data *data = i2c_get_clientdata(client); - down(&data->lock); - outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); - outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET); - up(&data->lock); - return 0; -} - -/* Called when we have found a new SIS5595. */ -static void sis5595_init_client(struct i2c_client *client) -{ - u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG); - if (!(config & 0x01)) - sis5595_write_value(client, SIS5595_REG_CONFIG, - (config & 0xf7) | 0x01); -} - -static struct sis5595_data *sis5595_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sis5595_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - - for (i = 0; i <= data->maxins; i++) { - data->in[i] = - sis5595_read_value(client, SIS5595_REG_IN(i)); - data->in_min[i] = - sis5595_read_value(client, - SIS5595_REG_IN_MIN(i)); - data->in_max[i] = - sis5595_read_value(client, - SIS5595_REG_IN_MAX(i)); - } - for (i = 0; i < 2; i++) { - data->fan[i] = - sis5595_read_value(client, SIS5595_REG_FAN(i)); - data->fan_min[i] = - sis5595_read_value(client, - SIS5595_REG_FAN_MIN(i)); - } - if (data->maxins == 3) { - data->temp = - sis5595_read_value(client, SIS5595_REG_TEMP); - data->temp_over = - sis5595_read_value(client, SIS5595_REG_TEMP_OVER); - data->temp_hyst = - sis5595_read_value(client, SIS5595_REG_TEMP_HYST); - } - i = sis5595_read_value(client, SIS5595_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = - sis5595_read_value(client, SIS5595_REG_ALARM1) | - (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static struct pci_device_id sis5595_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, sis5595_pci_ids); - -static int blacklist[] __devinitdata = { - PCI_DEVICE_ID_SI_540, - PCI_DEVICE_ID_SI_550, - PCI_DEVICE_ID_SI_630, - PCI_DEVICE_ID_SI_645, - PCI_DEVICE_ID_SI_730, - PCI_DEVICE_ID_SI_735, - PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but - that ID shows up in other chips so we - use the 5511 ID for recognition */ - PCI_DEVICE_ID_SI_5597, - PCI_DEVICE_ID_SI_5598, - 0 }; - -static int __devinit sis5595_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - u16 val; - int *i; - int addr = 0; - - for (i = blacklist; *i != 0; i++) { - struct pci_dev *dev; - dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL); - if (dev) { - dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i); - pci_dev_put(dev); - return -ENODEV; - } - } - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(dev, SIS5595_BASE_REG, &val)) - return -ENODEV; - - addr = val & ~(SIS5595_EXTENT - 1); - if (addr == 0 && force_addr == 0) { - dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - addr = force_addr; /* so detect will get called */ - - if (!addr) { - dev_err(&dev->dev,"No SiS 5595 sensors found.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - s_bridge = pci_dev_get(dev); - if (i2c_add_driver(&sis5595_driver)) { - pci_dev_put(s_bridge); - s_bridge = NULL; - } - - /* Always return failure here. This is to allow other drivers to bind - * to this pci device. We don't really want to have control over the - * pci device, we only wanted to read as few register values from it. - */ - return -ENODEV; -} - -static struct pci_driver sis5595_pci_driver = { - .name = "sis5595", - .id_table = sis5595_pci_ids, - .probe = sis5595_pci_probe, -}; - -static int __init sm_sis5595_init(void) -{ - return pci_register_driver(&sis5595_pci_driver); -} - -static void __exit sm_sis5595_exit(void) -{ - pci_unregister_driver(&sis5595_pci_driver); - if (s_bridge != NULL) { - i2c_del_driver(&sis5595_driver); - pci_dev_put(s_bridge); - s_bridge = NULL; - } -} - -MODULE_AUTHOR("Aurelien Jarno "); -MODULE_DESCRIPTION("SiS 5595 Sensor device"); -MODULE_LICENSE("GPL"); - -module_init(sm_sis5595_init); -module_exit(sm_sis5595_exit); diff --git a/drivers/i2c/chips/smsc47b397.c b/drivers/i2c/chips/smsc47b397.c deleted file mode 100644 index 251ac265955..00000000000 --- a/drivers/i2c/chips/smsc47b397.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - smsc47b397.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Supports the SMSC LPC47B397-NC Super-I/O chip. - - Author/Maintainer: Mark M. Hoffman - Copyright (C) 2004 Utilitek Systems, Inc. - - derived in part from smsc47m1.c: - Copyright (C) 2002 Mark D. Studebaker - Copyright (C) 2004 Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -/* Address is autodetected, there is no default value */ -static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; -static struct i2c_force_data forces[] = {{NULL}}; - -enum chips { any_chip, smsc47b397 }; -static struct i2c_address_data addr_data = { - .normal_i2c = normal_i2c, - .normal_isa = normal_isa, - .probe = normal_i2c, /* cheat */ - .ignore = normal_i2c, /* cheat */ - .forces = forces, -}; - -/* Super-I/0 registers and commands */ - -#define REG 0x2e /* The register to read/write */ -#define VAL 0x2f /* The value to read/write */ - -static inline void superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -/* select superio logical device */ -static inline void superio_select(int ld) -{ - superio_outb(0x07, ld); -} - -static inline void superio_enter(void) -{ - outb(0x55, REG); -} - -static inline void superio_exit(void) -{ - outb(0xAA, REG); -} - -#define SUPERIO_REG_DEVID 0x20 -#define SUPERIO_REG_DEVREV 0x21 -#define SUPERIO_REG_BASE_MSB 0x60 -#define SUPERIO_REG_BASE_LSB 0x61 -#define SUPERIO_REG_LD8 0x08 - -#define SMSC_EXTENT 0x02 - -/* 0 <= nr <= 3 */ -static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80}; -#define SMSC47B397_REG_TEMP(nr) (smsc47b397_reg_temp[(nr)]) - -/* 0 <= nr <= 3 */ -#define SMSC47B397_REG_FAN_LSB(nr) (0x28 + 2 * (nr)) -#define SMSC47B397_REG_FAN_MSB(nr) (0x29 + 2 * (nr)) - -struct smsc47b397_data { - struct i2c_client client; - struct semaphore lock; - - struct semaphore update_lock; - unsigned long last_updated; /* in jiffies */ - int valid; - - /* register values */ - u16 fan[4]; - u8 temp[4]; -}; - -static int smsc47b397_read_value(struct i2c_client *client, u8 reg) -{ - struct smsc47b397_data *data = i2c_get_clientdata(client); - int res; - - down(&data->lock); - outb(reg, client->addr); - res = inb_p(client->addr + 1); - up(&data->lock); - return res; -} - -static struct smsc47b397_data *smsc47b397_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47b397_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - dev_dbg(&client->dev, "starting device update...\n"); - - /* 4 temperature inputs, 4 fan inputs */ - for (i = 0; i < 4; i++) { - data->temp[i] = smsc47b397_read_value(client, - SMSC47B397_REG_TEMP(i)); - - /* must read LSB first */ - data->fan[i] = smsc47b397_read_value(client, - SMSC47B397_REG_FAN_LSB(i)); - data->fan[i] |= smsc47b397_read_value(client, - SMSC47B397_REG_FAN_MSB(i)) << 8; - } - - data->last_updated = jiffies; - data->valid = 1; - - dev_dbg(&client->dev, "... device update complete\n"); - } - - up(&data->update_lock); - - return data; -} - -/* TEMP: 0.001C/bit (-128C to +127C) - REG: 1C/bit, two's complement */ -static int temp_from_reg(u8 reg) -{ - return (s8)reg * 1000; -} - -/* 0 <= nr <= 3 */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) -{ - struct smsc47b397_data *data = smsc47b397_update_device(dev); - return sprintf(buf, "%d\n", temp_from_reg(data->temp[nr])); -} - -#define sysfs_temp(num) \ -static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, num-1); \ -} \ -static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL) - -sysfs_temp(1); -sysfs_temp(2); -sysfs_temp(3); -sysfs_temp(4); - -#define device_create_file_temp(client, num) \ - device_create_file(&client->dev, &dev_attr_temp##num##_input) - -/* FAN: 1 RPM/bit - REG: count of 90kHz pulses / revolution */ -static int fan_from_reg(u16 reg) -{ - return 90000 * 60 / reg; -} - -/* 0 <= nr <= 3 */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) -{ - struct smsc47b397_data *data = smsc47b397_update_device(dev); - return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr])); -} - -#define sysfs_fan(num) \ -static ssize_t show_fan##num(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, num-1); \ -} \ -static DEVICE_ATTR(fan##num##_input, S_IRUGO, show_fan##num, NULL) - -sysfs_fan(1); -sysfs_fan(2); -sysfs_fan(3); -sysfs_fan(4); - -#define device_create_file_fan(client, num) \ - device_create_file(&client->dev, &dev_attr_fan##num##_input) - -static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind); - -static int smsc47b397_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, smsc47b397_detect); -} - -static int smsc47b397_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - release_region(client->addr, SMSC_EXTENT); - kfree(i2c_get_clientdata(client)); - - return 0; -} - -static struct i2c_driver smsc47b397_driver = { - .owner = THIS_MODULE, - .name = "smsc47b397", - .id = I2C_DRIVERID_SMSC47B397, - .flags = I2C_DF_NOTIFY, - .attach_adapter = smsc47b397_attach_adapter, - .detach_client = smsc47b397_detach_client, -}; - -static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind) -{ - struct i2c_client *new_client; - struct smsc47b397_data *data; - int err = 0; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - if (!request_region(addr, SMSC_EXTENT, smsc47b397_driver.name)) { - dev_err(&adapter->dev, "Region 0x%x already in use!\n", addr); - return -EBUSY; - } - - if (!(data = kmalloc(sizeof(struct smsc47b397_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error_release; - } - memset(data, 0x00, sizeof(struct smsc47b397_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = addr; - init_MUTEX(&data->lock); - new_client->adapter = adapter; - new_client->driver = &smsc47b397_driver; - new_client->flags = 0; - - strlcpy(new_client->name, "smsc47b397", I2C_NAME_SIZE); - - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto error_free; - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - device_create_file_temp(new_client, 3); - device_create_file_temp(new_client, 4); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - device_create_file_fan(new_client, 4); - - return 0; - -error_free: - kfree(new_client); -error_release: - release_region(addr, SMSC_EXTENT); - return err; -} - -static int __init smsc47b397_find(unsigned int *addr) -{ - u8 id, rev; - - superio_enter(); - id = superio_inb(SUPERIO_REG_DEVID); - - if (id != 0x6f) { - superio_exit(); - return -ENODEV; - } - - rev = superio_inb(SUPERIO_REG_DEVREV); - - superio_select(SUPERIO_REG_LD8); - *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8) - | superio_inb(SUPERIO_REG_BASE_LSB); - - printk(KERN_INFO "smsc47b397: found SMSC LPC47B397-NC " - "(base address 0x%04x, revision %u)\n", *addr, rev); - - superio_exit(); - return 0; -} - -static int __init smsc47b397_init(void) -{ - int ret; - - if ((ret = smsc47b397_find(normal_isa))) - return ret; - - return i2c_add_driver(&smsc47b397_driver); -} - -static void __exit smsc47b397_exit(void) -{ - i2c_del_driver(&smsc47b397_driver); -} - -MODULE_AUTHOR("Mark M. Hoffman "); -MODULE_DESCRIPTION("SMSC LPC47B397 driver"); -MODULE_LICENSE("GPL"); - -module_init(smsc47b397_init); -module_exit(smsc47b397_exit); diff --git a/drivers/i2c/chips/smsc47m1.c b/drivers/i2c/chips/smsc47m1.c deleted file mode 100644 index 897117a7213..00000000000 --- a/drivers/i2c/chips/smsc47m1.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - smsc47m1.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x - Super-I/O chips. - - Copyright (C) 2002 Mark D. Studebaker - Copyright (C) 2004 Jean Delvare - Ported to Linux 2.6 by Gabriele Gorla - and Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -/* Address is autodetected, there is no default value */ -static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; -static struct i2c_force_data forces[] = {{NULL}}; - -enum chips { any_chip, smsc47m1 }; -static struct i2c_address_data addr_data = { - .normal_i2c = normal_i2c, - .normal_isa = normal_isa, - .forces = forces, -}; - -/* Super-I/0 registers and commands */ - -#define REG 0x2e /* The register to read/write */ -#define VAL 0x2f /* The value to read/write */ - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -/* logical device for fans is 0x0A */ -#define superio_select() superio_outb(0x07, 0x0A) - -static inline void -superio_enter(void) -{ - outb(0x55, REG); -} - -static inline void -superio_exit(void) -{ - outb(0xAA, REG); -} - -#define SUPERIO_REG_ACT 0x30 -#define SUPERIO_REG_BASE 0x60 -#define SUPERIO_REG_DEVID 0x20 - -/* Logical device registers */ - -#define SMSC_EXTENT 0x80 - -/* nr is 0 or 1 in the macros below */ -#define SMSC47M1_REG_ALARM 0x04 -#define SMSC47M1_REG_TPIN(nr) (0x34 - (nr)) -#define SMSC47M1_REG_PPIN(nr) (0x36 - (nr)) -#define SMSC47M1_REG_PWM(nr) (0x56 + (nr)) -#define SMSC47M1_REG_FANDIV 0x58 -#define SMSC47M1_REG_FAN(nr) (0x59 + (nr)) -#define SMSC47M1_REG_FAN_PRELOAD(nr) (0x5B + (nr)) - -#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \ - 983040/((192-(reg))*(div))) -#define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \ - 983040/(((reg)-(preload))*(div))) -#define DIV_FROM_REG(reg) (1 << (reg)) -#define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1) -#define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01) -#define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E) - -struct smsc47m1_data { - struct i2c_client client; - struct semaphore lock; - - struct semaphore update_lock; - unsigned long last_updated; /* In jiffies */ - - u8 fan[2]; /* Register value */ - u8 fan_preload[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u8 alarms; /* Register encoding */ - u8 pwm[2]; /* Register value (bit 7 is enable) */ -}; - - -static int smsc47m1_attach_adapter(struct i2c_adapter *adapter); -static int smsc47m1_find(int *address); -static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind); -static int smsc47m1_detach_client(struct i2c_client *client); - -static int smsc47m1_read_value(struct i2c_client *client, u8 reg); -static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value); - -static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, - int init); - - -static struct i2c_driver smsc47m1_driver = { - .owner = THIS_MODULE, - .name = "smsc47m1", - .id = I2C_DRIVERID_SMSC47M1, - .flags = I2C_DF_NOTIFY, - .attach_adapter = smsc47m1_attach_adapter, - .detach_client = smsc47m1_detach_client, -}; - -/* nr is 0 or 1 in the callback functions below */ - -static ssize_t get_fan(struct device *dev, char *buf, int nr) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - /* This chip (stupidly) stops monitoring fan speed if PWM is - enabled and duty cycle is 0%. This is fine if the monitoring - and control concern the same fan, but troublesome if they are - not (which could as well happen). */ - int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 : - FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr]), - data->fan_preload[nr]); - return sprintf(buf, "%d\n", rpm); -} - -static ssize_t get_fan_min(struct device *dev, char *buf, int nr) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - int rpm = MIN_FROM_REG(data->fan_preload[nr], - DIV_FROM_REG(data->fan_div[nr])); - return sprintf(buf, "%d\n", rpm); -} - -static ssize_t get_fan_div(struct device *dev, char *buf, int nr) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); -} - -static ssize_t get_pwm(struct device *dev, char *buf, int nr) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr])); -} - -static ssize_t get_pwm_en(struct device *dev, char *buf, int nr) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr])); -} - -static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); - return sprintf(buf, "%d\n", data->alarms); -} - -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - long rpmdiv, val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]); - - if (983040 > 192 * rpmdiv || 2 * rpmdiv > 983040) { - up(&data->update_lock); - return -EINVAL; - } - - data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv); - smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), - data->fan_preload[nr]); - up(&data->update_lock); - - return count; -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan clock divider. This follows the principle - of least suprise; the user doesn't expect the fan minimum to change just - because the divider changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - - long new_div = simple_strtol(buf, NULL, 10), tmp; - u8 old_div = DIV_FROM_REG(data->fan_div[nr]); - - if (new_div == old_div) /* No change */ - return count; - - down(&data->update_lock); - switch (new_div) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; - default: - up(&data->update_lock); - return -EINVAL; - } - - tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F; - tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6); - smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp); - - /* Preserve fan min */ - tmp = 192 - (old_div * (192 - data->fan_preload[nr]) - + new_div / 2) / new_div; - data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191); - smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr), - data->fan_preload[nr]); - up(&data->update_lock); - - return count; -} - -static ssize_t set_pwm(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - - long val = simple_strtol(buf, NULL, 10); - - if (val < 0 || val > 255) - return -EINVAL; - - down(&data->update_lock); - data->pwm[nr] &= 0x81; /* Preserve additional bits */ - data->pwm[nr] |= PWM_TO_REG(val); - smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), - data->pwm[nr]); - up(&data->update_lock); - - return count; -} - -static ssize_t set_pwm_en(struct device *dev, const char *buf, - size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - - long val = simple_strtol(buf, NULL, 10); - - if (val != 0 && val != 1) - return -EINVAL; - - down(&data->update_lock); - data->pwm[nr] &= 0xFE; /* preserve the other bits */ - data->pwm[nr] |= !val; - smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr), - data->pwm[nr]); - up(&data->update_lock); - - return count; -} - -#define fan_present(offset) \ -static ssize_t get_fan##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_fan(dev, buf, offset - 1); \ -} \ -static ssize_t get_fan##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t get_fan##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan##offset##_div (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static ssize_t get_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static ssize_t get_pwm##offset##_en (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return get_pwm_en(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_en (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_en(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset, \ - NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - get_fan##offset##_min, set_fan##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - get_fan##offset##_div, set_fan##offset##_div); \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - get_pwm##offset, set_pwm##offset); \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - get_pwm##offset##_en, set_pwm##offset##_en); - -fan_present(1); -fan_present(2); - -static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); - -static int smsc47m1_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, smsc47m1_detect); -} - -static int smsc47m1_find(int *address) -{ - u8 val; - - superio_enter(); - val = superio_inb(SUPERIO_REG_DEVID); - - /* - * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id - * 0x5F) and LPC47B27x (device id 0x51) have fan control. - * The LPC47M15x and LPC47M192 chips "with hardware monitoring block" - * can do much more besides (device id 0x60). - */ - if (val == 0x51) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n"); - else if (val == 0x59) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n"); - else if (val == 0x5F) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n"); - else if (val == 0x60) - printk(KERN_INFO "smsc47m1: Found SMSC LPC47M15x/LPC47M192\n"); - else { - superio_exit(); - return -ENODEV; - } - - superio_select(); - *address = (superio_inb(SUPERIO_REG_BASE) << 8) - | superio_inb(SUPERIO_REG_BASE + 1); - val = superio_inb(SUPERIO_REG_ACT); - if (*address == 0 || (val & 0x01) == 0) { - printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n"); - superio_exit(); - return -ENODEV; - } - - superio_exit(); - return 0; -} - -static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct smsc47m1_data *data; - int err = 0; - int fan1, fan2, pwm1, pwm2; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.name)) { - dev_err(&adapter->dev, "Region 0x%x already in use!\n", address); - return -EBUSY; - } - - if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error_release; - } - memset(data, 0x00, sizeof(struct smsc47m1_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->adapter = adapter; - new_client->driver = &smsc47m1_driver; - new_client->flags = 0; - - strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE); - init_MUTEX(&data->update_lock); - - /* If no function is properly configured, there's no point in - actually registering the chip. */ - fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05) - == 0x05; - fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05) - == 0x05; - pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05) - == 0x04; - pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05) - == 0x04; - if (!(fan1 || fan2 || pwm1 || pwm2)) { - dev_warn(&new_client->dev, "Device is not configured, will not use\n"); - err = -ENODEV; - goto error_free; - } - - if ((err = i2c_attach_client(new_client))) - goto error_free; - - /* Some values (fan min, clock dividers, pwm registers) may be - needed before any update is triggered, so we better read them - at least once here. We don't usually do it that way, but in - this particular case, manually reading 5 registers out of 8 - doesn't make much sense and we're better using the existing - function. */ - smsc47m1_update_device(&new_client->dev, 1); - - if (fan1) { - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - } else - dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, " - "skipping\n"); - - if (fan2) { - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - } else - dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, " - "skipping\n"); - - if (pwm1) { - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - } else - dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, " - "skipping\n"); - if (pwm2) { - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_pwm2_enable); - } else - dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, " - "skipping\n"); - - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -error_free: - kfree(new_client); -error_release: - release_region(address, SMSC_EXTENT); - return err; -} - -static int smsc47m1_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - release_region(client->addr, SMSC_EXTENT); - kfree(i2c_get_clientdata(client)); - - return 0; -} - -static int smsc47m1_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); - res = inb_p(client->addr + reg); - up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); - return res; -} - -static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); - outb_p(value, client->addr + reg); - up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock); -} - -static struct smsc47m1_data *smsc47m1_update_device(struct device *dev, - int init) -{ - struct i2c_client *client = to_i2c_client(dev); - struct smsc47m1_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) { - int i; - - for (i = 0; i < 2; i++) { - data->fan[i] = smsc47m1_read_value(client, - SMSC47M1_REG_FAN(i)); - data->fan_preload[i] = smsc47m1_read_value(client, - SMSC47M1_REG_FAN_PRELOAD(i)); - data->pwm[i] = smsc47m1_read_value(client, - SMSC47M1_REG_PWM(i)); - } - - i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - - data->alarms = smsc47m1_read_value(client, - SMSC47M1_REG_ALARM) >> 6; - /* Clear alarms if needed */ - if (data->alarms) - smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0); - - data->last_updated = jiffies; - } - - up(&data->update_lock); - return data; -} - -static int __init sm_smsc47m1_init(void) -{ - if (smsc47m1_find(normal_isa)) { - return -ENODEV; - } - - return i2c_add_driver(&smsc47m1_driver); -} - -static void __exit sm_smsc47m1_exit(void) -{ - i2c_del_driver(&smsc47m1_driver); -} - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_smsc47m1_init); -module_exit(sm_smsc47m1_exit); diff --git a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c deleted file mode 100644 index 164d4794839..00000000000 --- a/drivers/i2c/chips/via686a.c +++ /dev/null @@ -1,875 +0,0 @@ -/* - via686a.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 1998 - 2002 Frodo Looijaard , - Kyösti Mälkki , - Mark Studebaker , - and Bob Dougherty - (Some conversion-factor data were contributed by Jonathan Teh Soon Yew - and Alex van Kaam .) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Supports the Via VT82C686A, VT82C686B south bridges. - Reports all as a 686A. - Warning - only supports a single device. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - - -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ -static unsigned short force_addr = 0; -module_param(force_addr, ushort, 0); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -/* Addresses to scan. - Note that we can't determine the ISA address until we have initialized - our module */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0x0000, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(via686a); - -/* - The Via 686a southbridge has a LM78-like chip integrated on the same IC. - This driver is a customized copy of lm78.c -*/ - -/* Many VIA686A constants specified below */ - -/* Length of ISA address segment */ -#define VIA686A_EXTENT 0x80 -#define VIA686A_BASE_REG 0x70 -#define VIA686A_ENABLE_REG 0x74 - -/* The VIA686A registers */ -/* ins numbered 0-4 */ -#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) -#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) -#define VIA686A_REG_IN(nr) (0x22 + (nr)) - -/* fans numbered 1-2 */ -#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) -#define VIA686A_REG_FAN(nr) (0x28 + (nr)) - -/* temps numbered 1-3 */ -static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f }; -static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d }; -static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e }; -/* bits 7-6 */ -#define VIA686A_REG_TEMP_LOW1 0x4b -/* 2 = bits 5-4, 3 = bits 7-6 */ -#define VIA686A_REG_TEMP_LOW23 0x49 - -#define VIA686A_REG_ALARM1 0x41 -#define VIA686A_REG_ALARM2 0x42 -#define VIA686A_REG_FANDIV 0x47 -#define VIA686A_REG_CONFIG 0x40 -/* The following register sets temp interrupt mode (bits 1-0 for temp1, - 3-2 for temp2, 5-4 for temp3). Modes are: - 00 interrupt stays as long as value is out-of-range - 01 interrupt is cleared once register is read (default) - 10 comparator mode- like 00, but ignores hysteresis - 11 same as 00 */ -#define VIA686A_REG_TEMP_MODE 0x4b -/* We'll just assume that you want to set all 3 simultaneously: */ -#define VIA686A_TEMP_MODE_MASK 0x3F -#define VIA686A_TEMP_MODE_CONTINUOUS 0x00 - -/* Conversions. Limit checking is only done on the TO_REG - variants. - -********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** - From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): - voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp - voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V - voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V - voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V - voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V - in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; - That is: - volts = (25*regVal+133)*factor - regVal = (volts/factor-133)/25 - (These conversions were contributed by Jonathan Teh Soon Yew - ) */ -static inline u8 IN_TO_REG(long val, int inNum) -{ - /* To avoid floating point, we multiply constants by 10 (100 for +12V). - Rounding is done (120500 is actually 133000 - 12500). - Remember that val is expressed in 0.001V/bit, which is why we divide - by an additional 10000 (100000 for +12V): 1000 for val and 10 (100) - for the constants. */ - if (inNum <= 1) - return (u8) - SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255); - else if (inNum == 2) - return (u8) - SENSORS_LIMIT((val * 15737 - 1205000) / 250000, 0, 255); - else if (inNum == 3) - return (u8) - SENSORS_LIMIT((val * 10108 - 1205000) / 250000, 0, 255); - else - return (u8) - SENSORS_LIMIT((val * 41714 - 12050000) / 2500000, 0, 255); -} - -static inline long IN_FROM_REG(u8 val, int inNum) -{ - /* To avoid floating point, we multiply constants by 10 (100 for +12V). - We also multiply them by 1000 because we want 0.001V/bit for the - output value. Rounding is done. */ - if (inNum <= 1) - return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024); - else if (inNum == 2) - return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737); - else if (inNum == 3) - return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108); - else - return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714); -} - -/********* FAN RPM CONVERSIONS ********/ -/* Higher register values = slower fans (the fan's strobe gates a counter). - But this chip saturates back at 0, not at 255 like all the other chips. - So, 0 means 0 RPM */ -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 0; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); -} - -#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div))) - -/******** TEMP CONVERSIONS (Bob Dougherty) *********/ -/* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) - if(temp<169) - return double(temp)*0.427-32.08; - else if(temp>=169 && temp<=202) - return double(temp)*0.582-58.16; - else - return double(temp)*0.924-127.33; - - A fifth-order polynomial fits the unofficial data (provided by Alex van - Kaam ) a bit better. It also give more reasonable - numbers on my machine (ie. they agree with what my BIOS tells me). - Here's the fifth-order fit to the 8-bit data: - temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - - 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. - - (2000-10-25- RFD: thanks to Uwe Andersen for - finding my typos in this formula!) - - Alas, none of the elegant function-fit solutions will work because we - aren't allowed to use floating point in the kernel and doing it with - integers doesn't provide enough precision. So we'll do boring old - look-up table stuff. The unofficial data (see below) have effectively - 7-bit resolution (they are rounded to the nearest degree). I'm assuming - that the transfer function of the device is monotonic and smooth, so a - smooth function fit to the data will allow us to get better precision. - I used the 5th-order poly fit described above and solved for - VIA register values 0-255. I *10 before rounding, so we get tenth-degree - precision. (I could have done all 1024 values for our 10-bit readings, - but the function is very linear in the useful range (0-80 deg C), so - we'll just use linear interpolation for 10-bit readings.) So, tempLUT - is the temp at via register values 0-255: */ -static const long tempLUT[] = -{ -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, - -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, - -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, - -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, - -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, - -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, - -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, - 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, - 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, - 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, - 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, - 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, - 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, - 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, - 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, - 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, - 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, - 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, - 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, - 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, - 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, - 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 -}; - -/* the original LUT values from Alex van Kaam - (for via register values 12-240): -{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, --30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, --15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, --3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12, -12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22, -22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33, -33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45, -45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60, -61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84, -85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; - - - Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed - an extra term for a good fit to these inverse data!) and then - solving for each temp value from -50 to 110 (the useable range for - this chip). Here's the fit: - viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 - - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) - Note that n=161: */ -static const u8 viaLUT[] = -{ 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, - 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, - 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, - 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, - 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, - 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, - 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, - 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, - 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, - 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, - 239, 240 -}; - -/* Converting temps to (8-bit) hyst and over registers - No interpolation here. - The +50 is because the temps start at -50 */ -static inline u8 TEMP_TO_REG(long val) -{ - return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : - (val < 0 ? val - 500 : val + 500) / 1000 + 50]; -} - -/* for 8-bit temperature hyst and over registers */ -#define TEMP_FROM_REG(val) (tempLUT[(val)] * 100) - -/* for 10-bit temperature readings */ -static inline long TEMP_FROM_REG10(u16 val) -{ - u16 eightBits = val >> 2; - u16 twoBits = val & 3; - - /* no interpolation for these */ - if (twoBits == 0 || eightBits == 255) - return TEMP_FROM_REG(eightBits); - - /* do some linear interpolation */ - return (tempLUT[eightBits] * (4 - twoBits) + - tempLUT[eightBits + 1] * twoBits) * 25; -} - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) - -/* For the VIA686A, we need to keep some data in memory. - The structure is dynamically allocated, at the same time when a new - via686a client is allocated. */ -struct via686a_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[5]; /* Register value */ - u8 in_max[5]; /* Register value */ - u8 in_min[5]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u16 temp[3]; /* Register value 10 bit */ - u8 temp_over[3]; /* Register value */ - u8 temp_hyst[3]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding, combined */ -}; - -static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ - -static int via686a_attach_adapter(struct i2c_adapter *adapter); -static int via686a_detect(struct i2c_adapter *adapter, int address, int kind); -static int via686a_detach_client(struct i2c_client *client); - -static inline int via686a_read_value(struct i2c_client *client, u8 reg) -{ - return (inb_p(client->addr + reg)); -} - -static inline void via686a_write_value(struct i2c_client *client, u8 reg, - u8 value) -{ - outb_p(value, client->addr + reg); -} - -static struct via686a_data *via686a_update_device(struct device *dev); -static void via686a_init_client(struct i2c_client *client); - -/* following are the sysfs callback functions */ - -/* 7 voltage sensors */ -static ssize_t show_in(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr)); -} - -static ssize_t show_in_min(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr)); -} - -static ssize_t show_in_max(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)); -} - -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_min[nr] = IN_TO_REG(val, nr); - via686a_write_value(client, VIA686A_REG_IN_MIN(nr), - data->in_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->in_max[nr] = IN_TO_REG(val, nr); - via686a_write_value(client, VIA686A_REG_IN_MAX(nr), - data->in_max[nr]); - up(&data->update_lock); - return count; -} -#define show_in_offset(offset) \ -static ssize_t \ - show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t \ - show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); - -show_in_offset(0); -show_in_offset(1); -show_in_offset(2); -show_in_offset(3); -show_in_offset(4); - -/* 3 temperatures */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr])); -} -static ssize_t show_temp_over(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr])); -} -static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])); -} -static ssize_t set_temp_over(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_over[nr] = TEMP_TO_REG(val); - via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr], - data->temp_over[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_temp_hyst(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->temp_hyst[nr] = TEMP_TO_REG(val); - via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr], - data->temp_hyst[nr]); - up(&data->update_lock); - return count; -} -#define show_temp_offset(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t \ -show_temp_##offset##_over (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_over(dev, buf, offset - 1); \ -} \ -static ssize_t \ -show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_hyst(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_over(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_hyst(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_over, set_temp_##offset##_over); \ -static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_hyst, set_temp_##offset##_hyst); - -show_temp_offset(1); -show_temp_offset(2); -show_temp_offset(3); - -/* 2 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])) ); -} -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%d\n", - FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); -} -static ssize_t show_fan_div(struct device *dev, char *buf, int nr) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); -} -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]); - up(&data->update_lock); - return count; -} -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) { - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); - int old; - - down(&data->update_lock); - old = via686a_read_value(client, VIA686A_REG_FANDIV); - data->fan_div[nr] = DIV_TO_REG(val); - old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4); - via686a_write_value(client, VIA686A_REG_FANDIV, old); - up(&data->update_lock); - return count; -} - -#define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_div, set_fan_##offset##_div); - -show_fan_offset(1); -show_fan_offset(2); - -/* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { - struct via686a_data *data = via686a_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); - -/* The driver. I choose to use type i2c_driver, as at is identical to both - smbus_driver and isa_driver, and clients could be of either kind */ -static struct i2c_driver via686a_driver = { - .owner = THIS_MODULE, - .name = "via686a", - .id = I2C_DRIVERID_VIA686A, - .flags = I2C_DF_NOTIFY, - .attach_adapter = via686a_attach_adapter, - .detach_client = via686a_detach_client, -}; - - -/* This is called when the module is loaded */ -static int via686a_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, via686a_detect); -} - -static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct via686a_data *data; - int err = 0; - const char client_name[] = "via686a"; - u16 val; - - /* Make sure we are probing the ISA bus!! */ - if (!i2c_is_isa_adapter(adapter)) { - dev_err(&adapter->dev, - "via686a_detect called for an I2C bus adapter?!?\n"); - return 0; - } - - /* 8231 requires multiple of 256, we enforce that on 686 as well */ - if (force_addr) - address = force_addr & 0xFF00; - - if (force_addr) { - dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", - address); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) - return -ENODEV; - } - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) - return -ENODEV; - if (!(val & 0x0001)) { - dev_warn(&adapter->dev, "enabling sensors\n"); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, - val | 0x0001)) - return -ENODEV; - } - - /* Reserve the ISA region */ - if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) { - dev_err(&adapter->dev, "region 0x%x already in use!\n", - address); - return -ENODEV; - } - - if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - memset(data, 0, sizeof(struct via686a_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &via686a_driver; - new_client->flags = 0; - - /* Fill in the remaining client fields and put into the global list */ - strlcpy(new_client->name, client_name, I2C_NAME_SIZE); - - data->valid = 0; - init_MUTEX(&data->update_lock); - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Initialize the VIA686A chip */ - via686a_init_client(new_client); - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_alarms); - - return 0; - -ERROR3: - kfree(data); -ERROR0: - release_region(address, VIA686A_EXTENT); - return err; -} - -static int via686a_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, VIA686A_EXTENT); - kfree(i2c_get_clientdata(client)); - - return 0; -} - -/* Called when we have found a new VIA686A. Set limits, etc. */ -static void via686a_init_client(struct i2c_client *client) -{ - u8 reg; - - /* Start monitoring */ - reg = via686a_read_value(client, VIA686A_REG_CONFIG); - via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); - - /* Configure temp interrupt mode for continuous-interrupt operation */ - via686a_write_value(client, VIA686A_REG_TEMP_MODE, - via686a_read_value(client, VIA686A_REG_TEMP_MODE) & - !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); -} - -static struct via686a_data *via686a_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct via686a_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - for (i = 0; i <= 4; i++) { - data->in[i] = - via686a_read_value(client, VIA686A_REG_IN(i)); - data->in_min[i] = via686a_read_value(client, - VIA686A_REG_IN_MIN - (i)); - data->in_max[i] = - via686a_read_value(client, VIA686A_REG_IN_MAX(i)); - } - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = - via686a_read_value(client, VIA686A_REG_FAN(i)); - data->fan_min[i - 1] = via686a_read_value(client, - VIA686A_REG_FAN_MIN(i)); - } - for (i = 0; i <= 2; i++) { - data->temp[i] = via686a_read_value(client, - VIA686A_REG_TEMP[i]) << 2; - data->temp_over[i] = - via686a_read_value(client, - VIA686A_REG_TEMP_OVER[i]); - data->temp_hyst[i] = - via686a_read_value(client, - VIA686A_REG_TEMP_HYST[i]); - } - /* add in lower 2 bits - temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 - temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 - temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 - */ - data->temp[0] |= (via686a_read_value(client, - VIA686A_REG_TEMP_LOW1) - & 0xc0) >> 6; - data->temp[1] |= - (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & - 0x30) >> 4; - data->temp[2] |= - (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & - 0xc0) >> 6; - - i = via686a_read_value(client, VIA686A_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = - via686a_read_value(client, - VIA686A_REG_ALARM1) | - (via686a_read_value(client, VIA686A_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static struct pci_device_id via686a_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, via686a_pci_ids); - -static int __devinit via686a_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - u16 val; - int addr = 0; - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(dev, VIA686A_BASE_REG, &val)) - return -ENODEV; - - addr = val & ~(VIA686A_EXTENT - 1); - if (addr == 0 && force_addr == 0) { - dev_err(&dev->dev, "base address not set - upgrade BIOS " - "or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - addr = force_addr; /* so detect will get called */ - - if (!addr) { - dev_err(&dev->dev, "No Via 686A sensors found.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - s_bridge = pci_dev_get(dev); - if (i2c_add_driver(&via686a_driver)) { - pci_dev_put(s_bridge); - s_bridge = NULL; - } - - /* Always return failure here. This is to allow other drivers to bind - * to this pci device. We don't really want to have control over the - * pci device, we only wanted to read as few register values from it. - */ - return -ENODEV; -} - -static struct pci_driver via686a_pci_driver = { - .name = "via686a", - .id_table = via686a_pci_ids, - .probe = via686a_pci_probe, -}; - -static int __init sm_via686a_init(void) -{ - return pci_register_driver(&via686a_pci_driver); -} - -static void __exit sm_via686a_exit(void) -{ - pci_unregister_driver(&via686a_pci_driver); - if (s_bridge != NULL) { - i2c_del_driver(&via686a_driver); - pci_dev_put(s_bridge); - s_bridge = NULL; - } -} - -MODULE_AUTHOR("Kyösti Mälkki , " - "Mark Studebaker " - "and Bob Dougherty "); -MODULE_DESCRIPTION("VIA 686A Sensor device"); -MODULE_LICENSE("GPL"); - -module_init(sm_via686a_init); -module_exit(sm_via686a_exit); diff --git a/drivers/i2c/chips/w83627ehf.c b/drivers/i2c/chips/w83627ehf.c deleted file mode 100644 index 8a40b6976e1..00000000000 --- a/drivers/i2c/chips/w83627ehf.c +++ /dev/null @@ -1,846 +0,0 @@ -/* - w83627ehf - Driver for the hardware monitoring functionality of - the Winbond W83627EHF Super-I/O chip - Copyright (C) 2005 Jean Delvare - - Shamelessly ripped from the w83627hf driver - Copyright (C) 2003 Mark Studebaker - - Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help - in testing and debugging this driver. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - - Supports the following chips: - - Chip #vin #fan #pwm #temp chip_id man_id - w83627ehf - 5 - 3 0x88 0x5ca3 - - This is a preliminary version of the driver, only supporting the - fan and temperature inputs. The chip does much more than that. -*/ - -#include -#include -#include -#include -#include -#include -#include "lm75.h" - -/* Addresses to scan - The actual ISA address is read from Super-I/O configuration space */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(w83627ehf); - -/* - * Super-I/O constants and functions - */ - -static int REG; /* The register to read/write */ -static int VAL; /* The value to read/write */ - -#define W83627EHF_LD_HWM 0x0b - -#define SIO_REG_LDSEL 0x07 /* Logical device select */ -#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ -#define SIO_REG_ENABLE 0x30 /* Logical device enable */ -#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ - -#define SIO_W83627EHF_ID 0x8840 -#define SIO_ID_MASK 0xFFC0 - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static inline void -superio_select(int ld) -{ - outb(SIO_REG_LDSEL, REG); - outb(ld, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x87, REG); -} - -static inline void -superio_exit(void) -{ - outb(0x02, REG); - outb(0x02, VAL); -} - -/* - * ISA constants - */ - -#define REGION_LENGTH 8 -#define ADDR_REG_OFFSET 5 -#define DATA_REG_OFFSET 6 - -#define W83627EHF_REG_BANK 0x4E -#define W83627EHF_REG_CONFIG 0x40 -#define W83627EHF_REG_CHIP_ID 0x49 -#define W83627EHF_REG_MAN_ID 0x4F - -static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; -static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; - -#define W83627EHF_REG_TEMP1 0x27 -#define W83627EHF_REG_TEMP1_HYST 0x3a -#define W83627EHF_REG_TEMP1_OVER 0x39 -static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 }; -static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 }; -static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 }; -static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; - -/* Fan clock dividers are spread over the following five registers */ -#define W83627EHF_REG_FANDIV1 0x47 -#define W83627EHF_REG_FANDIV2 0x4B -#define W83627EHF_REG_VBAT 0x5D -#define W83627EHF_REG_DIODE 0x59 -#define W83627EHF_REG_SMI_OVT 0x4C - -/* - * Conversions - */ - -static inline unsigned int -fan_from_reg(u8 reg, unsigned int div) -{ - if (reg == 0 || reg == 255) - return 0; - return 1350000U / (reg * div); -} - -static inline unsigned int -div_from_reg(u8 reg) -{ - return 1 << reg; -} - -static inline int -temp1_from_reg(s8 reg) -{ - return reg * 1000; -} - -static inline s8 -temp1_to_reg(int temp) -{ - if (temp <= -128000) - return -128; - if (temp >= 127000) - return 127; - if (temp < 0) - return (temp - 500) / 1000; - return (temp + 500) / 1000; -} - -/* - * Data structures and manipulation thereof - */ - -struct w83627ehf_data { - struct i2c_client client; - struct semaphore lock; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - /* Register values */ - u8 fan[5]; - u8 fan_min[5]; - u8 fan_div[5]; - u8 has_fan; /* some fan inputs can be disabled */ - s8 temp1; - s8 temp1_max; - s8 temp1_max_hyst; - s16 temp[2]; - s16 temp_max[2]; - s16 temp_max_hyst[2]; -}; - -static inline int is_word_sized(u16 reg) -{ - return (((reg & 0xff00) == 0x100 - || (reg & 0xff00) == 0x200) - && ((reg & 0x00ff) == 0x50 - || (reg & 0x00ff) == 0x53 - || (reg & 0x00ff) == 0x55)); -} - -/* We assume that the default bank is 0, thus the following two functions do - nothing for registers which live in bank 0. For others, they respectively - set the bank register to the correct value (before the register is - accessed), and back to 0 (afterwards). */ -static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg) -{ - if (reg & 0xff00) { - outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); - outb_p(reg >> 8, client->addr + DATA_REG_OFFSET); - } -} - -static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg) -{ - if (reg & 0xff00) { - outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET); - outb_p(0, client->addr + DATA_REG_OFFSET); - } -} - -static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg) -{ - struct w83627ehf_data *data = i2c_get_clientdata(client); - int res, word_sized = is_word_sized(reg); - - down(&data->lock); - - w83627ehf_set_bank(client, reg); - outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); - res = inb_p(client->addr + DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, - client->addr + ADDR_REG_OFFSET); - res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET); - } - w83627ehf_reset_bank(client, reg); - - up(&data->lock); - - return res; -} - -static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - struct w83627ehf_data *data = i2c_get_clientdata(client); - int word_sized = is_word_sized(reg); - - down(&data->lock); - - w83627ehf_set_bank(client, reg); - outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, client->addr + DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, - client->addr + ADDR_REG_OFFSET); - } - outb_p(value & 0xff, client->addr + DATA_REG_OFFSET); - w83627ehf_reset_bank(client, reg); - - up(&data->lock); - return 0; -} - -/* This function assumes that the caller holds data->update_lock */ -static void w83627ehf_write_fan_div(struct i2c_client *client, int nr) -{ - struct w83627ehf_data *data = i2c_get_clientdata(client); - u8 reg; - - switch (nr) { - case 0: - reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf) - | ((data->fan_div[0] & 0x03) << 4); - w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf) - | ((data->fan_div[0] & 0x04) << 3); - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); - break; - case 1: - reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f) - | ((data->fan_div[1] & 0x03) << 6); - w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf) - | ((data->fan_div[1] & 0x04) << 4); - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); - break; - case 2: - reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f) - | ((data->fan_div[2] & 0x03) << 6); - w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f) - | ((data->fan_div[2] & 0x04) << 5); - w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg); - break; - case 3: - reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc) - | (data->fan_div[3] & 0x03); - w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); - reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f) - | ((data->fan_div[3] & 0x04) << 5); - w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg); - break; - case 4: - reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73) - | ((data->fan_div[4] & 0x03) << 3) - | ((data->fan_div[4] & 0x04) << 5); - w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg); - break; - } -} - -static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627ehf_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) - || !data->valid) { - /* Fan clock dividers */ - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2); - data->fan_div[2] = (i >> 6) & 0x03; - i = w83627ehf_read_value(client, W83627EHF_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - data->fan_div[2] |= (i >> 5) & 0x04; - if (data->has_fan & ((1 << 3) | (1 << 4))) { - i = w83627ehf_read_value(client, W83627EHF_REG_DIODE); - data->fan_div[3] = i & 0x03; - data->fan_div[4] = ((i >> 2) & 0x03) - | ((i >> 5) & 0x04); - } - if (data->has_fan & (1 << 3)) { - i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT); - data->fan_div[3] |= (i >> 5) & 0x04; - } - - /* Measured fan speeds and limits */ - for (i = 0; i < 5; i++) { - if (!(data->has_fan & (1 << i))) - continue; - - data->fan[i] = w83627ehf_read_value(client, - W83627EHF_REG_FAN[i]); - data->fan_min[i] = w83627ehf_read_value(client, - W83627EHF_REG_FAN_MIN[i]); - - /* If we failed to measure the fan speed and clock - divider can be increased, let's try that for next - time */ - if (data->fan[i] == 0xff - && data->fan_div[i] < 0x07) { - dev_dbg(&client->dev, "Increasing fan %d " - "clock divider from %u to %u\n", - i, div_from_reg(data->fan_div[i]), - div_from_reg(data->fan_div[i] + 1)); - data->fan_div[i]++; - w83627ehf_write_fan_div(client, i); - /* Preserve min limit if possible */ - if (data->fan_min[i] >= 2 - && data->fan_min[i] != 255) - w83627ehf_write_value(client, - W83627EHF_REG_FAN_MIN[i], - (data->fan_min[i] /= 2)); - } - } - - /* Measured temperatures and limits */ - data->temp1 = w83627ehf_read_value(client, - W83627EHF_REG_TEMP1); - data->temp1_max = w83627ehf_read_value(client, - W83627EHF_REG_TEMP1_OVER); - data->temp1_max_hyst = w83627ehf_read_value(client, - W83627EHF_REG_TEMP1_HYST); - for (i = 0; i < 2; i++) { - data->temp[i] = w83627ehf_read_value(client, - W83627EHF_REG_TEMP[i]); - data->temp_max[i] = w83627ehf_read_value(client, - W83627EHF_REG_TEMP_OVER[i]); - data->temp_max_hyst[i] = w83627ehf_read_value(client, - W83627EHF_REG_TEMP_HYST[i]); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - return data; -} - -/* - * Sysfs callback functions - */ - -#define show_fan_reg(reg) \ -static ssize_t \ -show_##reg(struct device *dev, char *buf, int nr) \ -{ \ - struct w83627ehf_data *data = w83627ehf_update_device(dev); \ - return sprintf(buf, "%d\n", \ - fan_from_reg(data->reg[nr], \ - div_from_reg(data->fan_div[nr]))); \ -} -show_fan_reg(fan); -show_fan_reg(fan_min); - -static ssize_t -show_fan_div(struct device *dev, char *buf, int nr) -{ - struct w83627ehf_data *data = w83627ehf_update_device(dev); - return sprintf(buf, "%u\n", - div_from_reg(data->fan_div[nr])); -} - -static ssize_t -store_fan_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627ehf_data *data = i2c_get_clientdata(client); - unsigned int val = simple_strtoul(buf, NULL, 10); - unsigned int reg; - u8 new_div; - - down(&data->update_lock); - if (!val) { - /* No min limit, alarm disabled */ - data->fan_min[nr] = 255; - new_div = data->fan_div[nr]; /* No change */ - dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1); - } else if ((reg = 1350000U / val) >= 128 * 255) { - /* Speed below this value cannot possibly be represented, - even with the highest divider (128) */ - data->fan_min[nr] = 254; - new_div = 7; /* 128 == (1 << 7) */ - dev_warn(dev, "fan%u low limit %u below minimum %u, set to " - "minimum\n", nr + 1, val, fan_from_reg(254, 128)); - } else if (!reg) { - /* Speed above this value cannot possibly be represented, - even with the lowest divider (1) */ - data->fan_min[nr] = 1; - new_div = 0; /* 1 == (1 << 0) */ - dev_warn(dev, "fan%u low limit %u above maximum %u, set to " - "maximum\n", nr + 1, val, fan_from_reg(1, 1)); - } else { - /* Automatically pick the best divider, i.e. the one such - that the min limit will correspond to a register value - in the 96..192 range */ - new_div = 0; - while (reg > 192 && new_div < 7) { - reg >>= 1; - new_div++; - } - data->fan_min[nr] = reg; - } - - /* Write both the fan clock divider (if it changed) and the new - fan min (unconditionally) */ - if (new_div != data->fan_div[nr]) { - if (new_div > data->fan_div[nr]) - data->fan[nr] >>= (data->fan_div[nr] - new_div); - else - data->fan[nr] <<= (new_div - data->fan_div[nr]); - - dev_dbg(dev, "fan%u clock divider changed from %u to %u\n", - nr + 1, div_from_reg(data->fan_div[nr]), - div_from_reg(new_div)); - data->fan_div[nr] = new_div; - w83627ehf_write_fan_div(client, nr); - } - w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr], - data->fan_min[nr]); - up(&data->update_lock); - - return count; -} - -#define sysfs_fan_offset(offset) \ -static ssize_t \ -show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_fan(dev, buf, offset-1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_reg_fan_##offset, NULL); - -#define sysfs_fan_min_offset(offset) \ -static ssize_t \ -show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_fan_min(dev, buf, offset-1); \ -} \ -static ssize_t \ -store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_fan_min(dev, buf, count, offset-1); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_reg_fan##offset##_min, \ - store_reg_fan##offset##_min); - -#define sysfs_fan_div_offset(offset) \ -static ssize_t \ -show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_fan_div(dev, buf, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \ - show_reg_fan##offset##_div, NULL); - -sysfs_fan_offset(1); -sysfs_fan_min_offset(1); -sysfs_fan_div_offset(1); -sysfs_fan_offset(2); -sysfs_fan_min_offset(2); -sysfs_fan_div_offset(2); -sysfs_fan_offset(3); -sysfs_fan_min_offset(3); -sysfs_fan_div_offset(3); -sysfs_fan_offset(4); -sysfs_fan_min_offset(4); -sysfs_fan_div_offset(4); -sysfs_fan_offset(5); -sysfs_fan_min_offset(5); -sysfs_fan_div_offset(5); - -#define show_temp1_reg(reg) \ -static ssize_t \ -show_##reg(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct w83627ehf_data *data = w83627ehf_update_device(dev); \ - return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \ -} -show_temp1_reg(temp1); -show_temp1_reg(temp1_max); -show_temp1_reg(temp1_max_hyst); - -#define store_temp1_reg(REG, reg) \ -static ssize_t \ -store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627ehf_data *data = i2c_get_clientdata(client); \ - u32 val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->temp1_##reg = temp1_to_reg(val); \ - w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \ - data->temp1_##reg); \ - up(&data->update_lock); \ - return count; \ -} -store_temp1_reg(OVER, max); -store_temp1_reg(HYST, max_hyst); - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR, - show_temp1_max, store_temp1_max); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR, - show_temp1_max_hyst, store_temp1_max_hyst); - -#define show_temp_reg(reg) \ -static ssize_t \ -show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627ehf_data *data = w83627ehf_update_device(dev); \ - return sprintf(buf, "%d\n", \ - LM75_TEMP_FROM_REG(data->reg[nr])); \ -} -show_temp_reg(temp); -show_temp_reg(temp_max); -show_temp_reg(temp_max_hyst); - -#define store_temp_reg(REG, reg) \ -static ssize_t \ -store_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627ehf_data *data = i2c_get_clientdata(client); \ - u32 val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->reg[nr] = LM75_TEMP_TO_REG(val); \ - w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \ - data->reg[nr]); \ - up(&data->update_lock); \ - return count; \ -} -store_temp_reg(OVER, temp_max); -store_temp_reg(HYST, temp_max_hyst); - -#define sysfs_temp_offset(offset) \ -static ssize_t \ -show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp(dev, buf, offset - 2); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_reg_temp##offset, NULL); - -#define sysfs_temp_reg_offset(reg, offset) \ -static ssize_t \ -show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_##reg(dev, buf, offset - 2); \ -} \ -static ssize_t \ -store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_temp_##reg(dev, buf, count, offset - 2); \ -} \ -static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_reg_temp##offset##_##reg, \ - store_reg_temp##offset##_##reg); - -sysfs_temp_offset(2); -sysfs_temp_reg_offset(max, 2); -sysfs_temp_reg_offset(max_hyst, 2); -sysfs_temp_offset(3); -sysfs_temp_reg_offset(max, 3); -sysfs_temp_reg_offset(max_hyst, 3); - -/* - * Driver and client management - */ - -static struct i2c_driver w83627ehf_driver; - -static void w83627ehf_init_client(struct i2c_client *client) -{ - int i; - u8 tmp; - - /* Start monitoring is needed */ - tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG); - if (!(tmp & 0x01)) - w83627ehf_write_value(client, W83627EHF_REG_CONFIG, - tmp | 0x01); - - /* Enable temp2 and temp3 if needed */ - for (i = 0; i < 2; i++) { - tmp = w83627ehf_read_value(client, - W83627EHF_REG_TEMP_CONFIG[i]); - if (tmp & 0x01) - w83627ehf_write_value(client, - W83627EHF_REG_TEMP_CONFIG[i], - tmp & 0xfe); - } -} - -static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *client; - struct w83627ehf_data *data; - int i, err = 0; - - if (!i2c_is_isa_adapter(adapter)) - return 0; - - if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) { - err = -EBUSY; - goto exit; - } - - if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit_release; - } - memset(data, 0, sizeof(struct w83627ehf_data)); - - client = &data->client; - i2c_set_clientdata(client, data); - client->addr = address; - init_MUTEX(&data->lock); - client->adapter = adapter; - client->driver = &w83627ehf_driver; - client->flags = 0; - - strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the i2c layer a new client has arrived */ - if ((err = i2c_attach_client(client))) - goto exit_free; - - /* Initialize the chip */ - w83627ehf_init_client(client); - - /* A few vars need to be filled upon startup */ - for (i = 0; i < 5; i++) - data->fan_min[i] = w83627ehf_read_value(client, - W83627EHF_REG_FAN_MIN[i]); - - /* It looks like fan4 and fan5 pins can be alternatively used - as fan on/off switches */ - data->has_fan = 0x07; /* fan1, fan2 and fan3 */ - i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); - if (i & (1 << 2)) - data->has_fan |= (1 << 3); - if (i & (1 << 0)) - data->has_fan |= (1 << 4); - - /* Register sysfs hooks */ - device_create_file(&client->dev, &dev_attr_fan1_input); - device_create_file(&client->dev, &dev_attr_fan1_min); - device_create_file(&client->dev, &dev_attr_fan1_div); - device_create_file(&client->dev, &dev_attr_fan2_input); - device_create_file(&client->dev, &dev_attr_fan2_min); - device_create_file(&client->dev, &dev_attr_fan2_div); - device_create_file(&client->dev, &dev_attr_fan3_input); - device_create_file(&client->dev, &dev_attr_fan3_min); - device_create_file(&client->dev, &dev_attr_fan3_div); - - if (data->has_fan & (1 << 3)) { - device_create_file(&client->dev, &dev_attr_fan4_input); - device_create_file(&client->dev, &dev_attr_fan4_min); - device_create_file(&client->dev, &dev_attr_fan4_div); - } - if (data->has_fan & (1 << 4)) { - device_create_file(&client->dev, &dev_attr_fan5_input); - device_create_file(&client->dev, &dev_attr_fan5_min); - device_create_file(&client->dev, &dev_attr_fan5_div); - } - - device_create_file(&client->dev, &dev_attr_temp1_input); - device_create_file(&client->dev, &dev_attr_temp1_max); - device_create_file(&client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&client->dev, &dev_attr_temp2_input); - device_create_file(&client->dev, &dev_attr_temp2_max); - device_create_file(&client->dev, &dev_attr_temp2_max_hyst); - device_create_file(&client->dev, &dev_attr_temp3_input); - device_create_file(&client->dev, &dev_attr_temp3_max); - device_create_file(&client->dev, &dev_attr_temp3_max_hyst); - - return 0; - -exit_free: - kfree(data); -exit_release: - release_region(address, REGION_LENGTH); -exit: - return err; -} - -static int w83627ehf_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, w83627ehf_detect); -} - -static int w83627ehf_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - release_region(client->addr, REGION_LENGTH); - kfree(i2c_get_clientdata(client)); - - return 0; -} - -static struct i2c_driver w83627ehf_driver = { - .owner = THIS_MODULE, - .name = "w83627ehf", - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83627ehf_attach_adapter, - .detach_client = w83627ehf_detach_client, -}; - -static int __init w83627ehf_find(int sioaddr, int *address) -{ - u16 val; - - REG = sioaddr; - VAL = sioaddr + 1; - superio_enter(); - - val = (superio_inb(SIO_REG_DEVID) << 8) - | superio_inb(SIO_REG_DEVID + 1); - if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) { - superio_exit(); - return -ENODEV; - } - - superio_select(W83627EHF_LD_HWM); - val = (superio_inb(SIO_REG_ADDR) << 8) - | superio_inb(SIO_REG_ADDR + 1); - *address = val & ~(REGION_LENGTH - 1); - if (*address == 0) { - superio_exit(); - return -ENODEV; - } - - /* Activate logical device if needed */ - val = superio_inb(SIO_REG_ENABLE); - if (!(val & 0x01)) - superio_outb(SIO_REG_ENABLE, val | 0x01); - - superio_exit(); - return 0; -} - -static int __init sensors_w83627ehf_init(void) -{ - if (w83627ehf_find(0x2e, &normal_isa[0]) - && w83627ehf_find(0x4e, &normal_isa[0])) - return -ENODEV; - - return i2c_add_driver(&w83627ehf_driver); -} - -static void __exit sensors_w83627ehf_exit(void) -{ - i2c_del_driver(&w83627ehf_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("W83627EHF driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_w83627ehf_init); -module_exit(sensors_w83627ehf_exit); diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c deleted file mode 100644 index bd87a42e068..00000000000 --- a/drivers/i2c/chips/w83627hf.c +++ /dev/null @@ -1,1511 +0,0 @@ -/* - w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2003 Frodo Looijaard , - Philip Edelbrock , - and Mark Studebaker - Ported to 2.6 by Bernhard C. Schrenk - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) - w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) - w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) - w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) - - For other winbond chips, and for i2c support in the above chips, - use w83781d.c. - - Note: automatic ("cruise") fan control for 697, 637 & 627thf not - supported yet. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "lm75.h" - -static u16 force_addr; -module_param(force_addr, ushort, 0); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); -static u8 force_i2c = 0x1f; -module_param(force_i2c, byte, 0); -MODULE_PARM_DESC(force_i2c, - "Initialize the i2c address of the sensors"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf); - -static int init = 1; -module_param(init, bool, 0); -MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); - -/* modified from kernel/include/traps.c */ -static int REG; /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -static int VAL; /* The value to read/write */ - -/* logical device numbers for superio_select (below) */ -#define W83627HF_LD_FDC 0x00 -#define W83627HF_LD_PRT 0x01 -#define W83627HF_LD_UART1 0x02 -#define W83627HF_LD_UART2 0x03 -#define W83627HF_LD_KBC 0x05 -#define W83627HF_LD_CIR 0x06 /* w83627hf only */ -#define W83627HF_LD_GAME 0x07 -#define W83627HF_LD_MIDI 0x07 -#define W83627HF_LD_GPIO1 0x07 -#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */ -#define W83627HF_LD_GPIO2 0x08 -#define W83627HF_LD_GPIO3 0x09 -#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */ -#define W83627HF_LD_ACPI 0x0a -#define W83627HF_LD_HWM 0x0b - -#define DEVID 0x20 /* Register: Device ID */ - -#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */ -#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */ -#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */ - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static inline void -superio_select(int ld) -{ - outb(DEV, REG); - outb(ld, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x87, REG); -} - -static inline void -superio_exit(void) -{ - outb(0xAA, REG); -} - -#define W627_DEVID 0x52 -#define W627THF_DEVID 0x82 -#define W697_DEVID 0x60 -#define W637_DEVID 0x70 -#define WINB_ACT_REG 0x30 -#define WINB_BASE_REG 0x60 -/* Constants specified below */ - -/* Length of ISA address segment */ -#define WINB_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define W83781D_ADDR_REG_OFFSET 5 -#define W83781D_DATA_REG_OFFSET 6 - -/* The W83781D registers */ -/* The W83782D registers for nr=7,8 are in bank 5 */ -#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ - (0x554 + (((nr) - 7) * 2))) -#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ - (0x555 + (((nr) - 7) * 2))) -#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ - (0x550 + (nr) - 7)) - -#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) -#define W83781D_REG_FAN(nr) (0x27 + (nr)) - -#define W83781D_REG_TEMP2_CONFIG 0x152 -#define W83781D_REG_TEMP3_CONFIG 0x252 -#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ - ((nr == 2) ? (0x0150) : \ - (0x27))) -#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \ - ((nr == 2) ? (0x153) : \ - (0x3A))) -#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \ - ((nr == 2) ? (0x155) : \ - (0x39))) - -#define W83781D_REG_BANK 0x4E - -#define W83781D_REG_CONFIG 0x40 -#define W83781D_REG_ALARM1 0x41 -#define W83781D_REG_ALARM2 0x42 -#define W83781D_REG_ALARM3 0x450 - -#define W83781D_REG_IRQ 0x4C -#define W83781D_REG_BEEP_CONFIG 0x4D -#define W83781D_REG_BEEP_INTS1 0x56 -#define W83781D_REG_BEEP_INTS2 0x57 -#define W83781D_REG_BEEP_INTS3 0x453 - -#define W83781D_REG_VID_FANDIV 0x47 - -#define W83781D_REG_CHIPID 0x49 -#define W83781D_REG_WCHIPID 0x58 -#define W83781D_REG_CHIPMAN 0x4F -#define W83781D_REG_PIN 0x4B - -#define W83781D_REG_VBAT 0x5D - -#define W83627HF_REG_PWM1 0x5A -#define W83627HF_REG_PWM2 0x5B -#define W83627HF_REG_PWMCLK12 0x5C - -#define W83627THF_REG_PWM1 0x01 /* 697HF and 637HF too */ -#define W83627THF_REG_PWM2 0x03 /* 697HF and 637HF too */ -#define W83627THF_REG_PWM3 0x11 /* 637HF too */ - -#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF too */ - -static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; -static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, - W83627THF_REG_PWM3 }; -#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ - regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1]) - -#define W83781D_REG_I2C_ADDR 0x48 -#define W83781D_REG_I2C_SUBADDR 0x4A - -/* Sensor selection */ -#define W83781D_REG_SCFG1 0x5D -static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; -#define W83781D_REG_SCFG2 0x59 -static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; -#define W83781D_DEFAULT_BETA 3435 - -/* Conversions. Limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) -#define IN_FROM_REG(val) ((val) * 16) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define TEMP_MIN (-128000) -#define TEMP_MAX ( 127000) - -/* TEMP: 0.001C/bit (-128C to +127C) - REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); - ntemp += (ntemp<0 ? -500 : 500); - return (u8)(ntemp / 1000); -} - -static int TEMP_FROM_REG(u8 reg) -{ - return (s8)reg * 1000; -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) - -#define BEEP_MASK_FROM_REG(val) (val) -#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff) -#define BEEP_ENABLE_TO_REG(val) ((val)?1:0) -#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0) - -#define DIV_FROM_REG(val) (1 << (val)) - -static inline u8 DIV_TO_REG(long val) -{ - int i; - val = SENSORS_LIMIT(val, 1, 128) >> 1; - for (i = 0; i < 7; i++) { - if (val == 0) - break; - val >>= 1; - } - return ((u8) i); -} - -/* For each registered chip, we need to keep some data in memory. That - data is pointed to by w83627hf_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new client is allocated. */ -struct w83627hf_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - struct i2c_client *lm75; /* for secondary I2C addresses */ - /* pointer to array of 2 subclients */ - - u8 in[9]; /* Register value */ - u8 in_max[9]; /* Register value */ - u8 in_min[9]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp; - u8 temp_max; /* Register value */ - u8 temp_max_hyst; /* Register value */ - u16 temp_add[2]; /* Register value */ - u16 temp_max_add[2]; /* Register value */ - u16 temp_max_hyst_add[2]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u32 beep_mask; /* Register encoding, combined */ - u8 beep_enable; /* Boolean */ - u8 pwm[3]; /* Register value */ - u16 sens[3]; /* 782D/783S only. - 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ - u8 vrm; - u8 vrm_ovt; /* Register value, 627thf & 637hf only */ -}; - - -static int w83627hf_attach_adapter(struct i2c_adapter *adapter); -static int w83627hf_detect(struct i2c_adapter *adapter, int address, - int kind); -static int w83627hf_detach_client(struct i2c_client *client); - -static int w83627hf_read_value(struct i2c_client *client, u16 register); -static int w83627hf_write_value(struct i2c_client *client, u16 register, - u16 value); -static struct w83627hf_data *w83627hf_update_device(struct device *dev); -static void w83627hf_init_client(struct i2c_client *client); - -static struct i2c_driver w83627hf_driver = { - .owner = THIS_MODULE, - .name = "w83627hf", - .id = I2C_DRIVERID_W83627HF, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83627hf_attach_adapter, - .detach_client = w83627hf_detach_client, -}; - -/* following are the sysfs callback functions */ -#define show_in_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \ -} -show_in_reg(in) -show_in_reg(in_min) -show_in_reg(in_max) - -#define store_in_reg(REG, reg) \ -static ssize_t \ -store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627hf_data *data = i2c_get_clientdata(client); \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - data->in_##reg[nr] = IN_TO_REG(val); \ - w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \ - data->in_##reg[nr]); \ - \ - up(&data->update_lock); \ - return count; \ -} -store_in_reg(MIN, min) -store_in_reg(MAX, max) - -#define sysfs_in_offset(offset) \ -static ssize_t \ -show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); - -#define sysfs_in_reg_offset(reg, offset) \ -static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_##reg (dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_in_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_regs_in_##reg##offset, store_regs_in_##reg##offset); - -#define sysfs_in_offsets(offset) \ -sysfs_in_offset(offset) \ -sysfs_in_reg_offset(min, offset) \ -sysfs_in_reg_offset(max, offset) - -sysfs_in_offsets(1); -sysfs_in_offsets(2); -sysfs_in_offsets(3); -sysfs_in_offsets(4); -sysfs_in_offsets(5); -sysfs_in_offsets(6); -sysfs_in_offsets(7); -sysfs_in_offsets(8); - -/* use a different set of functions for in0 */ -static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) -{ - long in0; - - if ((data->vrm_ovt & 0x01) && - (w83627thf == data->type || w83637hf == data->type)) - - /* use VRM9 calculation */ - in0 = (long)((reg * 488 + 70000 + 50) / 100); - else - /* use VRM8 (standard) calculation */ - in0 = (long)IN_FROM_REG(reg); - - return sprintf(buf,"%ld\n", in0); -} - -static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return show_in_0(data, buf, data->in[0]); -} - -static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return show_in_0(data, buf, data->in_min[0]); -} - -static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return show_in_0(data, buf, data->in_max[0]); -} - -static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - if ((data->vrm_ovt & 0x01) && - (w83627thf == data->type || w83637hf == data->type)) - - /* use VRM9 calculation */ - data->in_min[0] = (u8)(((val * 100) - 70000 + 244) / 488); - else - /* use VRM8 (standard) calculation */ - data->in_min[0] = IN_TO_REG(val); - - w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]); - up(&data->update_lock); - return count; -} - -static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - if ((data->vrm_ovt & 0x01) && - (w83627thf == data->type || w83637hf == data->type)) - - /* use VRM9 calculation */ - data->in_max[0] = (u8)(((val * 100) - 70000 + 244) / 488); - else - /* use VRM8 (standard) calculation */ - data->in_max[0] = IN_TO_REG(val); - - w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]); - up(&data->update_lock); - return count; -} - -static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL); -static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, - show_regs_in_min0, store_regs_in_min0); -static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, - show_regs_in_max0, store_regs_in_max0); - -#define device_create_file_in(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_in##offset##_input); \ -device_create_file(&client->dev, &dev_attr_in##offset##_min); \ -device_create_file(&client->dev, &dev_attr_in##offset##_max); \ -} while (0) - -#define show_fan_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - return sprintf(buf,"%ld\n", \ - FAN_FROM_REG(data->reg[nr-1], \ - (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ -} -show_fan_reg(fan); -show_fan_reg(fan_min); - -static ssize_t -store_fan_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr - 1] = - FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - - up(&data->update_lock); - return count; -} - -#define sysfs_fan_offset(offset) \ -static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); - -#define sysfs_fan_min_offset(offset) \ -static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_fan_min(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_regs_fan_min##offset, store_regs_fan_min##offset); - -sysfs_fan_offset(1); -sysfs_fan_min_offset(1); -sysfs_fan_offset(2); -sysfs_fan_min_offset(2); -sysfs_fan_offset(3); -sysfs_fan_min_offset(3); - -#define device_create_file_fan(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ -device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ -} while (0) - -#define show_temp_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - return sprintf(buf,"%ld\n", \ - (long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ - } else { /* TEMP1 */ \ - return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ - } \ -} -show_temp_reg(temp); -show_temp_reg(temp_max); -show_temp_reg(temp_max_hyst); - -#define store_temp_reg(REG, reg) \ -static ssize_t \ -store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83627hf_data *data = i2c_get_clientdata(client); \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ - w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ - data->temp_##reg##_add[nr-2]); \ - } else { /* TEMP1 */ \ - data->temp_##reg = TEMP_TO_REG(val); \ - w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ - data->temp_##reg); \ - } \ - \ - up(&data->update_lock); \ - return count; \ -} -store_temp_reg(OVER, max); -store_temp_reg(HYST, max_hyst); - -#define sysfs_temp_offset(offset) \ -static ssize_t \ -show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); - -#define sysfs_temp_reg_offset(reg, offset) \ -static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_##reg (dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_temp_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); - -#define sysfs_temp_offsets(offset) \ -sysfs_temp_offset(offset) \ -sysfs_temp_reg_offset(max, offset) \ -sysfs_temp_reg_offset(max_hyst, offset) - -sysfs_temp_offsets(1); -sysfs_temp_offsets(2); -sysfs_temp_offsets(3); - -#define device_create_file_temp(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ -} while (0) - -static ssize_t -show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid) - -static ssize_t -show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->vrm); -} -static ssize_t -store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - data->vrm = val; - - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm) - -static ssize_t -show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->alarms); -} -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); -#define device_create_file_alarms(client) \ -device_create_file(&client->dev, &dev_attr_alarms) - -#define show_beep_reg(REG, reg) \ -static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - return sprintf(buf,"%ld\n", \ - (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \ -} -show_beep_reg(ENABLE, enable) -show_beep_reg(MASK, mask) - -#define BEEP_ENABLE 0 /* Store beep_enable */ -#define BEEP_MASK 1 /* Store beep_mask */ - -static ssize_t -store_beep_reg(struct device *dev, const char *buf, size_t count, - int update_mask) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val, val2; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ - data->beep_mask = BEEP_MASK_TO_REG(val); - w83627hf_write_value(client, W83781D_REG_BEEP_INTS1, - data->beep_mask & 0xff); - w83627hf_write_value(client, W83781D_REG_BEEP_INTS3, - ((data->beep_mask) >> 16) & 0xff); - val2 = (data->beep_mask >> 8) & 0x7f; - } else { /* We are storing beep_enable */ - val2 = - w83627hf_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; - data->beep_enable = BEEP_ENABLE_TO_REG(val); - } - - w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, - val2 | data->beep_enable << 7); - - up(&data->update_lock); - return count; -} - -#define sysfs_beep(REG, reg) \ -static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_beep_##reg(dev, attr, buf); \ -} \ -static ssize_t \ -store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_beep_reg(dev, buf, count, BEEP_##REG); \ -} \ -static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \ - show_regs_beep_##reg, store_regs_beep_##reg); - -sysfs_beep(ENABLE, enable); -sysfs_beep(MASK, mask); - -#define device_create_file_beep(client) \ -do { \ -device_create_file(&client->dev, &dev_attr_beep_enable); \ -device_create_file(&client->dev, &dev_attr_beep_mask); \ -} while (0) - -static ssize_t -show_fan_div_reg(struct device *dev, char *buf, int nr) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", - (long) DIV_FROM_REG(data->fan_div[nr - 1])); -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t -store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - unsigned long min; - u8 reg; - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - - data->fan_div[nr] = DIV_TO_REG(val); - - reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) - & (nr==0 ? 0xcf : 0x3f)) - | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); - w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); - - reg = (w83627hf_read_value(client, W83781D_REG_VBAT) - & ~(1 << (5 + nr))) - | ((data->fan_div[nr] & 0x04) << (3 + nr)); - w83627hf_write_value(client, W83781D_REG_VBAT, reg); - - /* Restore fan_min */ - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); - - up(&data->update_lock); - return count; -} - -#define sysfs_fan_div(offset) \ -static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_fan_div_reg(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_regs_fan_div_##offset, store_regs_fan_div_##offset); - -sysfs_fan_div(1); -sysfs_fan_div(2); -sysfs_fan_div(3); - -#define device_create_file_fan_div(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ -} while (0) - -static ssize_t -show_pwm_reg(struct device *dev, char *buf, int nr) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]); -} - -static ssize_t -store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - if (data->type == w83627thf) { - /* bits 0-3 are reserved in 627THF */ - data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0; - w83627hf_write_value(client, - W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1] | - (w83627hf_read_value(client, - W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); - } else { - data->pwm[nr - 1] = PWM_TO_REG(val); - w83627hf_write_value(client, - W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1]); - } - - up(&data->update_lock); - return count; -} - -#define sysfs_pwm(offset) \ -static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_pwm_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_regs_pwm_##offset, store_regs_pwm_##offset); - -sysfs_pwm(1); -sysfs_pwm(2); -sysfs_pwm(3); - -#define device_create_file_pwm(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_pwm##offset); \ -} while (0) - -static ssize_t -show_sensor_reg(struct device *dev, char *buf, int nr) -{ - struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); -} - -static ssize_t -store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - u32 val, tmp; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - switch (val) { - case 1: /* PII/Celeron diode */ - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - w83627hf_write_value(client, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); - tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); - w83627hf_write_value(client, W83781D_REG_SCFG2, - tmp | BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; - break; - case 2: /* 3904 */ - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - w83627hf_write_value(client, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); - tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); - w83627hf_write_value(client, W83781D_REG_SCFG2, - tmp & ~BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; - break; - case W83781D_DEFAULT_BETA: /* thermistor */ - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - w83627hf_write_value(client, W83781D_REG_SCFG1, - tmp & ~BIT_SCFG1[nr - 1]); - data->sens[nr - 1] = val; - break; - default: - dev_err(&client->dev, - "Invalid sensor type %ld; must be 1, 2, or %d\n", - (long) val, W83781D_DEFAULT_BETA); - break; - } - - up(&data->update_lock); - return count; -} - -#define sysfs_sensor(offset) \ -static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_sensor_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_sensor_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_regs_sensor_##offset, store_regs_sensor_##offset); - -sysfs_sensor(1); -sysfs_sensor(2); -sysfs_sensor(3); - -#define device_create_file_sensor(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_type); \ -} while (0) - - -/* This function is called when: - * w83627hf_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and w83627hf_driver is still present) */ -static int w83627hf_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, w83627hf_detect); -} - -static int w83627hf_find(int sioaddr, int *address) -{ - u16 val; - - REG = sioaddr; - VAL = sioaddr + 1; - - superio_enter(); - val= superio_inb(DEVID); - if(val != W627_DEVID && - val != W627THF_DEVID && - val != W697_DEVID && - val != W637_DEVID) { - superio_exit(); - return -ENODEV; - } - - superio_select(W83627HF_LD_HWM); - val = (superio_inb(WINB_BASE_REG) << 8) | - superio_inb(WINB_BASE_REG + 1); - *address = val & ~(WINB_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - superio_exit(); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - superio_exit(); - return 0; -} - -int w83627hf_detect(struct i2c_adapter *adapter, int address, - int kind) -{ - int val; - struct i2c_client *new_client; - struct w83627hf_data *data; - int err = 0; - const char *client_name = ""; - - if (!i2c_is_isa_adapter(adapter)) { - err = -ENODEV; - goto ERROR0; - } - - if(force_addr) - address = force_addr & ~(WINB_EXTENT - 1); - - if (!request_region(address, WINB_EXTENT, w83627hf_driver.name)) { - err = -EBUSY; - goto ERROR0; - } - - if(force_addr) { - printk("w83627hf.o: forcing ISA address 0x%04X\n", address); - superio_enter(); - superio_select(W83627HF_LD_HWM); - superio_outb(WINB_BASE_REG, address >> 8); - superio_outb(WINB_BASE_REG+1, address & 0xff); - superio_exit(); - } - - superio_enter(); - val= superio_inb(DEVID); - if(val == W627_DEVID) - kind = w83627hf; - else if(val == W697_DEVID) - kind = w83697hf; - else if(val == W627THF_DEVID) - kind = w83627thf; - else if(val == W637_DEVID) - kind = w83637hf; - else { - dev_info(&adapter->dev, - "Unsupported chip (dev_id=0x%02X).\n", val); - goto ERROR1; - } - - superio_select(W83627HF_LD_HWM); - if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0) - superio_outb(WINB_ACT_REG, 1); - superio_exit(); - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access w83627hf_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR1; - } - memset(data, 0, sizeof(struct w83627hf_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->adapter = adapter; - new_client->driver = &w83627hf_driver; - new_client->flags = 0; - - - if (kind == w83627hf) { - client_name = "w83627hf"; - } else if (kind == w83627thf) { - client_name = "w83627thf"; - } else if (kind == w83697hf) { - client_name = "w83697hf"; - } else if (kind == w83637hf) { - client_name = "w83637hf"; - } - - /* Fill in the remaining client fields and put into the global list */ - strlcpy(new_client->name, client_name, I2C_NAME_SIZE); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - data->lm75 = NULL; - - /* Initialize the chip */ - w83627hf_init_client(new_client); - - /* A few vars need to be filled upon startup */ - data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1)); - data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2)); - data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3)); - - /* Register sysfs hooks */ - device_create_file_in(new_client, 0); - if (kind != w83697hf) - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - device_create_file_in(new_client, 4); - if (kind != w83627thf && kind != w83637hf) { - device_create_file_in(new_client, 5); - device_create_file_in(new_client, 6); - } - device_create_file_in(new_client, 7); - device_create_file_in(new_client, 8); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - if (kind != w83697hf) - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - if (kind != w83697hf) - device_create_file_temp(new_client, 3); - - if (kind != w83697hf) - device_create_file_vid(new_client); - - if (kind != w83697hf) - device_create_file_vrm(new_client); - - device_create_file_fan_div(new_client, 1); - device_create_file_fan_div(new_client, 2); - if (kind != w83697hf) - device_create_file_fan_div(new_client, 3); - - device_create_file_alarms(new_client); - - device_create_file_beep(new_client); - - device_create_file_pwm(new_client, 1); - device_create_file_pwm(new_client, 2); - if (kind == w83627thf || kind == w83637hf) - device_create_file_pwm(new_client, 3); - - device_create_file_sensor(new_client, 1); - device_create_file_sensor(new_client, 2); - if (kind != w83697hf) - device_create_file_sensor(new_client, 3); - - return 0; - - ERROR2: - kfree(data); - ERROR1: - release_region(address, WINB_EXTENT); - ERROR0: - return err; -} - -static int w83627hf_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, WINB_EXTENT); - kfree(i2c_get_clientdata(client)); - - return 0; -} - - -/* - ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int w83627hf_read_value(struct i2c_client *client, u16 reg) -{ - struct w83627hf_data *data = i2c_get_clientdata(client); - int res, word_sized; - - down(&data->lock); - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x50) - || ((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - res = - (res << 8) + inb_p(client->addr + - W83781D_DATA_REG_OFFSET); - } - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - up(&data->lock); - return res; -} - -static int w83627thf_read_gpio5(struct i2c_client *client) -{ - int res = 0xff, sel; - - superio_enter(); - superio_select(W83627HF_LD_GPIO5); - - /* Make sure these GPIO pins are enabled */ - if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) { - dev_dbg(&client->dev, "GPIO5 disabled, no VID function\n"); - goto exit; - } - - /* Make sure the pins are configured for input - There must be at least five (VRM 9), and possibly 6 (VRM 10) */ - sel = superio_inb(W83627THF_GPIO5_IOSR); - if ((sel & 0x1f) != 0x1f) { - dev_dbg(&client->dev, "GPIO5 not configured for VID " - "function\n"); - goto exit; - } - - dev_info(&client->dev, "Reading VID from GPIO5\n"); - res = superio_inb(W83627THF_GPIO5_DR) & sel; - -exit: - superio_exit(); - return res; -} - -static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - struct w83627hf_data *data = i2c_get_clientdata(client); - int word_sized; - - down(&data->lock); - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - } - outb_p(value & 0xff, - client->addr + W83781D_DATA_REG_OFFSET); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - up(&data->lock); - return 0; -} - -/* Called when we have found a new W83781D. It should set limits, etc. */ -static void w83627hf_init_client(struct i2c_client *client) -{ - struct w83627hf_data *data = i2c_get_clientdata(client); - int i; - int type = data->type; - u8 tmp; - - if(init) { - /* save this register */ - i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG); - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ - w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80); - /* Restore the register and disable power-on abnormal beep. - This saves FAN 1/2/3 input/output values set by BIOS. */ - w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); - /* Disable master beep-enable (reset turns it on). - Individual beeps should be reset to off but for some reason - disabling this bit helps some people not get beeped */ - w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0); - } - - /* Minimize conflicts with other winbond i2c-only clients... */ - /* disable i2c subclients... how to disable main i2c client?? */ - /* force i2c address to relatively uncommon address */ - w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89); - w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c); - - /* Read VID only once */ - if (w83627hf == data->type || w83637hf == data->type) { - int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - int hi = w83627hf_read_value(client, W83781D_REG_CHIPID); - data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); - } else if (w83627thf == data->type) { - data->vid = w83627thf_read_gpio5(client) & 0x3f; - } - - /* Read VRM & OVT Config only once */ - if (w83627thf == data->type || w83637hf == data->type) { - data->vrm_ovt = - w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); - data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82; - } else { - /* Convert VID to voltage based on default VRM */ - data->vrm = i2c_which_vrm(); - } - - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - for (i = 1; i <= 3; i++) { - if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; - } else { - if (w83627hf_read_value - (client, - W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) - data->sens[i - 1] = 1; - else - data->sens[i - 1] = 2; - } - if ((type == w83697hf) && (i == 2)) - break; - } - - if(init) { - /* Enable temp2 */ - tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG); - if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp2, readings " - "might not make sense\n"); - w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG, - tmp & 0xfe); - } - - /* Enable temp3 */ - if (type != w83697hf) { - tmp = w83627hf_read_value(client, - W83781D_REG_TEMP3_CONFIG); - if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp3, " - "readings might not make sense\n"); - w83627hf_write_value(client, - W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); - } - } - - if (type == w83627hf) { - /* enable PWM2 control (can't hurt since PWM reg - should have been reset to 0xff) */ - w83627hf_write_value(client, W83627HF_REG_PWMCLK12, - 0x19); - } - /* enable comparator mode for temp2 and temp3 so - alarm indication will work correctly */ - i = w83627hf_read_value(client, W83781D_REG_IRQ); - if (!(i & 0x40)) - w83627hf_write_value(client, W83781D_REG_IRQ, - i | 0x40); - } - - /* Start monitoring */ - w83627hf_write_value(client, W83781D_REG_CONFIG, - (w83627hf_read_value(client, - W83781D_REG_CONFIG) & 0xf7) - | 0x01); -} - -static struct w83627hf_data *w83627hf_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83627hf_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - for (i = 0; i <= 8; i++) { - /* skip missing sensors */ - if (((data->type == w83697hf) && (i == 1)) || - ((data->type == w83627thf || data->type == w83637hf) - && (i == 4 || i == 5))) - continue; - data->in[i] = - w83627hf_read_value(client, W83781D_REG_IN(i)); - data->in_min[i] = - w83627hf_read_value(client, - W83781D_REG_IN_MIN(i)); - data->in_max[i] = - w83627hf_read_value(client, - W83781D_REG_IN_MAX(i)); - } - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = - w83627hf_read_value(client, W83781D_REG_FAN(i)); - data->fan_min[i - 1] = - w83627hf_read_value(client, - W83781D_REG_FAN_MIN(i)); - } - for (i = 1; i <= 3; i++) { - u8 tmp = w83627hf_read_value(client, - W836X7HF_REG_PWM(data->type, i)); - /* bits 0-3 are reserved in 627THF */ - if (data->type == w83627thf) - tmp &= 0xf0; - data->pwm[i - 1] = tmp; - if(i == 2 && - (data->type == w83627hf || data->type == w83697hf)) - break; - } - - data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1)); - data->temp_max = - w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1)); - data->temp_max_hyst = - w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1)); - data->temp_add[0] = - w83627hf_read_value(client, W83781D_REG_TEMP(2)); - data->temp_max_add[0] = - w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2)); - data->temp_max_hyst_add[0] = - w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2)); - if (data->type != w83697hf) { - data->temp_add[1] = - w83627hf_read_value(client, W83781D_REG_TEMP(3)); - data->temp_max_add[1] = - w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3)); - data->temp_max_hyst_add[1] = - w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3)); - } - - i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - if (data->type != w83697hf) { - data->fan_div[2] = (w83627hf_read_value(client, - W83781D_REG_PIN) >> 6) & 0x03; - } - i = w83627hf_read_value(client, W83781D_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - if (data->type != w83697hf) - data->fan_div[2] |= (i >> 5) & 0x04; - data->alarms = - w83627hf_read_value(client, W83781D_REG_ALARM1) | - (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) | - (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16); - i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2); - data->beep_enable = i >> 7; - data->beep_mask = ((i & 0x7f) << 8) | - w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) | - w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_w83627hf_init(void) -{ - int addr; - - if (w83627hf_find(0x2e, &addr) - && w83627hf_find(0x4e, &addr)) { - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&w83627hf_driver); -} - -static void __exit sensors_w83627hf_exit(void) -{ - i2c_del_driver(&w83627hf_driver); -} - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "and Mark Studebaker "); -MODULE_DESCRIPTION("W83627HF driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_w83627hf_init); -module_exit(sensors_w83627hf_exit); diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c deleted file mode 100644 index 0bb131ce09e..00000000000 --- a/drivers/i2c/chips/w83781d.c +++ /dev/null @@ -1,1632 +0,0 @@ -/* - w83781d.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2001 Frodo Looijaard , - Philip Edelbrock , - and Mark Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - as99127f 7 3 0 3 0x31 0x12c3 yes no - as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no - w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes - w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) - w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes - w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "lm75.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, - 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f); -I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: " - "{bus, clientaddr, subclientaddr1, subclientaddr2}"); - -static int init = 1; -module_param(init, bool, 0); -MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); - -/* Constants specified below */ - -/* Length of ISA address segment */ -#define W83781D_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define W83781D_ADDR_REG_OFFSET 5 -#define W83781D_DATA_REG_OFFSET 6 - -/* The W83781D registers */ -/* The W83782D registers for nr=7,8 are in bank 5 */ -#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ - (0x554 + (((nr) - 7) * 2))) -#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ - (0x555 + (((nr) - 7) * 2))) -#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ - (0x550 + (nr) - 7)) - -#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) -#define W83781D_REG_FAN(nr) (0x27 + (nr)) - -#define W83781D_REG_BANK 0x4E -#define W83781D_REG_TEMP2_CONFIG 0x152 -#define W83781D_REG_TEMP3_CONFIG 0x252 -#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ - ((nr == 2) ? (0x0150) : \ - (0x27))) -#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \ - ((nr == 2) ? (0x153) : \ - (0x3A))) -#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \ - ((nr == 2) ? (0x155) : \ - (0x39))) - -#define W83781D_REG_CONFIG 0x40 -#define W83781D_REG_ALARM1 0x41 -#define W83781D_REG_ALARM2 0x42 -#define W83781D_REG_ALARM3 0x450 /* not on W83781D */ - -#define W83781D_REG_IRQ 0x4C -#define W83781D_REG_BEEP_CONFIG 0x4D -#define W83781D_REG_BEEP_INTS1 0x56 -#define W83781D_REG_BEEP_INTS2 0x57 -#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */ - -#define W83781D_REG_VID_FANDIV 0x47 - -#define W83781D_REG_CHIPID 0x49 -#define W83781D_REG_WCHIPID 0x58 -#define W83781D_REG_CHIPMAN 0x4F -#define W83781D_REG_PIN 0x4B - -/* 782D/783S only */ -#define W83781D_REG_VBAT 0x5D - -/* PWM 782D (1-4) and 783S (1-2) only */ -#define W83781D_REG_PWM1 0x5B /* 782d and 783s/627hf datasheets disagree */ - /* on which is which; */ -#define W83781D_REG_PWM2 0x5A /* We follow the 782d convention here, */ - /* However 782d is probably wrong. */ -#define W83781D_REG_PWM3 0x5E -#define W83781D_REG_PWM4 0x5F -#define W83781D_REG_PWMCLK12 0x5C -#define W83781D_REG_PWMCLK34 0x45C -static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2, - W83781D_REG_PWM3, W83781D_REG_PWM4 -}; - -#define W83781D_REG_PWM(nr) (regpwm[(nr) - 1]) - -#define W83781D_REG_I2C_ADDR 0x48 -#define W83781D_REG_I2C_SUBADDR 0x4A - -/* The following are undocumented in the data sheets however we - received the information in an email from Winbond tech support */ -/* Sensor selection - not on 781d */ -#define W83781D_REG_SCFG1 0x5D -static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; - -#define W83781D_REG_SCFG2 0x59 -static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; - -#define W83781D_DEFAULT_BETA 3435 - -/* RT Table registers */ -#define W83781D_REG_RT_IDX 0x50 -#define W83781D_REG_RT_VAL 0x51 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16) / 10) - -static inline u8 -FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); -} - -#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ - ((val) == 255 ? 0 : \ - 1350000 / ((val) * (div)))) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ - : (val)) / 1000, 0, 0xff)) -#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) - -#define PWM_FROM_REG(val) (val) -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) -#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \ - (val) ^ 0x7fff : (val)) -#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \ - (~(val)) & 0x7fff : (val) & 0xffffff) - -#define BEEP_ENABLE_TO_REG(val) ((val) ? 1 : 0) -#define BEEP_ENABLE_FROM_REG(val) ((val) ? 1 : 0) - -#define DIV_FROM_REG(val) (1 << (val)) - -static inline u8 -DIV_TO_REG(long val, enum chips type) -{ - int i; - val = SENSORS_LIMIT(val, 1, - ((type == w83781d - || type == as99127f) ? 8 : 128)) >> 1; - for (i = 0; i < 7; i++) { - if (val == 0) - break; - val >>= 1; - } - return ((u8) i); -} - -/* There are some complications in a module like this. First off, W83781D chips - may be both present on the SMBus and the ISA bus, and we have to handle - those cases separately at some places. Second, there might be several - W83781D chips available (well, actually, that is probably never done; but - it is a clean illustration of how to handle a case like that). Finally, - a specific chip may be attached to *both* ISA and SMBus, and we would - not like to detect it double. Fortunately, in the case of the W83781D at - least, a register tells us what SMBus address we are on, so that helps - a bit - except if there could be more than one SMBus. Groan. No solution - for this yet. */ - -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* For each registered W83781D, we need to keep some data in memory. That - data is pointed to by w83781d_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new w83781d client is - allocated. */ -struct w83781d_data { - struct i2c_client client; - struct semaphore lock; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - struct i2c_client *lm75[2]; /* for secondary I2C addresses */ - /* array of 2 pointers to subclients */ - - u8 in[9]; /* Register value - 8 & 9 for 782D only */ - u8 in_max[9]; /* Register value - 8 & 9 for 782D only */ - u8 in_min[9]; /* Register value - 8 & 9 for 782D only */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp; - u8 temp_max; /* Register value */ - u8 temp_max_hyst; /* Register value */ - u16 temp_add[2]; /* Register value */ - u16 temp_max_add[2]; /* Register value */ - u16 temp_max_hyst_add[2]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u32 beep_mask; /* Register encoding, combined */ - u8 beep_enable; /* Boolean */ - u8 pwm[4]; /* Register value */ - u8 pwmenable[4]; /* Boolean */ - u16 sens[3]; /* 782D/783S only. - 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ - u8 vrm; -}; - -static int w83781d_attach_adapter(struct i2c_adapter *adapter); -static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind); -static int w83781d_detach_client(struct i2c_client *client); - -static int w83781d_read_value(struct i2c_client *client, u16 register); -static int w83781d_write_value(struct i2c_client *client, u16 register, - u16 value); -static struct w83781d_data *w83781d_update_device(struct device *dev); -static void w83781d_init_client(struct i2c_client *client); - -static struct i2c_driver w83781d_driver = { - .owner = THIS_MODULE, - .name = "w83781d", - .id = I2C_DRIVERID_W83781D, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83781d_attach_adapter, - .detach_client = w83781d_detach_client, -}; - -/* following are the sysfs callback functions */ -#define show_in_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83781d_data *data = w83781d_update_device(dev); \ - return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr] * 10)); \ -} -show_in_reg(in); -show_in_reg(in_min); -show_in_reg(in_max); - -#define store_in_reg(REG, reg) \ -static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83781d_data *data = i2c_get_clientdata(client); \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10) / 10; \ - \ - down(&data->update_lock); \ - data->in_##reg[nr] = IN_TO_REG(val); \ - w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \ - \ - up(&data->update_lock); \ - return count; \ -} -store_in_reg(MIN, min); -store_in_reg(MAX, max); - -#define sysfs_in_offset(offset) \ -static ssize_t \ -show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); - -#define sysfs_in_reg_offset(reg, offset) \ -static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_##reg (dev, buf, offset); \ -} \ -static ssize_t store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_in_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset); - -#define sysfs_in_offsets(offset) \ -sysfs_in_offset(offset); \ -sysfs_in_reg_offset(min, offset); \ -sysfs_in_reg_offset(max, offset); - -sysfs_in_offsets(0); -sysfs_in_offsets(1); -sysfs_in_offsets(2); -sysfs_in_offsets(3); -sysfs_in_offsets(4); -sysfs_in_offsets(5); -sysfs_in_offsets(6); -sysfs_in_offsets(7); -sysfs_in_offsets(8); - -#define device_create_file_in(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_in##offset##_input); \ -device_create_file(&client->dev, &dev_attr_in##offset##_min); \ -device_create_file(&client->dev, &dev_attr_in##offset##_max); \ -} while (0) - -#define show_fan_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83781d_data *data = w83781d_update_device(dev); \ - return sprintf(buf,"%ld\n", \ - FAN_FROM_REG(data->reg[nr-1], (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ -} -show_fan_reg(fan); -show_fan_reg(fan_min); - -static ssize_t -store_fan_min(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->fan_min[nr - 1] = - FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - - up(&data->update_lock); - return count; -} - -#define sysfs_fan_offset(offset) \ -static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); - -#define sysfs_fan_min_offset(offset) \ -static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset); \ -} \ -static ssize_t store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_fan_min(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset); - -sysfs_fan_offset(1); -sysfs_fan_min_offset(1); -sysfs_fan_offset(2); -sysfs_fan_min_offset(2); -sysfs_fan_offset(3); -sysfs_fan_min_offset(3); - -#define device_create_file_fan(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ -device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ -} while (0) - -#define show_temp_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83781d_data *data = w83781d_update_device(dev); \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - return sprintf(buf,"%d\n", \ - LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ - } else { /* TEMP1 */ \ - return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ - } \ -} -show_temp_reg(temp); -show_temp_reg(temp_max); -show_temp_reg(temp_max_hyst); - -#define store_temp_reg(REG, reg) \ -static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct w83781d_data *data = i2c_get_clientdata(client); \ - s32 val; \ - \ - val = simple_strtol(buf, NULL, 10); \ - \ - down(&data->update_lock); \ - \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ - w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \ - data->temp_##reg##_add[nr-2]); \ - } else { /* TEMP1 */ \ - data->temp_##reg = TEMP_TO_REG(val); \ - w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \ - data->temp_##reg); \ - } \ - \ - up(&data->update_lock); \ - return count; \ -} -store_temp_reg(OVER, max); -store_temp_reg(HYST, max_hyst); - -#define sysfs_temp_offset(offset) \ -static ssize_t \ -show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); - -#define sysfs_temp_reg_offset(reg, offset) \ -static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_##reg (dev, buf, offset); \ -} \ -static ssize_t store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_temp_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); - -#define sysfs_temp_offsets(offset) \ -sysfs_temp_offset(offset); \ -sysfs_temp_reg_offset(max, offset); \ -sysfs_temp_reg_offset(max_hyst, offset); - -sysfs_temp_offsets(1); -sysfs_temp_offsets(2); -sysfs_temp_offsets(3); - -#define device_create_file_temp(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ -} while (0) - -static ssize_t -show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); -} - -static -DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid); -static ssize_t -show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->vrm); -} - -static ssize_t -store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - data->vrm = val; - - return count; -} - -static -DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm); -static ssize_t -show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%u\n", data->alarms); -} - -static -DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); -#define device_create_file_alarms(client) \ -device_create_file(&client->dev, &dev_attr_alarms); -static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", - (long)BEEP_MASK_FROM_REG(data->beep_mask, data->type)); -} -static ssize_t show_beep_enable (struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", - (long)BEEP_ENABLE_FROM_REG(data->beep_enable)); -} - -#define BEEP_ENABLE 0 /* Store beep_enable */ -#define BEEP_MASK 1 /* Store beep_mask */ - -static ssize_t -store_beep_reg(struct device *dev, const char *buf, size_t count, - int update_mask) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val, val2; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ - data->beep_mask = BEEP_MASK_TO_REG(val, data->type); - w83781d_write_value(client, W83781D_REG_BEEP_INTS1, - data->beep_mask & 0xff); - - if ((data->type != w83781d) && (data->type != as99127f)) { - w83781d_write_value(client, W83781D_REG_BEEP_INTS3, - ((data->beep_mask) >> 16) & 0xff); - } - - val2 = (data->beep_mask >> 8) & 0x7f; - } else { /* We are storing beep_enable */ - val2 = w83781d_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; - data->beep_enable = BEEP_ENABLE_TO_REG(val); - } - - w83781d_write_value(client, W83781D_REG_BEEP_INTS2, - val2 | data->beep_enable << 7); - - up(&data->update_lock); - return count; -} - -#define sysfs_beep(REG, reg) \ -static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_beep_##reg(dev, attr, buf); \ -} \ -static ssize_t store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_beep_reg(dev, buf, count, BEEP_##REG); \ -} \ -static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg); - -sysfs_beep(ENABLE, enable); -sysfs_beep(MASK, mask); - -#define device_create_file_beep(client) \ -do { \ -device_create_file(&client->dev, &dev_attr_beep_enable); \ -device_create_file(&client->dev, &dev_attr_beep_mask); \ -} while (0) - -static ssize_t -show_fan_div_reg(struct device *dev, char *buf, int nr) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", - (long) DIV_FROM_REG(data->fan_div[nr - 1])); -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ -static ssize_t -store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - unsigned long min; - u8 reg; - unsigned long val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - /* Save fan_min */ - min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - - data->fan_div[nr] = DIV_TO_REG(val, data->type); - - reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) - & (nr==0 ? 0xcf : 0x3f)) - | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); - w83781d_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); - - /* w83781d and as99127f don't have extended divisor bits */ - if (data->type != w83781d && data->type != as99127f) { - reg = (w83781d_read_value(client, W83781D_REG_VBAT) - & ~(1 << (5 + nr))) - | ((data->fan_div[nr] & 0x04) << (3 + nr)); - w83781d_write_value(client, W83781D_REG_VBAT, reg); - } - - /* Restore fan_min */ - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); - - up(&data->update_lock); - return count; -} - -#define sysfs_fan_div(offset) \ -static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_fan_div_reg(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset); - -sysfs_fan_div(1); -sysfs_fan_div(2); -sysfs_fan_div(3); - -#define device_create_file_fan_div(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ -} while (0) - -static ssize_t -show_pwm_reg(struct device *dev, char *buf, int nr) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr - 1])); -} - -static ssize_t -show_pwmenable_reg(struct device *dev, char *buf, int nr) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->pwmenable[nr - 1]); -} - -static ssize_t -store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - data->pwm[nr - 1] = PWM_TO_REG(val); - w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]); - up(&data->update_lock); - return count; -} - -static ssize_t -store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val, reg; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - switch (val) { - case 0: - case 1: - reg = w83781d_read_value(client, W83781D_REG_PWMCLK12); - w83781d_write_value(client, W83781D_REG_PWMCLK12, - (reg & 0xf7) | (val << 3)); - - reg = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); - w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, - (reg & 0xef) | (!val << 4)); - - data->pwmenable[nr - 1] = val; - break; - - default: - up(&data->update_lock); - return -EINVAL; - } - - up(&data->update_lock); - return count; -} - -#define sysfs_pwm(offset) \ -static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_pwm_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_regs_pwm_##offset, store_regs_pwm_##offset); - -#define sysfs_pwmenable(offset) \ -static ssize_t show_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwmenable_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_pwmenable_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - show_regs_pwmenable_##offset, store_regs_pwmenable_##offset); - -sysfs_pwm(1); -sysfs_pwm(2); -sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */ -sysfs_pwm(3); -sysfs_pwm(4); - -#define device_create_file_pwm(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_pwm##offset); \ -} while (0) - -#define device_create_file_pwmenable(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_pwm##offset##_enable); \ -} while (0) - -static ssize_t -show_sensor_reg(struct device *dev, char *buf, int nr) -{ - struct w83781d_data *data = w83781d_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); -} - -static ssize_t -store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - u32 val, tmp; - - val = simple_strtoul(buf, NULL, 10); - - down(&data->update_lock); - - switch (val) { - case 1: /* PII/Celeron diode */ - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - w83781d_write_value(client, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); - tmp = w83781d_read_value(client, W83781D_REG_SCFG2); - w83781d_write_value(client, W83781D_REG_SCFG2, - tmp | BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; - break; - case 2: /* 3904 */ - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - w83781d_write_value(client, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); - tmp = w83781d_read_value(client, W83781D_REG_SCFG2); - w83781d_write_value(client, W83781D_REG_SCFG2, - tmp & ~BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; - break; - case W83781D_DEFAULT_BETA: /* thermistor */ - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - w83781d_write_value(client, W83781D_REG_SCFG1, - tmp & ~BIT_SCFG1[nr - 1]); - data->sens[nr - 1] = val; - break; - default: - dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n", - (long) val, W83781D_DEFAULT_BETA); - break; - } - - up(&data->update_lock); - return count; -} - -#define sysfs_sensor(offset) \ -static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_sensor_reg(dev, buf, offset); \ -} \ -static ssize_t store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_sensor_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset); - -sysfs_sensor(1); -sysfs_sensor(2); -sysfs_sensor(3); - -#define device_create_file_sensor(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_type); \ -} while (0) - -/* This function is called when: - * w83781d_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and w83781d_driver is still present) */ -static int -w83781d_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, w83781d_detect); -} - -/* Assumes that adapter is of I2C, not ISA variety. - * OTHERWISE DON'T CALL THIS - */ -static int -w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, - struct i2c_client *new_client) -{ - int i, val1 = 0, id; - int err; - const char *client_name = ""; - struct w83781d_data *data = i2c_get_clientdata(new_client); - - data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[0])) { - err = -ENOMEM; - goto ERROR_SC_0; - } - memset(data->lm75[0], 0x00, sizeof (struct i2c_client)); - - id = i2c_adapter_id(adapter); - - if (force_subclients[0] == id && force_subclients[1] == address) { - for (i = 2; i <= 3; i++) { - if (force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - dev_err(&new_client->dev, "Invalid subclient " - "address %d; must be 0x48-0x4f\n", - force_subclients[i]); - err = -EINVAL; - goto ERROR_SC_1; - } - } - w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) << 4)); - data->lm75[0]->addr = force_subclients[2]; - } else { - val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR); - data->lm75[0]->addr = 0x48 + (val1 & 0x07); - } - - if (kind != w83783s) { - - data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[1])) { - err = -ENOMEM; - goto ERROR_SC_1; - } - memset(data->lm75[1], 0x0, sizeof(struct i2c_client)); - - if (force_subclients[0] == id && - force_subclients[1] == address) { - data->lm75[1]->addr = force_subclients[3]; - } else { - data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07); - } - if (data->lm75[0]->addr == data->lm75[1]->addr) { - dev_err(&new_client->dev, - "Duplicate addresses 0x%x for subclients.\n", - data->lm75[0]->addr); - err = -EBUSY; - goto ERROR_SC_2; - } - } - - if (kind == w83781d) - client_name = "w83781d subclient"; - else if (kind == w83782d) - client_name = "w83782d subclient"; - else if (kind == w83783s) - client_name = "w83783s subclient"; - else if (kind == w83627hf) - client_name = "w83627hf subclient"; - else if (kind == as99127f) - client_name = "as99127f subclient"; - - for (i = 0; i <= 1; i++) { - /* store all data in w83781d */ - i2c_set_clientdata(data->lm75[i], NULL); - data->lm75[i]->adapter = adapter; - data->lm75[i]->driver = &w83781d_driver; - data->lm75[i]->flags = 0; - strlcpy(data->lm75[i]->name, client_name, - I2C_NAME_SIZE); - if ((err = i2c_attach_client(data->lm75[i]))) { - dev_err(&new_client->dev, "Subclient %d " - "registration at address 0x%x " - "failed.\n", i, data->lm75[i]->addr); - if (i == 1) - goto ERROR_SC_3; - goto ERROR_SC_2; - } - if (kind == w83783s) - break; - } - - return 0; - -/* Undo inits in case of errors */ -ERROR_SC_3: - i2c_detach_client(data->lm75[0]); -ERROR_SC_2: - if (NULL != data->lm75[1]) - kfree(data->lm75[1]); -ERROR_SC_1: - if (NULL != data->lm75[0]) - kfree(data->lm75[0]); -ERROR_SC_0: - return err; -} - -static int -w83781d_detect(struct i2c_adapter *adapter, int address, int kind) -{ - int i = 0, val1 = 0, val2; - struct i2c_client *new_client; - struct w83781d_data *data; - int err; - const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - enum vendor { winbond, asus } vendid; - - if (!is_isa - && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - err = -EINVAL; - goto ERROR0; - } - - /* Prevent users from forcing a kind for a bus it isn't supposed - to possibly be on */ - if (is_isa && (kind == as99127f || kind == w83783s)) { - dev_err(&adapter->dev, - "Cannot force I2C-only chip for ISA address 0x%02x.\n", - address); - err = -EINVAL; - goto ERROR0; - } - - if (is_isa) - if (!request_region(address, W83781D_EXTENT, - w83781d_driver.name)) { - dev_dbg(&adapter->dev, "Request of region " - "0x%x-0x%x for w83781d failed\n", address, - address + W83781D_EXTENT - 1); - err = -EBUSY; - goto ERROR0; - } - - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (kind < 0) { - if (is_isa) { - -#define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like - chips. But only if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i - || inb_p(address + 3) != i - || inb_p(address + 7) != i) { - dev_dbg(&adapter->dev, "Detection of w83781d " - "chip failed at step 1\n"); - err = -ENODEV; - goto ERROR1; - } -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - val2 = inb_p(address + 5) & 0x7f; - if (val2 != (~i & 0x7f)) { - outb_p(i, address + 5); - dev_dbg(&adapter->dev, "Detection of w83781d " - "chip failed at step 2 (0x%x != " - "0x%x at 0x%x)\n", val2, ~i & 0x7f, - address + 5); - err = -ENODEV; - goto ERROR1; - } - } - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access w83781d_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR1; - } - memset(data, 0, sizeof(struct w83781d_data)); - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->adapter = adapter; - new_client->driver = &w83781d_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - /* The w8378?d may be stuck in some other bank than bank 0. This may - make reading other information impossible. Specify a force=... or - force_*=... parameter, and the Winbond will be reset to the right - bank. */ - if (kind < 0) { - if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) { - dev_dbg(&new_client->dev, "Detection failed at step " - "3\n"); - err = -ENODEV; - goto ERROR2; - } - val1 = w83781d_read_value(new_client, W83781D_REG_BANK); - val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); - /* Check for Winbond or Asus ID if in bank 0 */ - if ((!(val1 & 0x07)) && - (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)) - || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) { - dev_dbg(&new_client->dev, "Detection failed at step " - "4\n"); - err = -ENODEV; - goto ERROR2; - } - /* If Winbond SMBus, check address at 0x48. - Asus doesn't support, except for as99127f rev.2 */ - if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || - ((val1 & 0x80) && (val2 == 0x5c)))) { - if (w83781d_read_value - (new_client, W83781D_REG_I2C_ADDR) != address) { - dev_dbg(&new_client->dev, "Detection failed " - "at step 5\n"); - err = -ENODEV; - goto ERROR2; - } - } - } - - /* We have either had a force parameter, or we have already detected the - Winbond. Put it now into bank 0 and Vendor ID High Byte */ - w83781d_write_value(new_client, W83781D_REG_BANK, - (w83781d_read_value(new_client, - W83781D_REG_BANK) & 0x78) | - 0x80); - - /* Determine the chip type. */ - if (kind <= 0) { - /* get vendor ID */ - val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); - if (val2 == 0x5c) - vendid = winbond; - else if (val2 == 0x12) - vendid = asus; - else { - dev_dbg(&new_client->dev, "Chip was made by neither " - "Winbond nor Asus?\n"); - err = -ENODEV; - goto ERROR2; - } - - val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID); - if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond) - kind = w83781d; - else if (val1 == 0x30 && vendid == winbond) - kind = w83782d; - else if (val1 == 0x40 && vendid == winbond && !is_isa - && address == 0x2d) - kind = w83783s; - else if (val1 == 0x21 && vendid == winbond) - kind = w83627hf; - else if (val1 == 0x31 && !is_isa && address >= 0x28) - kind = as99127f; - else { - if (kind == 0) - dev_warn(&new_client->dev, "Ignoring 'force' " - "parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - err = -EINVAL; - goto ERROR2; - } - } - - if (kind == w83781d) { - client_name = "w83781d"; - } else if (kind == w83782d) { - client_name = "w83782d"; - } else if (kind == w83783s) { - client_name = "w83783s"; - } else if (kind == w83627hf) { - client_name = "w83627hf"; - } else if (kind == as99127f) { - client_name = "as99127f"; - } - - /* Fill in the remaining client fields and put into the global list */ - strlcpy(new_client->name, client_name, I2C_NAME_SIZE); - data->type = kind; - - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - /* attach secondary i2c lm75-like clients */ - if (!is_isa) { - if ((err = w83781d_detect_subclients(adapter, address, - kind, new_client))) - goto ERROR3; - } else { - data->lm75[0] = NULL; - data->lm75[1] = NULL; - } - - /* Initialize the chip */ - w83781d_init_client(new_client); - - /* A few vars need to be filled upon startup */ - for (i = 1; i <= 3; i++) { - data->fan_min[i - 1] = w83781d_read_value(new_client, - W83781D_REG_FAN_MIN(i)); - } - if (kind != w83781d && kind != as99127f) - for (i = 0; i < 4; i++) - data->pwmenable[i] = 1; - - /* Register sysfs hooks */ - device_create_file_in(new_client, 0); - if (kind != w83783s) - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - device_create_file_in(new_client, 4); - device_create_file_in(new_client, 5); - device_create_file_in(new_client, 6); - if (kind != as99127f && kind != w83781d && kind != w83783s) { - device_create_file_in(new_client, 7); - device_create_file_in(new_client, 8); - } - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - if (kind != w83783s) - device_create_file_temp(new_client, 3); - - device_create_file_vid(new_client); - device_create_file_vrm(new_client); - - device_create_file_fan_div(new_client, 1); - device_create_file_fan_div(new_client, 2); - device_create_file_fan_div(new_client, 3); - - device_create_file_alarms(new_client); - - device_create_file_beep(new_client); - - if (kind != w83781d && kind != as99127f) { - device_create_file_pwm(new_client, 1); - device_create_file_pwm(new_client, 2); - device_create_file_pwmenable(new_client, 2); - } - if (kind == w83782d && !is_isa) { - device_create_file_pwm(new_client, 3); - device_create_file_pwm(new_client, 4); - } - - if (kind != as99127f && kind != w83781d) { - device_create_file_sensor(new_client, 1); - device_create_file_sensor(new_client, 2); - if (kind != w83783s) - device_create_file_sensor(new_client, 3); - } - - return 0; - -ERROR3: - i2c_detach_client(new_client); -ERROR2: - kfree(data); -ERROR1: - if (is_isa) - release_region(address, W83781D_EXTENT); -ERROR0: - return err; -} - -static int -w83781d_detach_client(struct i2c_client *client) -{ - int err; - - if (i2c_is_isa_client(client)) - release_region(client->addr, W83781D_EXTENT); - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - - if (i2c_get_clientdata(client)==NULL) { - /* subclients */ - kfree(client); - } else { - /* main client */ - kfree(i2c_get_clientdata(client)); - } - - return 0; -} - -/* The SMBus locks itself, usually, but nothing may access the Winbond between - bank switches. ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int -w83781d_read_value(struct i2c_client *client, u16 reg) -{ - struct w83781d_data *data = i2c_get_clientdata(client); - int res, word_sized, bank; - struct i2c_client *cl; - - down(&data->lock); - if (i2c_is_isa_client(client)) { - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x50) - || ((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - res = - (res << 8) + inb_p(client->addr + - W83781D_DATA_REG_OFFSET); - } - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - } else { - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - bank); - if (bank == 0 || bank > 2) { - res = i2c_smbus_read_byte_data(client, reg & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x50: /* TEMP */ - res = swab16(i2c_smbus_read_word_data(cl, 0)); - break; - case 0x52: /* CONFIG */ - res = i2c_smbus_read_byte_data(cl, 1); - break; - case 0x53: /* HYST */ - res = swab16(i2c_smbus_read_word_data(cl, 2)); - break; - case 0x55: /* OVER */ - default: - res = swab16(i2c_smbus_read_word_data(cl, 3)); - break; - } - } - if (bank > 2) - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); - } - up(&data->lock); - return res; -} - -static int -w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - struct w83781d_data *data = i2c_get_clientdata(client); - int word_sized, bank; - struct i2c_client *cl; - - down(&data->lock); - if (i2c_is_isa_client(client)) { - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - } - outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - } else { - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - bank); - if (bank == 0 || bank > 2) { - i2c_smbus_write_byte_data(client, reg & 0xff, - value & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x52: /* CONFIG */ - i2c_smbus_write_byte_data(cl, 1, value & 0xff); - break; - case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, swab16(value)); - break; - case 0x55: /* OVER */ - i2c_smbus_write_word_data(cl, 3, swab16(value)); - break; - } - } - if (bank > 2) - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); - } - up(&data->lock); - return 0; -} - -/* Called when we have found a new W83781D. It should set limits, etc. */ -static void -w83781d_init_client(struct i2c_client *client) -{ - struct w83781d_data *data = i2c_get_clientdata(client); - int i, p; - int type = data->type; - u8 tmp; - - if (init && type != as99127f) { /* this resets registers we don't have - documentation for on the as99127f */ - /* save these registers */ - i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); - p = w83781d_read_value(client, W83781D_REG_PWMCLK12); - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ - w83781d_write_value(client, W83781D_REG_CONFIG, 0x80); - /* Restore the registers and disable power-on abnormal beep. - This saves FAN 1/2/3 input/output values set by BIOS. */ - w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); - w83781d_write_value(client, W83781D_REG_PWMCLK12, p); - /* Disable master beep-enable (reset turns it on). - Individual beep_mask should be reset to off but for some reason - disabling this bit helps some people not get beeped */ - w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); - } - - data->vrm = i2c_which_vrm(); - - if ((type != w83781d) && (type != as99127f)) { - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - for (i = 1; i <= 3; i++) { - if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; - } else { - if (w83781d_read_value - (client, - W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) - data->sens[i - 1] = 1; - else - data->sens[i - 1] = 2; - } - if (type == w83783s && i == 2) - break; - } - } - - if (init && type != as99127f) { - /* Enable temp2 */ - tmp = w83781d_read_value(client, W83781D_REG_TEMP2_CONFIG); - if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp2, readings " - "might not make sense\n"); - w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG, - tmp & 0xfe); - } - - /* Enable temp3 */ - if (type != w83783s) { - tmp = w83781d_read_value(client, - W83781D_REG_TEMP3_CONFIG); - if (tmp & 0x01) { - dev_warn(&client->dev, "Enabling temp3, " - "readings might not make sense\n"); - w83781d_write_value(client, - W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); - } - } - - if (type != w83781d) { - /* enable comparator mode for temp2 and temp3 so - alarm indication will work correctly */ - i = w83781d_read_value(client, W83781D_REG_IRQ); - if (!(i & 0x40)) - w83781d_write_value(client, W83781D_REG_IRQ, - i | 0x40); - } - } - - /* Start monitoring */ - w83781d_write_value(client, W83781D_REG_CONFIG, - (w83781d_read_value(client, - W83781D_REG_CONFIG) & 0xf7) - | 0x01); -} - -static struct w83781d_data *w83781d_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83781d_data *data = i2c_get_clientdata(client); - int i; - - down(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(dev, "Starting device update\n"); - - for (i = 0; i <= 8; i++) { - if (data->type == w83783s && i == 1) - continue; /* 783S has no in1 */ - data->in[i] = - w83781d_read_value(client, W83781D_REG_IN(i)); - data->in_min[i] = - w83781d_read_value(client, W83781D_REG_IN_MIN(i)); - data->in_max[i] = - w83781d_read_value(client, W83781D_REG_IN_MAX(i)); - if ((data->type != w83782d) - && (data->type != w83627hf) && (i == 6)) - break; - } - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = - w83781d_read_value(client, W83781D_REG_FAN(i)); - data->fan_min[i - 1] = - w83781d_read_value(client, W83781D_REG_FAN_MIN(i)); - } - if (data->type != w83781d && data->type != as99127f) { - for (i = 1; i <= 4; i++) { - data->pwm[i - 1] = - w83781d_read_value(client, - W83781D_REG_PWM(i)); - if ((data->type != w83782d - || i2c_is_isa_client(client)) - && i == 2) - break; - } - /* Only PWM2 can be disabled */ - data->pwmenable[1] = (w83781d_read_value(client, - W83781D_REG_PWMCLK12) & 0x08) >> 3; - } - - data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1)); - data->temp_max = - w83781d_read_value(client, W83781D_REG_TEMP_OVER(1)); - data->temp_max_hyst = - w83781d_read_value(client, W83781D_REG_TEMP_HYST(1)); - data->temp_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP(2)); - data->temp_max_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP_OVER(2)); - data->temp_max_hyst_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP_HYST(2)); - if (data->type != w83783s) { - data->temp_add[1] = - w83781d_read_value(client, W83781D_REG_TEMP(3)); - data->temp_max_add[1] = - w83781d_read_value(client, - W83781D_REG_TEMP_OVER(3)); - data->temp_max_hyst_add[1] = - w83781d_read_value(client, - W83781D_REG_TEMP_HYST(3)); - } - i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); - data->vid = i & 0x0f; - data->vid |= (w83781d_read_value(client, - W83781D_REG_CHIPID) & 0x01) << 4; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->fan_div[2] = (w83781d_read_value(client, - W83781D_REG_PIN) >> 6) & 0x03; - if ((data->type != w83781d) && (data->type != as99127f)) { - i = w83781d_read_value(client, W83781D_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - data->fan_div[2] |= (i >> 5) & 0x04; - } - data->alarms = - w83781d_read_value(client, - W83781D_REG_ALARM1) + - (w83781d_read_value(client, W83781D_REG_ALARM2) << 8); - if ((data->type == w83782d) || (data->type == w83627hf)) { - data->alarms |= - w83781d_read_value(client, - W83781D_REG_ALARM3) << 16; - } - i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2); - data->beep_enable = i >> 7; - data->beep_mask = ((i & 0x7f) << 8) + - w83781d_read_value(client, W83781D_REG_BEEP_INTS1); - if ((data->type != w83781d) && (data->type != as99127f)) { - data->beep_mask |= - w83781d_read_value(client, - W83781D_REG_BEEP_INTS3) << 16; - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init -sensors_w83781d_init(void) -{ - return i2c_add_driver(&w83781d_driver); -} - -static void __exit -sensors_w83781d_exit(void) -{ - i2c_del_driver(&w83781d_driver); -} - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "and Mark Studebaker "); -MODULE_DESCRIPTION("W83781D driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_w83781d_init); -module_exit(sensors_w83781d_exit); diff --git a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c deleted file mode 100644 index 4469d52aba4..00000000000 --- a/drivers/i2c/chips/w83l785ts.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2004 Jean Delvare - * - * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made - * by Winbond. It reports a single external temperature with a 1 deg - * resolution and a 3 deg accuracy. Datasheet can be obtained from - * Winbond's website at: - * http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf - * - * Ported to Linux 2.6 by Wolfgang Ziegler and Jean Delvare - * . - * - * Thanks to James Bolt for benchmarking the read - * error handling mechanism. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* How many retries on register read error */ -#define MAX_RETRIES 5 - -/* - * Address to scan - * Address is fully defined internally and cannot be changed. - */ - -static unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(w83l785ts); - -/* - * The W83L785TS-S registers - * Manufacturer ID is 0x5CA3 for Winbond. - */ - -#define W83L785TS_REG_MAN_ID1 0x4D -#define W83L785TS_REG_MAN_ID2 0x4C -#define W83L785TS_REG_CHIP_ID 0x4E -#define W83L785TS_REG_CONFIG 0x40 -#define W83L785TS_REG_TYPE 0x52 -#define W83L785TS_REG_TEMP 0x27 -#define W83L785TS_REG_TEMP_OVER 0x53 /* not sure about this one */ - -/* - * Conversions - * The W83L785TS-S uses signed 8-bit values. - */ - -#define TEMP_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000) - -/* - * Functions declaration - */ - -static int w83l785ts_attach_adapter(struct i2c_adapter *adapter); -static int w83l785ts_detect(struct i2c_adapter *adapter, int address, - int kind); -static int w83l785ts_detach_client(struct i2c_client *client); -static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval); -static struct w83l785ts_data *w83l785ts_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver w83l785ts_driver = { - .owner = THIS_MODULE, - .name = "w83l785ts", - .id = I2C_DRIVERID_W83L785TS, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83l785ts_attach_adapter, - .detach_client = w83l785ts_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct w83l785ts_data { - struct i2c_client client; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - u8 temp, temp_over; -}; - -/* - * Sysfs stuff - */ - -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83l785ts_data *data = w83l785ts_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); -} - -static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct w83l785ts_data *data = w83l785ts_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); -} - -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_over, NULL); - -/* - * Real code - */ - -static int w83l785ts_attach_adapter(struct i2c_adapter *adapter) -{ - if (!(adapter->class & I2C_CLASS_HWMON)) - return 0; - return i2c_detect(adapter, &addr_data, w83l785ts_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct w83l785ts_data *data; - int err = 0; - - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct w83l785ts_data)); - - - /* The common I2C client data is placed right before the - * W83L785TS-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &w83l785ts_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip (actually there is only - * one possible kind of chip for now, W83L785TS-S). A zero kind means - * that the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - if (kind < 0) { /* detection */ - if (((w83l785ts_read_value(new_client, - W83L785TS_REG_CONFIG, 0) & 0x80) != 0x00) - || ((w83l785ts_read_value(new_client, - W83L785TS_REG_TYPE, 0) & 0xFC) != 0x00)) { - dev_dbg(&adapter->dev, - "W83L785TS-S detection failed at 0x%02x.\n", - address); - goto exit_free; - } - } - - if (kind <= 0) { /* identification */ - u16 man_id; - u8 chip_id; - - man_id = (w83l785ts_read_value(new_client, - W83L785TS_REG_MAN_ID1, 0) << 8) + - w83l785ts_read_value(new_client, - W83L785TS_REG_MAN_ID2, 0); - chip_id = w83l785ts_read_value(new_client, - W83L785TS_REG_CHIP_ID, 0); - - if (man_id == 0x5CA3) { /* Winbond */ - if (chip_id == 0x70) { /* W83L785TS-S */ - kind = w83l785ts; - } - } - - if (kind <= 0) { /* identification failed */ - dev_info(&adapter->dev, - "Unsupported chip (man_id=0x%04X, " - "chip_id=0x%02X).\n", man_id, chip_id); - goto exit_free; - } - } - - /* We can fill in the remaining client fields. */ - strlcpy(new_client->name, "w83l785ts", I2C_NAME_SIZE); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Default values in case the first read fails (unlikely). */ - data->temp_over = data->temp = 0; - - /* Tell the I2C layer a new client has arrived. */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* - * Initialize the W83L785TS chip - * Nothing yet, assume it is already started. - */ - - /* Register sysfs hooks */ - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static int w83l785ts_detach_client(struct i2c_client *client) -{ - int err; - - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(i2c_get_clientdata(client)); - return 0; -} - -static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval) -{ - int value, i; - - /* Frequent read errors have been reported on Asus boards, so we - * retry on read errors. If it still fails (unlikely), return the - * default value requested by the caller. */ - for (i = 1; i <= MAX_RETRIES; i++) { - value = i2c_smbus_read_byte_data(client, reg); - if (value >= 0) { - dev_dbg(&client->dev, "Read 0x%02x from register " - "0x%02x.\n", value, reg); - return value; - } - dev_dbg(&client->dev, "Read failed, will retry in %d.\n", i); - msleep(i); - } - - dev_err(&client->dev, "Couldn't read value from register 0x%02x. " - "Please report.\n", reg); - return defval; -} - -static struct w83l785ts_data *w83l785ts_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct w83l785ts_data *data = i2c_get_clientdata(client); - - down(&data->update_lock); - - if (!data->valid || time_after(jiffies, data->last_updated + HZ * 2)) { - dev_dbg(&client->dev, "Updating w83l785ts data.\n"); - data->temp = w83l785ts_read_value(client, - W83L785TS_REG_TEMP, data->temp); - data->temp_over = w83l785ts_read_value(client, - W83L785TS_REG_TEMP_OVER, data->temp_over); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); - - return data; -} - -static int __init sensors_w83l785ts_init(void) -{ - return i2c_add_driver(&w83l785ts_driver); -} - -static void __exit sensors_w83l785ts_exit(void) -{ - i2c_del_driver(&w83l785ts_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("W83L785TS-S driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_w83l785ts_init); -module_exit(sensors_w83l785ts_exit); -- cgit v1.2.3 From 45b1b196677b8009ab6cdc4b656265f1d7015c1b Mon Sep 17 00:00:00 2001 From: Keiichiro Tokunaga Date: Wed, 2 Mar 2005 00:00:00 -0500 Subject: [ACPI] update CONFIG_ACPI_CONTAINER Kconfig help Signed-off-by: Keiichiro Tokunaga Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 670fdb5142d..4aa26acbc46 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -327,8 +327,13 @@ config ACPI_CONTAINER depends on EXPERIMENTAL default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO) ---help--- - This is the ACPI generic container driver which supports - ACPI0004, PNP0A05 and PNP0A06 devices + This allows _physical_ insertion and removal of CPUs and memory. + This can be useful, for example, on NUMA machines that support + ACPI based physical hotplug of nodes, or non-NUMA machines that + support physical cpu/memory hot-plug. + + If one selects "m", this driver can be loaded with + "modprobe acpi_container". config ACPI_HOTPLUG_MEMORY tristate "Memory Hotplug" -- cgit v1.2.3 From bd4698dad3023ae137b366c736e29ca6eaf3b9f7 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 18 Mar 2005 15:35:22 -0500 Subject: [ACPI] Allow simultaneous Fixed Feature and Control Method buttons delete /proc/acpi/button http://bugzilla.kernel.org/show_bug.cgi?id=1920 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/button.c | 245 +------------------------------------------------- 1 file changed, 1 insertion(+), 244 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index ec4430e3053..0f45d45f05a 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -26,9 +26,6 @@ #include #include #include -#include -#include -#include #include #include @@ -36,9 +33,6 @@ #define ACPI_BUTTON_COMPONENT 0x00080000 #define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver" #define ACPI_BUTTON_CLASS "button" -#define ACPI_BUTTON_FILE_INFO "info" -#define ACPI_BUTTON_FILE_STATE "state" -#define ACPI_BUTTON_TYPE_UNKNOWN 0x00 #define ACPI_BUTTON_NOTIFY_STATUS 0x80 #define ACPI_BUTTON_SUBCLASS_POWER "power" @@ -70,8 +64,6 @@ MODULE_LICENSE("GPL"); static int acpi_button_add (struct acpi_device *device); static int acpi_button_remove (struct acpi_device *device, int type); -static int acpi_button_info_open_fs(struct inode *inode, struct file *file); -static int acpi_button_state_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_button_driver = { .name = ACPI_BUTTON_DRIVER_NAME, @@ -90,187 +82,6 @@ struct acpi_button { unsigned long pushed; }; -static struct file_operations acpi_button_info_fops = { - .open = acpi_button_info_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static struct file_operations acpi_button_state_fops = { - .open = acpi_button_state_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -/* -------------------------------------------------------------------------- - FS Interface (/proc) - -------------------------------------------------------------------------- */ - -static struct proc_dir_entry *acpi_button_dir; - -static int acpi_button_info_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_button *button = (struct acpi_button *) seq->private; - - ACPI_FUNCTION_TRACE("acpi_button_info_seq_show"); - - if (!button || !button->device) - return_VALUE(0); - - seq_printf(seq, "type: %s\n", - acpi_device_name(button->device)); - - return_VALUE(0); -} - -static int acpi_button_info_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_button_info_seq_show, PDE(inode)->data); -} - -static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_button *button = (struct acpi_button *) seq->private; - acpi_status status; - unsigned long state; - - ACPI_FUNCTION_TRACE("acpi_button_state_seq_show"); - - if (!button || !button->device) - return_VALUE(0); - - status = acpi_evaluate_integer(button->handle,"_LID",NULL,&state); - if (ACPI_FAILURE(status)) { - seq_printf(seq, "state: unsupported\n"); - } - else{ - seq_printf(seq, "state: %s\n", (state ? "open" : "closed")); - } - - return_VALUE(0); -} - -static int acpi_button_state_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_button_state_seq_show, PDE(inode)->data); -} - -static int -acpi_button_add_fs ( - struct acpi_device *device) -{ - struct proc_dir_entry *entry = NULL; - struct acpi_button *button = NULL; - - ACPI_FUNCTION_TRACE("acpi_button_add_fs"); - - if (!device || !acpi_driver_data(device)) - return_VALUE(-EINVAL); - - button = acpi_driver_data(device); - - switch (button->type) { - case ACPI_BUTTON_TYPE_POWER: - case ACPI_BUTTON_TYPE_POWERF: - entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER, - acpi_button_dir); - break; - case ACPI_BUTTON_TYPE_SLEEP: - case ACPI_BUTTON_TYPE_SLEEPF: - entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP, - acpi_button_dir); - break; - case ACPI_BUTTON_TYPE_LID: - entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, - acpi_button_dir); - break; - } - - if (!entry) - return_VALUE(-ENODEV); - entry->owner = THIS_MODULE; - - acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry); - if (!acpi_device_dir(device)) - return_VALUE(-ENODEV); - acpi_device_dir(device)->owner = THIS_MODULE; - - /* 'info' [R] */ - entry = create_proc_entry(ACPI_BUTTON_FILE_INFO, - S_IRUGO, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_BUTTON_FILE_INFO)); - else { - entry->proc_fops = &acpi_button_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - - /* show lid state [R] */ - if (button->type == ACPI_BUTTON_TYPE_LID) { - entry = create_proc_entry(ACPI_BUTTON_FILE_STATE, - S_IRUGO, acpi_device_dir(device)); - if (!entry) - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Unable to create '%s' fs entry\n", - ACPI_BUTTON_FILE_INFO)); - else { - entry->proc_fops = &acpi_button_state_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - } - - return_VALUE(0); -} - - -static int -acpi_button_remove_fs ( - struct acpi_device *device) -{ - struct acpi_button *button = NULL; - - ACPI_FUNCTION_TRACE("acpi_button_remove_fs"); - - button = acpi_driver_data(device); - if (acpi_device_dir(device)) { - if (button->type == ACPI_BUTTON_TYPE_LID) - remove_proc_entry(ACPI_BUTTON_FILE_STATE, - acpi_device_dir(device)); - remove_proc_entry(ACPI_BUTTON_FILE_INFO, - acpi_device_dir(device)); - - remove_proc_entry(acpi_device_bid(device), - acpi_device_dir(device)->parent); - - - switch (button->type) { - case ACPI_BUTTON_TYPE_POWER: - case ACPI_BUTTON_TYPE_POWERF: - remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, - acpi_button_dir); - break; - case ACPI_BUTTON_TYPE_SLEEP: - case ACPI_BUTTON_TYPE_SLEEPF: - remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, - acpi_button_dir); - break; - case ACPI_BUTTON_TYPE_LID: - remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, - acpi_button_dir); - break; - } - acpi_device_dir(device) = NULL; - } - - return_VALUE(0); -} - - /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ @@ -310,8 +121,7 @@ acpi_button_notify_fixed ( ACPI_FUNCTION_TRACE("acpi_button_notify_fixed"); - if (!button) - return_ACPI_STATUS(AE_BAD_PARAMETER); + BUG_ON(!button); acpi_button_notify(button->handle, ACPI_BUTTON_NOTIFY_STATUS, button); @@ -327,10 +137,6 @@ acpi_button_add ( acpi_status status = AE_OK; struct acpi_button *button = NULL; - static struct acpi_device *power_button; - static struct acpi_device *sleep_button; - static struct acpi_device *lid_button; - ACPI_FUNCTION_TRACE("acpi_button_add"); if (!device) @@ -391,42 +197,6 @@ acpi_button_add ( goto end; } - /* - * Ensure only one button of each type is used. - */ - switch (button->type) { - case ACPI_BUTTON_TYPE_POWER: - case ACPI_BUTTON_TYPE_POWERF: - if (!power_button) - power_button = device; - else { - kfree(button); - return_VALUE(-ENODEV); - } - break; - case ACPI_BUTTON_TYPE_SLEEP: - case ACPI_BUTTON_TYPE_SLEEPF: - if (!sleep_button) - sleep_button = device; - else { - kfree(button); - return_VALUE(-ENODEV); - } - break; - case ACPI_BUTTON_TYPE_LID: - if (!lid_button) - lid_button = device; - else { - kfree(button); - return_VALUE(-ENODEV); - } - break; - } - - result = acpi_button_add_fs(device); - if (result) - goto end; - switch (button->type) { case ACPI_BUTTON_TYPE_POWERF: status = acpi_install_fixed_event_handler ( @@ -470,7 +240,6 @@ acpi_button_add ( end: if (result) { - acpi_button_remove_fs(device); kfree(button); } @@ -511,8 +280,6 @@ acpi_button_remove (struct acpi_device *device, int type) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error removing notify handler\n")); - acpi_button_remove_fs(device); - kfree(button); return_VALUE(0); @@ -526,21 +293,14 @@ acpi_button_init (void) ACPI_FUNCTION_TRACE("acpi_button_init"); - acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); - if (!acpi_button_dir) - return_VALUE(-ENODEV); - acpi_button_dir->owner = THIS_MODULE; - result = acpi_bus_register_driver(&acpi_button_driver); if (result < 0) { - remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); return_VALUE(-ENODEV); } return_VALUE(0); } - static void __exit acpi_button_exit (void) { @@ -548,11 +308,8 @@ acpi_button_exit (void) acpi_bus_unregister_driver(&acpi_button_driver); - remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); - return_VOID; } - module_init(acpi_button_init); module_exit(acpi_button_exit); -- cgit v1.2.3 From be91492ca871e58f61b517cfba541095bb60001c Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 18 Mar 2005 16:00:29 -0500 Subject: [ACPI] CONFIG_ACPI now depends on CONFIG_PM Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 4aa26acbc46..ceecc5634e7 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -3,6 +3,7 @@ # menu "ACPI (Advanced Configuration and Power Interface) Support" + depends on PM depends on !X86_VISWS depends on !IA64_HP_SIM depends on IA64 || X86 @@ -56,7 +57,7 @@ if ACPI_INTERPRETER config ACPI_SLEEP bool "Sleep States (EXPERIMENTAL)" depends on X86 - depends on EXPERIMENTAL && PM + depends on EXPERIMENTAL default y ---help--- This option adds support for ACPI suspend states. -- cgit v1.2.3 From e2a5b420f716cd1a46674b1a90389612eced916f Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 18 Mar 2005 16:20:46 -0500 Subject: [ACPI] ACPI poweroff fix Register an "acpi" system device to be notified of shutdown preparation. This depends on CONFIG_PM http://bugzilla.kernel.org/show_bug.cgi?id=4041 Signed-off-by: Alexey Starikovskiy Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/sleep/main.c | 74 +++++++++++++++++---------------------- drivers/acpi/sleep/poweroff.c | 81 ++++++++++++++++++++++++++++++++++++++----- drivers/base/sys.c | 1 - 3 files changed, 105 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 0a5d2a94131..7249ba2b7a2 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -1,6 +1,7 @@ /* * sleep.c - ACPI sleep support. * + * Copyright (c) 2005 Alexey Starikovskiy * Copyright (c) 2004 David Shaohua Li * Copyright (c) 2000-2003 Patrick Mochel * Copyright (c) 2003 Open Source Development Lab @@ -14,7 +15,6 @@ #include #include #include -#include #include #include #include "sleep.h" @@ -27,10 +27,11 @@ extern void do_suspend_lowlevel_s4bios(void); extern void do_suspend_lowlevel(void); static u32 acpi_suspend_states[] = { - [PM_SUSPEND_ON] = ACPI_STATE_S0, - [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, - [PM_SUSPEND_MEM] = ACPI_STATE_S3, - [PM_SUSPEND_DISK] = ACPI_STATE_S4, + [PM_SUSPEND_ON] = ACPI_STATE_S0, + [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, + [PM_SUSPEND_MEM] = ACPI_STATE_S3, + [PM_SUSPEND_DISK] = ACPI_STATE_S4, + [PM_SUSPEND_MAX] = ACPI_STATE_S5 }; static int init_8259A_after_S1; @@ -44,30 +45,20 @@ static int init_8259A_after_S1; * wakeup code to the waking vector. */ +extern int acpi_sleep_prepare(u32 acpi_state); +extern void acpi_power_off(void); + static int acpi_pm_prepare(suspend_state_t pm_state) { u32 acpi_state = acpi_suspend_states[pm_state]; - if (!sleep_states[acpi_state]) + if (!sleep_states[acpi_state]) { + printk("acpi_pm_prepare does not support %d \n", pm_state); return -EPERM; - - /* do we have a wakeup address for S2 and S3? */ - /* Here, we support only S4BIOS, those we set the wakeup address */ - /* S4OS is only supported for now via swsusp.. */ - if (pm_state == PM_SUSPEND_MEM || pm_state == PM_SUSPEND_DISK) { - if (!acpi_wakeup_address) - return -EFAULT; - acpi_set_firmware_waking_vector( - (acpi_physical_address) virt_to_phys( - (void *)acpi_wakeup_address)); } - ACPI_FLUSH_CPU_CACHE(); - acpi_enable_wakeup_device_prep(acpi_state); - acpi_enter_sleep_state_prep(acpi_state); - return 0; + return acpi_sleep_prepare(acpi_state); } - /** * acpi_pm_enter - Actually enter a sleep state. * @pm_state: State we're entering. @@ -92,11 +83,9 @@ static int acpi_pm_enter(suspend_state_t pm_state) return error; } - local_irq_save(flags); acpi_enable_wakeup_device(acpi_state); - switch (pm_state) - { + switch (pm_state) { case PM_SUSPEND_STANDBY: barrier(); status = acpi_enter_sleep_state(acpi_state); @@ -112,6 +101,10 @@ static int acpi_pm_enter(suspend_state_t pm_state) else do_suspend_lowlevel_s4bios(); break; + case PM_SUSPEND_MAX: + acpi_power_off(); + break; + default: return -EINVAL; } @@ -126,11 +119,9 @@ static int acpi_pm_enter(suspend_state_t pm_state) if (pm_state > PM_SUSPEND_STANDBY) acpi_restore_state_mem(); - return ACPI_SUCCESS(status) ? 0 : -EFAULT; } - /** * acpi_pm_finish - Finish up suspend sequence. * @pm_state: State we're coming out of. @@ -156,27 +147,26 @@ static int acpi_pm_finish(suspend_state_t pm_state) return 0; } - int acpi_suspend(u32 acpi_state) { suspend_state_t states[] = { - [1] = PM_SUSPEND_STANDBY, - [3] = PM_SUSPEND_MEM, - [4] = PM_SUSPEND_DISK, + [1] = PM_SUSPEND_STANDBY, + [3] = PM_SUSPEND_MEM, + [4] = PM_SUSPEND_DISK, + [5] = PM_SUSPEND_MAX }; - if (acpi_state <= 4 && states[acpi_state]) + if (acpi_state < 6 && states[acpi_state]) return pm_suspend(states[acpi_state]); return -EINVAL; } static struct pm_ops acpi_pm_ops = { - .prepare = acpi_pm_prepare, - .enter = acpi_pm_enter, - .finish = acpi_pm_finish, + .prepare = acpi_pm_prepare, + .enter = acpi_pm_enter, + .finish = acpi_pm_finish, }; - /* * Toshiba fails to preserve interrupts over S1, reinitialization * of 8259 is needed after S1 resume. @@ -190,16 +180,16 @@ static int __init init_ints_after_s1(struct dmi_system_id *d) static struct dmi_system_id __initdata acpisleep_dmi_table[] = { { - .callback = init_ints_after_s1, - .ident = "Toshiba Satellite 4030cdt", - .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), }, - }, - { }, + .callback = init_ints_after_s1, + .ident = "Toshiba Satellite 4030cdt", + .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),}, + }, + {}, }; static int __init acpi_sleep_init(void) { - int i = 0; + int i = 0; dmi_check_system(acpisleep_dmi_table); @@ -207,7 +197,7 @@ static int __init acpi_sleep_init(void) return 0; printk(KERN_INFO PREFIX "(supports"); - for (i=0; i < ACPI_S_STATE_COUNT; i++) { + for (i = 0; i < ACPI_S_STATE_COUNT; i++) { acpi_status status; u8 type_a, type_b; status = acpi_get_sleep_type_data(i, &type_a, &type_b); diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c index da237754ded..1fc86e6b5ab 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c @@ -3,35 +3,100 @@ * * AKA S5, but it is independent of whether or not the kernel supports * any other sleep support in the system. + * + * Copyright (c) 2005 Alexey Starikovskiy + * + * This file is released under the GPLv2. */ #include #include #include #include +#include +#include #include "sleep.h" -static void -acpi_power_off (void) +int acpi_sleep_prepare(u32 acpi_state) +{ + /* Flag to do not allow second time invocation for S5 state */ + static int shutdown_prepared = 0; +#ifdef CONFIG_ACPI_SLEEP + /* do we have a wakeup address for S2 and S3? */ + /* Here, we support only S4BIOS, those we set the wakeup address */ + /* S4OS is only supported for now via swsusp.. */ + if (acpi_state == ACPI_STATE_S3 || acpi_state == ACPI_STATE_S4) { + if (!acpi_wakeup_address) { + return -EFAULT; + } + acpi_set_firmware_waking_vector((acpi_physical_address) + virt_to_phys((void *) + acpi_wakeup_address)); + + } + ACPI_FLUSH_CPU_CACHE(); + acpi_enable_wakeup_device_prep(acpi_state); +#endif + if (acpi_state == ACPI_STATE_S5) { + /* Check if we were already called */ + if (shutdown_prepared) + return 0; + acpi_wakeup_gpe_poweroff_prepare(); + shutdown_prepared = 1; + } + acpi_enter_sleep_state_prep(acpi_state); + return 0; +} + +void acpi_power_off(void) { - printk("%s called\n",__FUNCTION__); + printk("%s called\n", __FUNCTION__); + acpi_sleep_prepare(ACPI_STATE_S5); + local_irq_disable(); /* Some SMP machines only can poweroff in boot CPU */ set_cpus_allowed(current, cpumask_of_cpu(0)); - acpi_wakeup_gpe_poweroff_prepare(); - acpi_enter_sleep_state_prep(ACPI_STATE_S5); - ACPI_DISABLE_IRQS(); acpi_enter_sleep_state(ACPI_STATE_S5); } +#ifdef CONFIG_PM + +static int acpi_shutdown(struct sys_device *x) +{ + return acpi_sleep_prepare(ACPI_STATE_S5); +} + +static struct sysdev_class acpi_sysclass = { + set_kset_name("acpi"), + .shutdown = acpi_shutdown +}; + +static struct sys_device device_acpi = { + .id = 0, + .cls = &acpi_sysclass, +}; + +#endif + static int acpi_poweroff_init(void) { if (!acpi_disabled) { u8 type_a, type_b; acpi_status status; - status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); - if (ACPI_SUCCESS(status)) + status = + acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); + if (ACPI_SUCCESS(status)) { pm_power_off = acpi_power_off; +#ifdef CONFIG_PM + { + int error; + error = sysdev_class_register(&acpi_sysclass); + if (!error) + error = sysdev_register(&device_acpi); + return error; + } +#endif + } } return 0; } diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 9102e3756f9..5474bf9622d 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -22,7 +22,6 @@ #include #include - extern struct subsystem devices_subsys; #define to_sysdev(k) container_of(k, struct sys_device, kobj) -- cgit v1.2.3 From 362b06bb70b5a5779b2e852e0f2bdb437061106e Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Fri, 18 Mar 2005 16:30:29 -0500 Subject: [ACPI] S3 Suspend to RAM: interrupt resume fix Delete PCI Interrupt Link Device .resume method -- it is the device driver's job to request interrupts, not the Link's job to remember what the devices want. This addresses the issue of attempting to run the ACPI interpreter too early in resume, when interrupts are still disabled. http://bugzilla.kernel.org/show_bug.cgi?id=3469 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/acpi/pci_link.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 520b28ad074..f2271173bbd 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -72,10 +72,12 @@ struct acpi_pci_link_irq { u8 active; /* Current IRQ */ u8 edge_level; /* All IRQs */ u8 active_high_low; /* All IRQs */ - u8 initialized; u8 resource_type; u8 possible_count; u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; + u8 initialized:1; + u8 suspend_resume:1; + u8 reserved:6; }; struct acpi_pci_link { @@ -530,6 +532,10 @@ static int acpi_pci_link_allocate( ACPI_FUNCTION_TRACE("acpi_pci_link_allocate"); + if (link->irq.suspend_resume) { + acpi_pci_link_set(link, link->irq.active); + link->irq.suspend_resume = 0; + } if (link->irq.initialized) return_VALUE(0); @@ -713,38 +719,24 @@ end: return_VALUE(result); } - -static int -acpi_pci_link_resume ( - struct acpi_pci_link *link) -{ - ACPI_FUNCTION_TRACE("acpi_pci_link_resume"); - - if (link->irq.active && link->irq.initialized) - return_VALUE(acpi_pci_link_set(link, link->irq.active)); - else - return_VALUE(0); -} - - static int -irqrouter_resume( - struct sys_device *dev) +irqrouter_suspend( + struct sys_device *dev, + u32 state) { struct list_head *node = NULL; struct acpi_pci_link *link = NULL; - ACPI_FUNCTION_TRACE("irqrouter_resume"); + ACPI_FUNCTION_TRACE("irqrouter_suspend"); list_for_each(node, &acpi_link.entries) { - link = list_entry(node, struct acpi_pci_link, node); if (!link) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); continue; } - - acpi_pci_link_resume(link); + if (link->irq.active && link->irq.initialized) + link->irq.suspend_resume = 1; } return_VALUE(0); } @@ -856,7 +848,7 @@ __setup("acpi_irq_balance", acpi_irq_balance_set); static struct sysdev_class irqrouter_sysdev_class = { set_kset_name("irqrouter"), - .resume = irqrouter_resume, + .suspend = irqrouter_suspend, }; -- cgit v1.2.3 From d58da590451cf6ae75379a2ebf96d3afb8d810d8 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Fri, 18 Mar 2005 16:43:54 -0500 Subject: [ACPI] S3 Suspend to RAM: fix driver suspend/resume methods Drivers should do this: .suspend() pci_disable_device() .resume() pci_enable_device() http://bugzilla.kernel.org/show_bug.cgi?id=3469 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/net/b44.c | 3 +++ drivers/net/ne2k-pci.c | 3 +++ drivers/pcmcia/yenta_socket.c | 3 +++ drivers/usb/core/hcd-pci.c | 1 + 4 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 3fe8ba992c3..38844d003e4 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1927,6 +1927,7 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) b44_free_rings(bp); spin_unlock_irq(&bp->lock); + pci_disable_device(pdev); return 0; } @@ -1936,6 +1937,8 @@ static int b44_resume(struct pci_dev *pdev) struct b44 *bp = netdev_priv(dev); pci_restore_state(pdev); + pci_enable_device(pdev); + pci_set_master(pdev); if (!netif_running(dev)) return 0; diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index a1a6c08e7dc..f1c01ac2910 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -660,6 +660,7 @@ static int ne2k_pci_suspend (struct pci_dev *pdev, pm_message_t state) netif_device_detach(dev); pci_save_state(pdev); + pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; @@ -671,6 +672,8 @@ static int ne2k_pci_resume (struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); + pci_enable_device(pdev); + pci_set_master(pdev); NS8390_init(dev, 1); netif_device_attach(dev); diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 6404d97a12e..caf7159a54b 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1032,6 +1032,7 @@ static int yenta_dev_suspend (struct pci_dev *dev, pm_message_t state) pci_save_state(dev); pci_read_config_dword(dev, 16*4, &socket->saved_state[0]); pci_read_config_dword(dev, 17*4, &socket->saved_state[1]); + pci_disable_device(dev); /* * Some laptops (IBM T22) do not like us putting the Cardbus @@ -1055,6 +1056,8 @@ static int yenta_dev_resume (struct pci_dev *dev) pci_restore_state(dev); pci_write_config_dword(dev, 16*4, socket->saved_state[0]); pci_write_config_dword(dev, 17*4, socket->saved_state[1]); + pci_enable_device(dev); + pci_set_master(dev); if (socket->type && socket->type->restore_state) socket->type->restore_state(socket); diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 71b4a8d6631..fc056062c96 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -380,6 +380,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev) usb_hc_died (hcd); } + pci_enable_device(dev); return retval; } EXPORT_SYMBOL (usb_hcd_pci_resume); -- cgit v1.2.3 From fb9802fa59b196d7f90bb3c2e33c555c6bdc4c54 Mon Sep 17 00:00:00 2001 From: Luming Yu Date: Fri, 18 Mar 2005 18:03:45 -0500 Subject: [ACPI] generic Hot Key support See Documentation/acpi-hotkey.txt Use cmdline "acpi_specific_hotkey" to enable legacy platform specific drivers. http://bugzilla.kernel.org/show_bug.cgi?id=3887 Signed-off-by: Luming Yu Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 9 + drivers/acpi/Makefile | 3 +- drivers/acpi/asus_acpi.c | 4 + drivers/acpi/hotkey.c | 1018 +++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/ibm_acpi.c | 4 + drivers/acpi/osl.c | 12 + drivers/acpi/toshiba_acpi.c | 5 + 7 files changed, 1054 insertions(+), 1 deletion(-) create mode 100644 drivers/acpi/hotkey.c (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index ceecc5634e7..fa7f4345189 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -123,6 +123,15 @@ config ACPI_VIDEO Note that this is an ref. implementation only. It may or may not work for your integrated video device. +config ACPI_HOTKEY + tristate "Generic Hotkey" + depends on ACPI_INTERPRETER + depends on EXPERIMENTAL + depends on !IA64_SGI_SN + default m + help + ACPI generic hotkey + config ACPI_FAN tristate "Fan" depends on !IA64_SGI_SN diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 65c92e20566..24eb397e17b 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -42,7 +42,8 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o obj-$(CONFIG_ACPI_EC) += ec.o obj-$(CONFIG_ACPI_FAN) += fan.o -obj-$(CONFIG_ACPI_VIDEO) += video.o +obj-$(CONFIG_ACPI_VIDEO) += video.o +obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o obj-$(CONFIG_ACPI_PCI) += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-$(CONFIG_ACPI_POWER) += power.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index a75cb565cae..a560b1e2da7 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -1204,6 +1204,10 @@ static int __init asus_acpi_init(void) if (acpi_disabled) return -ENODEV; + if (!acpi_specific_hotkey_enabled){ + printk(KERN_ERR "Using generic hotkey driver\n"); + return -ENODEV; + } asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); if (!asus_proc_dir) { printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c new file mode 100644 index 00000000000..0aef9fc449c --- /dev/null +++ b/drivers/acpi/hotkey.c @@ -0,0 +1,1018 @@ +/* + * hotkey.c - ACPI Hotkey Driver ($Revision:$) + * + * Copyright (C) 2004 Luming Yu + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 + +#define HOTKEY_ACPI_VERSION "0.1" + +#define HOTKEY_PROC "hotkey" +#define HOTKEY_EV_CONFIG "event_config" +#define HOTKEY_PL_CONFIG "poll_config" +#define HOTKEY_ACTION "action" +#define HOTKEY_INFO "info" + +#define ACPI_HOTK_NAME "Generic Hotkey Driver" +#define ACPI_HOTK_CLASS "Hotkey" +#define ACPI_HOTK_DEVICE_NAME "Hotkey" +#define ACPI_HOTK_HID "Unknown?" +#define ACPI_HOTKEY_COMPONENT 0x20000000 + +#define ACPI_HOTKEY_EVENT 0x1 +#define ACPI_HOTKEY_POLLING 0x2 +#define ACPI_UNDEFINED_EVENT 0xf + +#define MAX_CONFIG_RECORD_LEN 80 +#define MAX_NAME_PATH_LEN 80 +#define MAX_CALL_PARM 80 + +#define IS_EVENT(e) 0xff /* ((e) & 0x40000000) */ +#define IS_POLL(e) 0xff /* (~((e) & 0x40000000)) */ + +#define _COMPONENT ACPI_HOTKEY_COMPONENT +ACPI_MODULE_NAME("acpi_hotkey") + + MODULE_AUTHOR("luming.yu@intel.com"); +MODULE_DESCRIPTION(ACPI_HOTK_NAME); +MODULE_LICENSE("GPL"); + +/* standardized internal hotkey number/event */ +enum { + /* Video Extension event */ + HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80, + HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE, + HK_EVENT_CYCLE_DISPLAY_OUTPUT, + HK_EVENT_NEXT_DISPLAY_OUTPUT, + HK_EVENT_PREVIOUS_DISPLAY_OUTPUT, + HK_EVENT_CYCLE_BRIGHTNESS, + HK_EVENT_INCREASE_BRIGHTNESS, + HK_EVENT_DECREASE_BRIGHTNESS, + HK_EVENT_ZERO_BRIGHTNESS, + HK_EVENT_DISPLAY_DEVICE_OFF, + + /* Snd Card event */ + HK_EVENT_VOLUME_MUTE, + HK_EVENT_VOLUME_INCLREASE, + HK_EVENT_VOLUME_DECREASE, + + /* running state control */ + HK_EVENT_ENTERRING_S3, + HK_EVENT_ENTERRING_S4, + HK_EVENT_ENTERRING_S5, +}; + +/* procdir we use */ +static struct proc_dir_entry *hotkey_proc_dir; +static struct proc_dir_entry *hotkey_config; +static struct proc_dir_entry *hotkey_poll_config; +static struct proc_dir_entry *hotkey_action; +static struct proc_dir_entry *hotkey_info; + +/* linkage for all type of hotkey */ +struct acpi_hotkey_link { + struct list_head entries; + int hotkey_type; /* event or polling based hotkey */ + int hotkey_standard_num; /* standardized hotkey(event) number */ +}; + +/* event based hotkey */ +struct acpi_event_hotkey { + struct acpi_hotkey_link hotkey_link; + int flag; + acpi_handle bus_handle; /* bus to install notify handler */ + int external_hotkey_num; /* external hotkey/event number */ + acpi_handle action_handle; /* acpi handle attached aml action method */ + char *action_method; /* action method */ +}; + +/* + * There are two ways to poll status + * 1. directy call read_xxx method, without any arguments passed in + * 2. call write_xxx method, with arguments passed in, you need + * the result is saved in acpi_polling_hotkey.poll_result. + * anthoer read command through polling interface. + * + */ + +/* polling based hotkey */ +struct acpi_polling_hotkey { + struct acpi_hotkey_link hotkey_link; + int flag; + acpi_handle poll_handle; /* acpi handle attached polling method */ + char *poll_method; /* poll method */ + acpi_handle action_handle; /* acpi handle attached action method */ + char *action_method; /* action method */ + void *poll_result; /* polling_result */ + struct proc_dir_entry *proc; +}; + +/* hotkey object union */ +union acpi_hotkey { + struct list_head entries; + struct acpi_hotkey_link link; + struct acpi_event_hotkey event_hotkey; + struct acpi_polling_hotkey poll_hotkey; +}; + +/* hotkey object list */ +struct acpi_hotkey_list { + struct list_head *entries; + int count; +}; + +static int auto_hotkey_add(struct acpi_device *device); +static int auto_hotkey_remove(struct acpi_device *device, int type); + +static struct acpi_driver hotkey_driver = { + .name = ACPI_HOTK_NAME, + .class = ACPI_HOTK_CLASS, + .ids = ACPI_HOTK_HID, + .ops = { + .add = auto_hotkey_add, + .remove = auto_hotkey_remove, + }, +}; + +static int hotkey_open_config(struct inode *inode, struct file *file); +static ssize_t hotkey_write_config(struct file *file, + const char __user * buffer, + size_t count, loff_t * data); +static ssize_t hotkey_write_poll_config(struct file *file, + const char __user * buffer, + size_t count, loff_t * data); +static int hotkey_info_open_fs(struct inode *inode, struct file *file); +static int hotkey_action_open_fs(struct inode *inode, struct file *file); +static ssize_t hotkey_execute_aml_method(struct file *file, + const char __user * buffer, + size_t count, loff_t * data); +static int hotkey_config_seq_show(struct seq_file *seq, void *offset); +static int hotkey_polling_open_fs(struct inode *inode, struct file *file); + +/* event based config */ +static struct file_operations hotkey_config_fops = { + .open = hotkey_open_config, + .read = seq_read, + .write = hotkey_write_config, + .llseek = seq_lseek, + .release = single_release, +}; + +/* polling based config */ +static struct file_operations hotkey_poll_config_fops = { + .open = hotkey_open_config, + .read = seq_read, + .write = hotkey_write_poll_config, + .llseek = seq_lseek, + .release = single_release, +}; + +/* hotkey driver info */ +static struct file_operations hotkey_info_fops = { + .open = hotkey_info_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* action */ +static struct file_operations hotkey_action_fops = { + .open = hotkey_action_open_fs, + .read = seq_read, + .write = hotkey_execute_aml_method, + .llseek = seq_lseek, + .release = single_release, +}; + +/* polling results */ +static struct file_operations hotkey_polling_fops = { + .open = hotkey_polling_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */ +struct list_head hotkey_entries; /* head of the list of hotkey_list */ + +static int hotkey_info_seq_show(struct seq_file *seq, void *offset) +{ + ACPI_FUNCTION_TRACE("hotkey_info_seq_show"); + + seq_printf(seq, "Hotkey generic driver ver: %s", HOTKEY_ACPI_VERSION); + + return_VALUE(0); +} + +static int hotkey_info_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, hotkey_info_seq_show, PDE(inode)->data); +} + +static char *format_result(union acpi_object *object) +{ + char *buf = (char *)kmalloc(sizeof(union acpi_object), GFP_KERNEL); + + memset(buf, 0, sizeof(union acpi_object)); + + /* Now, just support integer type */ + if (object->type == ACPI_TYPE_INTEGER) + sprintf(buf, "%d", (u32) object->integer.value); + + return buf; +} + +static int hotkey_polling_seq_show(struct seq_file *seq, void *offset) +{ + struct acpi_polling_hotkey *poll_hotkey = + (struct acpi_polling_hotkey *)seq->private; + + ACPI_FUNCTION_TRACE("hotkey_polling_seq_show"); + + if (poll_hotkey->poll_result) + seq_printf(seq, "%s", format_result(poll_hotkey->poll_result)); + + return_VALUE(0); +} + +static int hotkey_polling_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, hotkey_polling_seq_show, PDE(inode)->data); +} + +static int hotkey_action_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, hotkey_info_seq_show, PDE(inode)->data); +} + +/* Mapping external hotkey number to standardized hotkey event num */ +static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list) +{ + struct list_head *entries, *next; + int val = 0; + + ACPI_FUNCTION_TRACE("hotkey_get_internal_event"); + + list_for_each_safe(entries, next, list->entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_type == ACPI_HOTKEY_EVENT + && key->event_hotkey.external_hotkey_num == event) + val = key->link.hotkey_standard_num; + else + val = -1; + } + + return_VALUE(val); +} + +static void +acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data) +{ + struct acpi_device *device = NULL; + u32 internal_event; + + ACPI_FUNCTION_TRACE("acpi_hotkey_notify_handler"); + + if (acpi_bus_get_device(handle, &device)) + return_VOID; + + internal_event = hotkey_get_internal_event(event, &global_hotkey_list); + acpi_bus_generate_event(device, event, 0); + + return_VOID; +} + +/* Need to invent automatically hotkey add method */ +static int auto_hotkey_add(struct acpi_device *device) +{ + /* Implement me */ + return 0; +} + +/* Need to invent automatically hotkey remove method */ +static int auto_hotkey_remove(struct acpi_device *device, int type) +{ + /* Implement me */ + return 0; +} + +/* Create a proc file for each polling method */ +static int create_polling_proc(union acpi_hotkey *device) +{ + struct proc_dir_entry *proc; + + ACPI_FUNCTION_TRACE("create_polling_proc"); + mode_t mode = S_IFREG | S_IRUGO | S_IWUGO; + + proc = create_proc_entry(device->poll_hotkey.action_method, + mode, hotkey_proc_dir); + + if (!proc) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + device->poll_hotkey.poll_method)); + return_VALUE(-ENODEV); + } else { + proc->proc_fops = &hotkey_polling_fops; + proc->owner = THIS_MODULE; + proc->data = device; + proc->uid = 0; + proc->gid = 0; + device->poll_hotkey.proc = proc; + } + return_VALUE(0); +} + +static int is_valid_acpi_path(const char *pathname) +{ + acpi_handle handle; + acpi_status status; + ACPI_FUNCTION_TRACE("is_valid_acpi_path"); + + status = acpi_get_handle(NULL, (char *)pathname, &handle); + return_VALUE(!ACPI_FAILURE(status)); +} + +static int is_valid_hotkey(union acpi_hotkey *device) +{ + ACPI_FUNCTION_TRACE("is_valid_hotkey"); + /* Implement valid check */ + return_VALUE(1); +} + +static int hotkey_add(union acpi_hotkey *device) +{ + int status = 0; + struct acpi_device *dev = NULL; + + ACPI_FUNCTION_TRACE("hotkey_add"); + + if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) { + status = + acpi_bus_get_device(device->event_hotkey.bus_handle, &dev); + if (status) + return_VALUE(status); + + status = acpi_install_notify_handler(dev->handle, + ACPI_SYSTEM_NOTIFY, + acpi_hotkey_notify_handler, + device); + } else /* Add polling hotkey */ + create_polling_proc(device); + + global_hotkey_list.count++; + + list_add_tail(&device->link.entries, global_hotkey_list.entries); + + return_VALUE(status); +} + +static int hotkey_remove(union acpi_hotkey *device) +{ + struct list_head *entries, *next; + + ACPI_FUNCTION_TRACE("hotkey_remove"); + + list_for_each_safe(entries, next, global_hotkey_list.entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_standard_num == + device->link.hotkey_standard_num) { + list_del(&key->link.entries); + remove_proc_entry(key->poll_hotkey.action_method, + hotkey_proc_dir); + global_hotkey_list.count--; + break; + } + } + return_VALUE(0); +} + +static void hotkey_update(union acpi_hotkey *key) +{ + struct list_head *entries, *next; + + ACPI_FUNCTION_TRACE("hotkey_update"); + + list_for_each_safe(entries, next, global_hotkey_list.entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_standard_num == + key->link.hotkey_standard_num) { + key->event_hotkey.bus_handle = + key->event_hotkey.bus_handle; + key->event_hotkey.external_hotkey_num = + key->event_hotkey.external_hotkey_num; + key->event_hotkey.action_handle = + key->event_hotkey.action_handle; + key->event_hotkey.action_method = + key->event_hotkey.action_method; + break; + } + } + + return_VOID; +} + +static void free_hotkey_device(union acpi_hotkey *key) +{ + struct acpi_device *dev; + int status; + + ACPI_FUNCTION_TRACE("free_hotkey_device"); + + if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { + status = + acpi_bus_get_device(key->event_hotkey.bus_handle, &dev); + if (dev->handle) + acpi_remove_notify_handler(dev->handle, + ACPI_SYSTEM_NOTIFY, + acpi_hotkey_notify_handler); + } else + remove_proc_entry(key->poll_hotkey.action_method, + hotkey_proc_dir); + kfree(key); + return_VOID; +} + +static int +init_hotkey_device(union acpi_hotkey *key, char *bus_str, char *action_str, + char *method, int std_num, int external_num) +{ + ACPI_FUNCTION_TRACE("init_hotkey_device"); + + key->link.hotkey_type = ACPI_HOTKEY_EVENT; + key->link.hotkey_standard_num = std_num; + key->event_hotkey.flag = 0; + if (is_valid_acpi_path(bus_str)) + acpi_get_handle((acpi_handle) 0, + bus_str, &(key->event_hotkey.bus_handle)); + else + return_VALUE(-ENODEV); + key->event_hotkey.external_hotkey_num = external_num; + if (is_valid_acpi_path(action_str)) + acpi_get_handle((acpi_handle) 0, + action_str, &(key->event_hotkey.action_handle)); + key->event_hotkey.action_method = kmalloc(sizeof(method), GFP_KERNEL); + strcpy(key->event_hotkey.action_method, method); + + return_VALUE(!is_valid_hotkey(key)); +} + +static int +init_poll_hotkey_device(union acpi_hotkey *key, + char *poll_str, + char *poll_method, + char *action_str, char *action_method, int std_num) +{ + ACPI_FUNCTION_TRACE("init_poll_hotkey_device"); + + key->link.hotkey_type = ACPI_HOTKEY_POLLING; + key->link.hotkey_standard_num = std_num; + key->poll_hotkey.flag = 0; + if (is_valid_acpi_path(poll_str)) + acpi_get_handle((acpi_handle) 0, + poll_str, &(key->poll_hotkey.poll_handle)); + else + return_VALUE(-ENODEV); + key->poll_hotkey.poll_method = poll_method; + if (is_valid_acpi_path(action_str)) + acpi_get_handle((acpi_handle) 0, + action_str, &(key->poll_hotkey.action_handle)); + key->poll_hotkey.action_method = + kmalloc(sizeof(action_method), GFP_KERNEL); + strcpy(key->poll_hotkey.action_method, action_method); + key->poll_hotkey.poll_result = + (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL); + return_VALUE(is_valid_hotkey(key)); +} + +static int check_hotkey_valid(union acpi_hotkey *key, + struct acpi_hotkey_list *list) +{ + ACPI_FUNCTION_TRACE("check_hotkey_valid"); + return_VALUE(0); +} + +static int hotkey_open_config(struct inode *inode, struct file *file) +{ + ACPI_FUNCTION_TRACE("hotkey_open_config"); + return_VALUE(single_open + (file, hotkey_config_seq_show, PDE(inode)->data)); +} + +static int hotkey_config_seq_show(struct seq_file *seq, void *offset) +{ + struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; + struct list_head *entries, *next; + char bus_name[ACPI_PATHNAME_MAX] = { 0 }; + char action_name[ACPI_PATHNAME_MAX] = { 0 }; + struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; + struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; + + ACPI_FUNCTION_TRACE(("hotkey_config_seq_show")); + + if (!hotkey_list) + goto end; + + list_for_each_safe(entries, next, hotkey_list->entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { + acpi_get_name(key->event_hotkey.bus_handle, + ACPI_NAME_TYPE_MAX, &bus); + acpi_get_name(key->event_hotkey.action_handle, + ACPI_NAME_TYPE_MAX, &act); + seq_printf(seq, "%s:%s:%s:%d:%d", bus_name, + action_name, + key->event_hotkey.action_method, + key->link.hotkey_standard_num, + key->event_hotkey.external_hotkey_num); + } /* ACPI_HOTKEY_POLLING */ + else { + acpi_get_name(key->poll_hotkey.poll_handle, + ACPI_NAME_TYPE_MAX, &bus); + acpi_get_name(key->poll_hotkey.action_handle, + ACPI_NAME_TYPE_MAX, &act); + seq_printf(seq, "%s:%s:%s:%s:%d", bus_name, + key->poll_hotkey.poll_method, + action_name, + key->poll_hotkey.action_method, + key->link.hotkey_standard_num); + } + } + seq_puts(seq, "\n"); + end: + return_VALUE(0); +} + +static int +get_parms(char *config_record, + int *cmd, + char *bus_handle, + char *bus_method, + char *action_handle, + char *method, int *internal_event_num, int *external_event_num) +{ + char *tmp, *tmp1; + ACPI_FUNCTION_TRACE(("get_parms")); + + sscanf(config_record, "%d", cmd); + + tmp = strchr(config_record, ':'); + tmp++; + tmp1 = strchr(tmp, ':'); + strncpy(bus_handle, tmp, tmp1 - tmp); + bus_handle[tmp1 - tmp] = 0; + + tmp = tmp1; + tmp++; + tmp1 = strchr(tmp, ':'); + strncpy(bus_method, tmp, tmp1 - tmp); + bus_method[tmp1 - tmp] = 0; + + tmp = tmp1; + tmp++; + tmp1 = strchr(tmp, ':'); + strncpy(action_handle, tmp, tmp1 - tmp); + action_handle[tmp1 - tmp] = 0; + + tmp = tmp1; + tmp++; + tmp1 = strchr(tmp, ':'); + strncpy(method, tmp, tmp1 - tmp); + method[tmp1 - tmp] = 0; + + sscanf(tmp1 + 1, "%d:%d", internal_event_num, external_event_num); + return_VALUE(6); +} + +/* count is length for one input record */ +static ssize_t hotkey_write_config(struct file *file, + const char __user * buffer, + size_t count, loff_t * data) +{ + struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; + char config_record[MAX_CONFIG_RECORD_LEN]; + char bus_handle[MAX_NAME_PATH_LEN]; + char bus_method[MAX_NAME_PATH_LEN]; + char action_handle[MAX_NAME_PATH_LEN]; + char method[20]; + int cmd, internal_event_num, external_event_num; + int ret = 0; + union acpi_hotkey *key = NULL; + + ACPI_FUNCTION_TRACE(("hotkey_write_config")); + + if (!hotkey_list || count > MAX_CONFIG_RECORD_LEN) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid arguments\n")); + return_VALUE(-EINVAL); + } + + if (copy_from_user(config_record, buffer, count)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n")); + return_VALUE(-EINVAL); + } + config_record[count] = '\0'; + + ret = get_parms(config_record, + &cmd, + bus_handle, + bus_method, + action_handle, + method, &internal_event_num, &external_event_num); + if (ret != 6) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid data format ret=%d\n", ret)); + return_VALUE(-EINVAL); + } + + key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL); + ret = init_hotkey_device(key, bus_handle, action_handle, method, + internal_event_num, external_event_num); + + if (ret || check_hotkey_valid(key, hotkey_list)) { + kfree(key); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n")); + return_VALUE(-EINVAL); + } + switch (cmd) { + case 0: + hotkey_add(key); + break; + case 1: + hotkey_remove(key); + free_hotkey_device(key); + break; + case 2: + hotkey_update(key); + break; + default: + break; + } + return_VALUE(count); +} + +/* count is length for one input record */ +static ssize_t hotkey_write_poll_config(struct file *file, + const char __user * buffer, + size_t count, loff_t * data) +{ + struct seq_file *m = (struct seq_file *)file->private_data; + struct acpi_hotkey_list *hotkey_list = + (struct acpi_hotkey_list *)m->private; + + char config_record[MAX_CONFIG_RECORD_LEN]; + char polling_handle[MAX_NAME_PATH_LEN]; + char action_handle[MAX_NAME_PATH_LEN]; + char poll_method[20], action_method[20]; + int ret, internal_event_num, cmd, external_event_num; + union acpi_hotkey *key = NULL; + + ACPI_FUNCTION_TRACE("hotkey_write_poll_config"); + + if (!hotkey_list || count > MAX_CONFIG_RECORD_LEN) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid arguments\n")); + return_VALUE(-EINVAL); + } + + if (copy_from_user(config_record, buffer, count)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n")); + return_VALUE(-EINVAL); + } + config_record[count] = '\0'; + + ret = get_parms(config_record, + &cmd, + polling_handle, + poll_method, + action_handle, + action_method, + &internal_event_num, &external_event_num); + + if (ret != 6) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n")); + return_VALUE(-EINVAL); + } + + key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL); + ret = init_poll_hotkey_device(key, polling_handle, poll_method, + action_handle, action_method, + internal_event_num); + if (ret || check_hotkey_valid(key, hotkey_list)) { + kfree(key); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n")); + return_VALUE(-EINVAL); + } + switch (cmd) { + case 0: + hotkey_add(key); + break; + case 1: + hotkey_remove(key); + break; + case 2: + hotkey_update(key); + break; + default: + break; + } + return_VALUE(count); +} + +/* + * This function evaluates an ACPI method, given an int as parameter, the + * method is searched within the scope of the handle, can be NULL. The output + * of the method is written is output, which can also be NULL + * + * returns 1 if write is successful, 0 else. + */ +static int write_acpi_int(acpi_handle handle, const char *method, int val, + struct acpi_buffer *output) +{ + struct acpi_object_list params; /* list of input parameters (an int here) */ + union acpi_object in_obj; /* the only param we use */ + acpi_status status; + + ACPI_FUNCTION_TRACE("write_acpi_int"); + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = val; + + status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); + + return_VALUE(status == AE_OK); +} + +static int read_acpi_int(acpi_handle handle, const char *method, int *val) +{ + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + ACPI_FUNCTION_TRACE("read_acpi_int"); + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, (char *)method, NULL, &output); + *val = out_obj.integer.value; + return_VALUE((status == AE_OK) + && (out_obj.type == ACPI_TYPE_INTEGER)); +} + +static acpi_handle +get_handle_from_hotkeylist(struct acpi_hotkey_list *hotkey_list, int event_num) +{ + struct list_head *entries, *next; + + list_for_each_safe(entries, next, hotkey_list->entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_type == ACPI_HOTKEY_EVENT + && key->link.hotkey_standard_num == event_num) { + return (key->event_hotkey.action_handle); + } + } + return (NULL); +} + +static +char *get_method_from_hotkeylist(struct acpi_hotkey_list *hotkey_list, + int event_num) +{ + struct list_head *entries, *next; + + list_for_each_safe(entries, next, hotkey_list->entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + + if (key->link.hotkey_type == ACPI_HOTKEY_EVENT && + key->link.hotkey_standard_num == event_num) + return (key->event_hotkey.action_method); + } + return (NULL); +} + +static struct acpi_polling_hotkey *get_hotkey_by_event(struct + acpi_hotkey_list + *hotkey_list, int event) +{ + struct list_head *entries, *next; + + list_for_each_safe(entries, next, hotkey_list->entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + if (key->link.hotkey_type == ACPI_HOTKEY_POLLING + && key->link.hotkey_standard_num == event) { + return (&key->poll_hotkey); + } + } + return (NULL); +} + +/* + * user call AML method interface: + * Call convention: + * echo "event_num: arg type : value" + * example: echo "1:1:30" > /proc/acpi/action + * Just support 1 integer arg passing to AML method + */ + +static ssize_t hotkey_execute_aml_method(struct file *file, + const char __user * buffer, + size_t count, loff_t * data) +{ + struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; + char arg[MAX_CALL_PARM]; + int event, type, value; + + char *method; + acpi_handle handle; + + ACPI_FUNCTION_TRACE("hotkey_execte_aml_method"); + + if (!hotkey_list || count > MAX_CALL_PARM) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 1")); + return_VALUE(-EINVAL); + } + + if (copy_from_user(arg, buffer, count)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 2")); + return_VALUE(-EINVAL); + } + + arg[count] = '\0'; + + if (sscanf(arg, "%d:%d:%d", &event, &type, &value) != 3) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 3")); + return_VALUE(-EINVAL); + } + + if (type == ACPI_TYPE_INTEGER) { + handle = get_handle_from_hotkeylist(hotkey_list, event); + method = (char *)get_method_from_hotkeylist(hotkey_list, event); + if (IS_EVENT(event)) + write_acpi_int(handle, method, value, NULL); + else if (IS_POLL(event)) { + struct acpi_polling_hotkey *key; + key = (struct acpi_polling_hotkey *) + get_hotkey_by_event(hotkey_list, event); + read_acpi_int(handle, method, key->poll_result); + } + } else { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Not supported")); + return_VALUE(-EINVAL); + } + + return_VALUE(count); +} + +static int __init hotkey_init(void) +{ + int result; + mode_t mode = S_IFREG | S_IRUGO | S_IWUGO; + + ACPI_FUNCTION_TRACE("hotkey_init"); + + if (acpi_disabled) + return -ENODEV; + + if (acpi_specific_hotkey_enabled) { + printk("Using specific hotkey driver\n"); + return -ENODEV; + } + + hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir); + if (!hotkey_proc_dir) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + HOTKEY_PROC)); + return (-ENODEV); + } + hotkey_proc_dir->owner = THIS_MODULE; + + hotkey_config = + create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir); + if (!hotkey_config) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + HOTKEY_EV_CONFIG)); + return (-ENODEV); + } else { + hotkey_config->proc_fops = &hotkey_config_fops; + hotkey_config->data = &global_hotkey_list; + hotkey_config->owner = THIS_MODULE; + hotkey_config->uid = 0; + hotkey_config->gid = 0; + } + + hotkey_poll_config = + create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir); + if (!hotkey_poll_config) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + HOTKEY_EV_CONFIG)); + return (-ENODEV); + } else { + hotkey_poll_config->proc_fops = &hotkey_poll_config_fops; + hotkey_poll_config->data = &global_hotkey_list; + hotkey_poll_config->owner = THIS_MODULE; + hotkey_poll_config->uid = 0; + hotkey_poll_config->gid = 0; + } + + hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir); + if (!hotkey_action) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + HOTKEY_ACTION)); + return (-ENODEV); + } else { + hotkey_action->proc_fops = &hotkey_action_fops; + hotkey_action->owner = THIS_MODULE; + hotkey_action->uid = 0; + hotkey_action->gid = 0; + } + + hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir); + if (!hotkey_info) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Hotkey: Unable to create %s entry\n", + HOTKEY_INFO)); + return (-ENODEV); + } else { + hotkey_info->proc_fops = &hotkey_info_fops; + hotkey_info->owner = THIS_MODULE; + hotkey_info->uid = 0; + hotkey_info->gid = 0; + } + + result = acpi_bus_register_driver(&hotkey_driver); + if (result < 0) { + remove_proc_entry(HOTKEY_PROC, acpi_root_dir); + return (-ENODEV); + } + global_hotkey_list.count = 0; + global_hotkey_list.entries = &hotkey_entries; + + INIT_LIST_HEAD(&hotkey_entries); + + return (0); +} + +static void __exit hotkey_exit(void) +{ + struct list_head *entries, *next; + + ACPI_FUNCTION_TRACE("hotkey_remove"); + + list_for_each_safe(entries, next, global_hotkey_list.entries) { + union acpi_hotkey *key = + container_of(entries, union acpi_hotkey, entries); + + acpi_os_wait_events_complete(NULL); + list_del(&key->link.entries); + global_hotkey_list.count--; + free_hotkey_device(key); + } + acpi_bus_unregister_driver(&hotkey_driver); + remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); + remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); + remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); + remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); + remove_proc_entry(HOTKEY_PROC, acpi_root_dir); + return; +} + +module_init(hotkey_init); +module_exit(hotkey_exit); diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index 0fb731a470d..6c8291c3e77 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -1185,6 +1185,10 @@ static int __init acpi_ibm_init(void) if (acpi_disabled) return -ENODEV; + if (!acpi_specific_hotkey_enabled){ + printk(IBM_ERR "Using generic hotkey driver\n"); + return -ENODEV; + } /* these handles are required */ if (IBM_HANDLE_INIT(ec, 1) < 0 || IBM_HANDLE_INIT(hkey, 1) < 0 || diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 5a9128de622..bdd9f37f810 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -71,6 +71,9 @@ EXPORT_SYMBOL(acpi_in_debugger); extern char line_buf[80]; #endif /*ENABLE_DEBUGGER*/ +int acpi_specific_hotkey_enabled; +EXPORT_SYMBOL(acpi_specific_hotkey_enabled); + static unsigned int acpi_irq_irq; static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; @@ -1152,6 +1155,15 @@ acpi_wake_gpes_always_on_setup(char *str) __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); +int __init +acpi_hotkey_setup(char *str) +{ + acpi_specific_hotkey_enabled = TRUE; + return 1; +} + +__setup("acpi_specific_hotkey", acpi_hotkey_setup); + /* * max_cstate is defined in the base kernel so modules can * change it w/o depending on the state of the processor module. diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index c84997c9f96..bed8e53a5ee 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -529,6 +529,11 @@ toshiba_acpi_init(void) if (acpi_disabled) return -ENODEV; + + if (!acpi_specific_hotkey_enabled){ + printk(MY_INFO "Using generic hotkey driver\n"); + return -ENODEV; + } /* simple device detection: look for HCI method */ if (is_valid_acpi_path(METHOD_HCI_1)) method_hci = METHOD_HCI_1; -- cgit v1.2.3 From 4e10d12a3d88c88fba3258809aa42d14fd8cf1d1 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Fri, 18 Mar 2005 18:45:35 -0500 Subject: [ACPI] Bind PCI devices with ACPI devices Implement the framework for binding physical devices with ACPI devices. A physical bus like PCI bus should create a 'acpi_bus_type', with: .find_device: For device which has parent such as normal PCI devices. .find_bridge: It's for special devices, such as PCI root bridge or IDE controller. Such devices generally haven't a parent or ->bus. We use the special method to get an ACPI handle. Uses new field in struct device: firmware_data http://bugzilla.kernel.org/show_bug.cgi?id=4277 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/acpi/Makefile | 2 +- drivers/acpi/glue.c | 362 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/ibm_acpi.c | 4 +- 3 files changed, 365 insertions(+), 3 deletions(-) create mode 100644 drivers/acpi/glue.c (limited to 'drivers') diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 24eb397e17b..ad67e8f61e6 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -36,7 +36,7 @@ processor-objs += processor_perflib.o endif obj-$(CONFIG_ACPI_BUS) += sleep/ -obj-$(CONFIG_ACPI_BUS) += bus.o +obj-$(CONFIG_ACPI_BUS) += bus.o glue.o obj-$(CONFIG_ACPI_AC) += ac.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c new file mode 100644 index 00000000000..b6d2045caf3 --- /dev/null +++ b/drivers/acpi/glue.c @@ -0,0 +1,362 @@ +/* + * Link physical devices with ACPI devices support + * + * Copyright (c) 2005 David Shaohua Li + * Copyright (c) 2005 Intel Corp. + * + * This file is released under the GPLv2. + */ +#include +#include +#include +#include +#include + +#define ACPI_GLUE_DEBUG 0 +#if ACPI_GLUE_DEBUG +#define DBG(x...) printk(PREFIX x) +#else +#define DBG(x...) +#endif +static LIST_HEAD(bus_type_list); +static DECLARE_RWSEM(bus_type_sem); + +int register_acpi_bus_type(struct acpi_bus_type *type) +{ + if (acpi_disabled) + return -ENODEV; + if (type && type->bus && type->find_device) { + down_write(&bus_type_sem); + list_add_tail(&type->list, &bus_type_list); + up_write(&bus_type_sem); + DBG("ACPI bus type %s registered\n", type->bus->name); + return 0; + } + return -ENODEV; +} + +EXPORT_SYMBOL(register_acpi_bus_type); + +int unregister_acpi_bus_type(struct acpi_bus_type *type) +{ + if (acpi_disabled) + return 0; + if (type) { + down_write(&bus_type_sem); + list_del_init(&type->list); + up_write(&bus_type_sem); + DBG("ACPI bus type %s unregistered\n", type->bus->name); + return 0; + } + return -ENODEV; +} + +EXPORT_SYMBOL(unregister_acpi_bus_type); + +static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type) +{ + struct acpi_bus_type *tmp, *ret = NULL; + + down_read(&bus_type_sem); + list_for_each_entry(tmp, &bus_type_list, list) { + if (tmp->bus == type) { + ret = tmp; + break; + } + } + up_read(&bus_type_sem); + return ret; +} + +static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle) +{ + struct acpi_bus_type *tmp; + int ret = -ENODEV; + + down_read(&bus_type_sem); + list_for_each_entry(tmp, &bus_type_list, list) { + if (tmp->find_bridge && !tmp->find_bridge(dev, handle)) { + ret = 0; + break; + } + } + up_read(&bus_type_sem); + return ret; +} + +/* Get PCI root bridge's handle from its segment and bus number */ +struct acpi_find_pci_root { + unsigned int seg; + unsigned int bus; + acpi_handle handle; +}; + +static acpi_status +do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) +{ + int *busnr = (int *)data; + struct acpi_resource_address64 address; + + if (resource->id != ACPI_RSTYPE_ADDRESS16 && + resource->id != ACPI_RSTYPE_ADDRESS32 && + resource->id != ACPI_RSTYPE_ADDRESS64) + return AE_OK; + + acpi_resource_to_address64(resource, &address); + if ((address.address_length > 0) && + (address.resource_type == ACPI_BUS_NUMBER_RANGE)) + *busnr = address.min_address_range; + + return AE_OK; +} + +static int get_root_bridge_busnr(acpi_handle handle) +{ + acpi_status status; + int bus, bbn; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, + (unsigned long *)&bbn); + if (status == AE_NOT_FOUND) { + /* Assume bus = 0 */ + printk(KERN_INFO PREFIX + "Assume root bridge [%s] bus is 0\n", + (char *)buffer.pointer); + status = AE_OK; + bbn = 0; + } + if (ACPI_FAILURE(status)) { + bbn = -ENODEV; + goto exit; + } + if (bbn > 0) + goto exit; + + /* _BBN in some systems return 0 for all root bridges */ + bus = -1; + status = acpi_walk_resources(handle, METHOD_NAME__CRS, + do_root_bridge_busnr_callback, &bus); + /* If _CRS failed, we just use _BBN */ + if (ACPI_FAILURE(status) || (bus == -1)) + goto exit; + /* We select _CRS */ + if (bbn != bus) { + printk(KERN_INFO PREFIX + "_BBN and _CRS returns different value for %s. Select _CRS\n", + (char *)buffer.pointer); + bbn = bus; + } + exit: + acpi_os_free(buffer.pointer); + return bbn; +} + +static acpi_status +find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + struct acpi_find_pci_root *find = (struct acpi_find_pci_root *)context; + unsigned long seg, bus; + acpi_status status; + int tmp; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &seg); + if (status == AE_NOT_FOUND) { + /* Assume seg = 0 */ + printk(KERN_INFO PREFIX + "Assume root bridge [%s] segment is 0\n", + (char *)buffer.pointer); + status = AE_OK; + seg = 0; + } + if (ACPI_FAILURE(status)) { + status = AE_CTRL_DEPTH; + goto exit; + } + + tmp = get_root_bridge_busnr(handle); + if (tmp < 0) { + printk(KERN_ERR PREFIX + "Find root bridge failed for %s\n", + (char *)buffer.pointer); + status = AE_CTRL_DEPTH; + goto exit; + } + bus = tmp; + + if (seg == find->seg && bus == find->bus) + find->handle = handle; + status = AE_OK; + exit: + acpi_os_free(buffer.pointer); + return status; +} + +acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) +{ + struct acpi_find_pci_root find = { seg, bus, NULL }; + + acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL); + return find.handle; +} + +/* Get device's handler per its address under its parent */ +struct acpi_find_child { + acpi_handle handle; + acpi_integer address; +}; + +static acpi_status +do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + struct acpi_device_info *info; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_find_child *find = (struct acpi_find_child *)context; + + status = acpi_get_object_info(handle, &buffer); + if (ACPI_SUCCESS(status)) { + info = buffer.pointer; + if (info->address == find->address) + find->handle = handle; + acpi_os_free(buffer.pointer); + } + return AE_OK; +} + +acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address) +{ + struct acpi_find_child find = { NULL, address }; + + if (!parent) + return NULL; + acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, + 1, do_acpi_find_child, &find, NULL); + return find.handle; +} + +EXPORT_SYMBOL(acpi_get_child); + +/* Link ACPI devices with physical devices */ +static void acpi_glue_data_handler(acpi_handle handle, + u32 function, void *context) +{ + /* we provide an empty handler */ +} + +/* Note: a success call will increase reference count by one */ +struct device *acpi_get_physical_device(acpi_handle handle) +{ + acpi_status status; + struct device *dev; + + status = acpi_get_data(handle, acpi_glue_data_handler, (void **)&dev); + if (ACPI_SUCCESS(status)) + return get_device(dev); + return NULL; +} + +EXPORT_SYMBOL(acpi_get_physical_device); + +static int acpi_bind_one(struct device *dev, acpi_handle handle) +{ + acpi_status status; + + if (dev->firmware_data) { + printk(KERN_WARNING PREFIX + "Drivers changed 'firmware_data' for %s\n", dev->bus_id); + return -EINVAL; + } + get_device(dev); + status = acpi_attach_data(handle, acpi_glue_data_handler, dev); + if (ACPI_FAILURE(status)) { + put_device(dev); + return -EINVAL; + } + dev->firmware_data = handle; + + return 0; +} + +static int acpi_unbind_one(struct device *dev) +{ + if (!dev->firmware_data) + return 0; + if (dev == acpi_get_physical_device(dev->firmware_data)) { + /* acpi_get_physical_device increase refcnt by one */ + put_device(dev); + acpi_detach_data(dev->firmware_data, acpi_glue_data_handler); + dev->firmware_data = NULL; + /* acpi_bind_one increase refcnt by one */ + put_device(dev); + } else { + printk(KERN_ERR PREFIX + "Oops, 'firmware_data' corrupt for %s\n", dev->bus_id); + } + return 0; +} + +static int acpi_platform_notify(struct device *dev) +{ + struct acpi_bus_type *type; + acpi_handle handle; + int ret = -EINVAL; + + if (!dev->bus || !dev->parent) { + /* bridge devices genernally haven't bus or parent */ + ret = acpi_find_bridge_device(dev, &handle); + goto end; + } + type = acpi_get_bus_type(dev->bus); + if (!type) { + printk(KERN_INFO PREFIX "No ACPI bus support for %s\n", + dev->bus_id); + ret = -EINVAL; + goto end; + } + if ((ret = type->find_device(dev, &handle)) != 0) + printk(KERN_INFO PREFIX "Can't get handler for %s\n", + dev->bus_id); + end: + if (!ret) + acpi_bind_one(dev, handle); + +#if ACPI_GLUE_DEBUG + if (!ret) { + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + acpi_get_name(dev->firmware_data, ACPI_FULL_PATHNAME, &buffer); + DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer); + acpi_os_free(buffer.pointer); + } else + DBG("Device %s -> No ACPI support\n", dev->bus_id); +#endif + + return ret; +} + +static int acpi_platform_notify_remove(struct device *dev) +{ + acpi_unbind_one(dev); + return 0; +} + +static int __init init_acpi_device_notify(void) +{ + if (acpi_disabled) + return 0; + if (platform_notify || platform_notify_remove) { + printk(KERN_ERR PREFIX "Can't use platform_notify\n"); + return 0; + } + platform_notify = acpi_platform_notify; + platform_notify_remove = acpi_platform_notify_remove; + return 0; +} + +arch_initcall(init_acpi_device_notify); diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index 6c8291c3e77..ad85e10001f 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -1025,7 +1025,7 @@ static int setup_notify(struct ibm_struct *ibm) return 0; } -static int device_add(struct acpi_device *device) +static int ibmacpi_device_add(struct acpi_device *device) { return 0; } @@ -1043,7 +1043,7 @@ static int register_driver(struct ibm_struct *ibm) memset(ibm->driver, 0, sizeof(struct acpi_driver)); sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name); ibm->driver->ids = ibm->hid; - ibm->driver->ops.add = &device_add; + ibm->driver->ops.add = &ibmacpi_device_add; ret = acpi_bus_register_driver(ibm->driver); if (ret < 0) { -- cgit v1.2.3 From 84df749f364209c9623304b7a94ddb954dc343bb Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Fri, 18 Mar 2005 18:53:36 -0500 Subject: [ACPI] Bind ACPI and PCI devices http://bugzilla.kernel.org/show_bug.cgi?id=4277 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/pci/pci-acpi.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index bc01d34e263..f94c86fbc66 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -1,9 +1,10 @@ /* * File: pci-acpi.c - * Purpose: Provide PCI supports in ACPI + * Purpose: Provide PCI support in ACPI * - * Copyright (C) 2004 Intel - * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) + * Copyright (C) 2005 David Shaohua Li + * Copyright (C) 2004 Tom Long Nguyen + * Copyright (C) 2004 Intel Corp. */ #include @@ -207,3 +208,53 @@ acpi_status pci_osc_control_set(u32 flags) return status; } EXPORT_SYMBOL(pci_osc_control_set); + +/* ACPI bus type */ +static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) +{ + struct pci_dev * pci_dev; + acpi_integer addr; + + pci_dev = to_pci_dev(dev); + /* Please ref to ACPI spec for the syntax of _ADR */ + addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); + *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr); + if (!*handle) + return -ENODEV; + return 0; +} + +static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) +{ + int num; + unsigned int seg, bus; + + /* + * The string should be the same as root bridge's name + * Please look at 'pci_scan_bus_parented' + */ + num = sscanf(dev->bus_id, "pci%04x:%02x", &seg, &bus); + if (num != 2) + return -ENODEV; + *handle = acpi_get_pci_rootbridge_handle(seg, bus); + if (!*handle) + return -ENODEV; + return 0; +} + +static struct acpi_bus_type pci_acpi_bus = { + .bus = &pci_bus_type, + .find_device = pci_acpi_find_device, + .find_bridge = pci_acpi_find_root_bridge, +}; + +static int __init pci_acpi_init(void) +{ + int ret; + + ret = register_acpi_bus_type(&pci_acpi_bus); + if (ret) + return 0; + return 0; +} +arch_initcall(pci_acpi_init); -- cgit v1.2.3 From 0f64474b8f7f1f7f3af5b24ef997baa35f923509 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Sat, 19 Mar 2005 00:15:48 -0500 Subject: [ACPI] PCI can now get suspend state from firmware pci_choose_state() can now call platform_pci_choose_state() and ACPI can answer http://bugzilla.kernel.org/show_bug.cgi?id=4277 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/pci/pci-acpi.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- drivers/pci/pci.c | 11 ++++++++++- drivers/pci/pci.h | 3 +++ 3 files changed, 59 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index f94c86fbc66..8eb599708de 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -1,6 +1,6 @@ /* * File: pci-acpi.c - * Purpose: Provide PCI support in ACPI + * Purpose: Provde PCI support in ACPI * * Copyright (C) 2005 David Shaohua Li * Copyright (C) 2004 Tom Long Nguyen @@ -17,6 +17,7 @@ #include #include +#include "pci.h" static u32 ctrlset_buf[3] = {0, 0, 0}; static u32 global_ctrlsets = 0; @@ -209,6 +210,49 @@ acpi_status pci_osc_control_set(u32 flags) } EXPORT_SYMBOL(pci_osc_control_set); +/* + * _SxD returns the D-state with the highest power + * (lowest D-state number) supported in the S-state "x". + * + * If the devices does not have a _PRW + * (Power Resources for Wake) supporting system wakeup from "x" + * then the OS is free to choose a lower power (higher number + * D-state) than the return value from _SxD. + * + * But if _PRW is enabled at S-state "x", the OS + * must not choose a power lower than _SxD -- + * unless the device has an _SxW method specifying + * the lowest power (highest D-state number) the device + * may enter while still able to wake the system. + * + * ie. depending on global OS policy: + * + * if (_PRW at S-state x) + * choose from highest power _SxD to lowest power _SxW + * else // no _PRW at S-state x + * choose highest power _SxD or any lower power + * + * currently we simply return _SxD, if present. + */ + +static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) +{ + char dstate_str[] = "_S0D"; + acpi_status status; + unsigned long val; + struct device *dev = &pdev->dev; + + /* Fixme: the check is wrong after pm_message_t is a struct */ + if ((state >= PM_SUSPEND_MAX) || !DEVICE_ACPI_HANDLE(dev)) + return -EINVAL; + dstate_str[2] += state; /* _S1D, _S2D, _S3D, _S4D */ + status = acpi_evaluate_integer(DEVICE_ACPI_HANDLE(dev), dstate_str, + NULL, &val); + if (ACPI_SUCCESS(status)) + return val; + return -ENODEV; +} + /* ACPI bus type */ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) { @@ -255,6 +299,7 @@ static int __init pci_acpi_init(void) ret = register_acpi_bus_type(&pci_acpi_bus); if (ret) return 0; + platform_pci_choose_state = acpi_pci_choose_state; return 0; } arch_initcall(pci_acpi_init); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f04b9ffe415..5af94180778 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -304,6 +304,8 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) return 0; } +int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state) = NULL; + /** * pci_choose_state - Choose the power state of a PCI device * @dev: PCI device to be suspended @@ -316,10 +318,17 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { + int ret; + if (!pci_find_capability(dev, PCI_CAP_ID_PM)) return PCI_D0; - switch (state) { + if (platform_pci_choose_state) { + ret = platform_pci_choose_state(dev, state); + if (ret >= 0) + state = ret; + } + switch (state) { case 0: return PCI_D0; case 3: return PCI_D3hot; default: diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 744da0d4ae5..25c44922f7d 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -11,6 +11,9 @@ extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, void (*alignf)(void *, struct resource *, unsigned long, unsigned long), void *alignf_data); +/* Firmware callbacks */ +extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); + /* PCI /proc functions */ #ifdef CONFIG_PROC_FS extern int pci_proc_attach_device(struct pci_dev *dev); -- cgit v1.2.3 From b913100d7304ea9596d8d85ab5f3ae04bd2b0ddb Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Sat, 19 Mar 2005 00:16:18 -0500 Subject: [ACPI] pci_set_power_state() now calls platform_pci_set_power_state() and ACPI can answer http://bugzilla.kernel.org/show_bug.cgi?id=4277 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/acpi/bus.c | 8 +++++++- drivers/pci/pci-acpi.c | 19 +++++++++++++++++++ drivers/pci/pci.c | 11 +++++++++-- drivers/pci/pci.h | 1 + 4 files changed, 36 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 4edff173857..d77c2307883 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -212,6 +212,12 @@ acpi_bus_set_power ( ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device is not power manageable\n")); return_VALUE(-ENODEV); } + /* + * Get device's current power state if it's unknown + * This means device power state isn't initialized or previous setting failed + */ + if (device->power.state == ACPI_STATE_UNKNOWN) + acpi_bus_get_power(device->handle, &device->power.state); if (state == device->power.state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); return_VALUE(0); @@ -231,7 +237,7 @@ acpi_bus_set_power ( * On transitions to a high-powered state we first apply power (via * power resources) then evalute _PSx. Conversly for transitions to * a lower-powered state. - */ + */ if (state < device->power.state) { if (device->power.flags.power_resources) { result = acpi_power_transition(device, state); diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 8eb599708de..a0d43ea872d 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -253,6 +253,24 @@ static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) return -ENODEV; } +static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) +{ + acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); + static int state_conv[] = { + [0] = 0, + [1] = 1, + [2] = 2, + [3] = 3, + [4] = 3 + }; + int acpi_state = state_conv[(int __force) state]; + + if (!handle) + return -ENODEV; + return acpi_bus_set_power(handle, acpi_state); +} + + /* ACPI bus type */ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) { @@ -300,6 +318,7 @@ static int __init pci_acpi_init(void) if (ret) return 0; platform_pci_choose_state = acpi_pci_choose_state; + platform_pci_set_power_state = acpi_pci_set_power_state; return 0; } arch_initcall(pci_acpi_init); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5af94180778..a1c66e8ea5f 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -235,7 +235,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) * -EIO if device does not support PCI PM. * 0 if we can successfully change the power state. */ - +int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t) = NULL; int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { @@ -299,8 +299,15 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) msleep(10); else if (state == PCI_D2 || dev->current_state == PCI_D2) udelay(200); - dev->current_state = state; + /* + * Give firmware a chance to be called, such as ACPI _PRx, _PSx + * Firmware method after natice method ? + */ + if (platform_pci_set_power_state) + platform_pci_set_power_state(dev, state); + + dev->current_state = state; return 0; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 25c44922f7d..d94d7af4f7a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -13,6 +13,7 @@ extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, void *alignf_data); /* Firmware callbacks */ extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); +extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state); /* PCI /proc functions */ #ifdef CONFIG_PROC_FS -- cgit v1.2.3 From 451566f45a2e6cd10ba56e7220a9dd84ba3ef550 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 19 Mar 2005 01:10:05 -0500 Subject: [ACPI] Enable EC Burst Mode Fixes several Embedded Controller issues, including button failure and battery status AE_TIME failure. http://bugzilla.kernel.org/show_bug.cgi?id=3851 Based on patch by: Andi Kleen Signed-off-by: Dmitry Torokhov Signed-off-by: Luming Yu Signed-off-by: Len Brown --- drivers/acpi/ec.c | 390 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 276 insertions(+), 114 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index fdf143b405b..69b04d430f0 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -49,17 +50,19 @@ ACPI_MODULE_NAME ("acpi_ec") #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ +#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ #define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */ #define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */ -#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */ -#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */ +#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */ #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ #define ACPI_EC_COMMAND_READ 0x80 #define ACPI_EC_COMMAND_WRITE 0x81 +#define ACPI_EC_BURST_ENABLE 0x82 +#define ACPI_EC_BURST_DISABLE 0x83 #define ACPI_EC_COMMAND_QUERY 0x84 static int acpi_ec_add (struct acpi_device *device); @@ -87,7 +90,11 @@ struct acpi_ec { struct acpi_generic_address command_addr; struct acpi_generic_address data_addr; unsigned long global_lock; - spinlock_t lock; + unsigned int expect_event; + atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort*/ + atomic_t pending_gpe; + struct semaphore sem; + wait_queue_head_t wait; }; /* If we find an EC via the ECDT, we need to keep a ptr to its context */ @@ -100,59 +107,138 @@ static struct acpi_device *first_ec; Transaction Management -------------------------------------------------------------------------- */ -static int -acpi_ec_wait ( - struct acpi_ec *ec, - u8 event) +static inline u32 acpi_ec_read_status(struct acpi_ec *ec) { - u32 acpi_ec_status = 0; - u32 i = ACPI_EC_UDELAY_COUNT; + u32 status = 0; - if (!ec) - return -EINVAL; + acpi_hw_low_level_read(8, &status, &ec->status_addr); + return status; +} + +static int acpi_ec_wait(struct acpi_ec *ec, unsigned int event) +{ + int result = 0; + + ACPI_FUNCTION_TRACE("acpi_ec_wait"); - /* Poll the EC status register waiting for the event to occur. */ + ec->expect_event = event; + smp_mb(); + + result = wait_event_interruptible_timeout(ec->wait, + !ec->expect_event, + msecs_to_jiffies(ACPI_EC_DELAY)); + + ec->expect_event = 0; + smp_mb(); + + if (result < 0){ + ACPI_DEBUG_PRINT((ACPI_DB_ERROR," result = %d ", result)); + return_VALUE(result); + } + + /* + * Verify that the event in question has actually happened by + * querying EC status. Do the check even if operation timed-out + * to make sure that we did not miss interrupt. + */ switch (event) { case ACPI_EC_EVENT_OBF: - do { - acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr); - if (acpi_ec_status & ACPI_EC_FLAG_OBF) - return 0; - udelay(ACPI_EC_UDELAY); - } while (--i>0); + if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) + return_VALUE(0); break; + case ACPI_EC_EVENT_IBE: - do { - acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr); - if (!(acpi_ec_status & ACPI_EC_FLAG_IBF)) - return 0; - udelay(ACPI_EC_UDELAY); - } while (--i>0); + if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) + return_VALUE(0); break; - default: - return -EINVAL; } - return -ETIME; + return_VALUE(-ETIME); } + +static int +acpi_ec_enter_burst_mode ( + struct acpi_ec *ec) +{ + u32 tmp = 0; + int status = 0; + + ACPI_FUNCTION_TRACE("acpi_ec_enter_burst_mode"); + + status = acpi_ec_read_status(ec); + if (status != -EINVAL && + !(status & ACPI_EC_FLAG_BURST)){ + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"entering burst mode \n")); + acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (status){ + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR," status = %d\n", status)); + return_VALUE(-EINVAL); + } + acpi_hw_low_level_read(8, &tmp, &ec->data_addr); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + if(tmp != 0x90 ) {/* Burst ACK byte*/ + ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Ack failed \n")); + return_VALUE(-EINVAL); + } + } else + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"already be in burst mode \n")); + atomic_set(&ec->leaving_burst , 0); + return_VALUE(0); +} + +static int +acpi_ec_leave_burst_mode ( + struct acpi_ec *ec) +{ + int status =0; + + ACPI_FUNCTION_TRACE("acpi_ec_leave_burst_mode"); + + atomic_set(&ec->leaving_burst , 1); + status = acpi_ec_read_status(ec); + if (status != -EINVAL && + (status & ACPI_EC_FLAG_BURST)){ + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"leaving burst mode\n")); + acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->command_addr); + status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF); + if (status){ + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->wait fail\n")); + return_VALUE(-EINVAL); + } + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + status = acpi_ec_read_status(ec); + if (status != -EINVAL && + (status & ACPI_EC_FLAG_BURST)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->status fail\n")); + return_VALUE(-EINVAL); + } + }else + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"already be in Non-burst mode \n")); + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"leaving burst mode\n")); + + return_VALUE(0); +} + static int acpi_ec_read ( struct acpi_ec *ec, u8 address, u32 *data) { - acpi_status status = AE_OK; - int result = 0; - unsigned long flags = 0; - u32 glk = 0; + int status = 0; + u32 glk; ACPI_FUNCTION_TRACE("acpi_ec_read"); if (!ec || !data) return_VALUE(-EINVAL); +retry: *data = 0; if (ec->global_lock) { @@ -160,32 +246,50 @@ acpi_ec_read ( if (ACPI_FAILURE(status)) return_VALUE(-ENODEV); } - - spin_lock_irqsave(&ec->lock, flags); + + WARN_ON(in_interrupt()); + down(&ec->sem); + + if(acpi_ec_enter_burst_mode(ec)) + goto end; acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + if (status) { goto end; + } acpi_hw_low_level_write(8, address, &ec->data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (result) + status= acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (status){ + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); goto end; - + } acpi_hw_low_level_read(8, data, &ec->data_addr); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n", *data, address)); - + end: - spin_unlock_irqrestore(&ec->lock, flags); + acpi_ec_leave_burst_mode(ec); + up(&ec->sem); if (ec->global_lock) acpi_release_global_lock(glk); - return_VALUE(result); + if(atomic_read(&ec->leaving_burst) == 2){ + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); + while(!atomic_read(&ec->pending_gpe)){ + msleep(1); + } + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + goto retry; + } + + return_VALUE(status); } @@ -195,49 +299,80 @@ acpi_ec_write ( u8 address, u8 data) { - int result = 0; - acpi_status status = AE_OK; - unsigned long flags = 0; - u32 glk = 0; + int status = 0; + u32 glk; + u32 tmp; ACPI_FUNCTION_TRACE("acpi_ec_write"); if (!ec) return_VALUE(-EINVAL); - +retry: if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); if (ACPI_FAILURE(status)) return_VALUE(-ENODEV); } - spin_lock_irqsave(&ec->lock, flags); + WARN_ON(in_interrupt()); + down(&ec->sem); + + if(acpi_ec_enter_burst_mode(ec)) + goto end; + + status = acpi_ec_read_status(ec); + if (status != -EINVAL && + !(status & ACPI_EC_FLAG_BURST)){ + acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr); + status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (status) + goto end; + acpi_hw_low_level_read(8, &tmp, &ec->data_addr); + if(tmp != 0x90 ) /* Burst ACK byte*/ + goto end; + } + /*Now we are in burst mode*/ acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + if (status){ goto end; + } acpi_hw_low_level_write(8, address, &ec->data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + if (status){ + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); goto end; + } acpi_hw_low_level_write(8, data, &ec->data_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); - if (result) + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + if (status) goto end; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n", data, address)); end: - spin_unlock_irqrestore(&ec->lock, flags); + acpi_ec_leave_burst_mode(ec); + up(&ec->sem); if (ec->global_lock) acpi_release_global_lock(glk); - return_VALUE(result); + if(atomic_read(&ec->leaving_burst) == 2){ + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); + while(!atomic_read(&ec->pending_gpe)){ + msleep(1); + } + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + goto retry; + } + + return_VALUE(status); } /* @@ -289,16 +424,14 @@ acpi_ec_query ( struct acpi_ec *ec, u32 *data) { - int result = 0; - acpi_status status = AE_OK; - unsigned long flags = 0; - u32 glk = 0; + int status = 0; + u32 glk; ACPI_FUNCTION_TRACE("acpi_ec_query"); if (!ec || !data) return_VALUE(-EINVAL); - +retry: *data = 0; if (ec->global_lock) { @@ -307,29 +440,43 @@ acpi_ec_query ( return_VALUE(-ENODEV); } + down(&ec->sem); + if(acpi_ec_enter_burst_mode(ec)) + goto end; /* * Query the EC to find out which _Qxx method we need to evaluate. * Note that successful completion of the query causes the ACPI_EC_SCI * bit to be cleared (and thus clearing the interrupt source). */ - spin_lock_irqsave(&ec->lock, flags); - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr); - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); - if (result) + status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF); + if (status){ + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); goto end; - + } + acpi_hw_low_level_read(8, data, &ec->data_addr); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); if (!*data) - result = -ENODATA; + status = -ENODATA; end: - spin_unlock_irqrestore(&ec->lock, flags); + acpi_ec_leave_burst_mode(ec); + up(&ec->sem); if (ec->global_lock) acpi_release_global_lock(glk); - return_VALUE(result); + if(atomic_read(&ec->leaving_burst) == 2){ + ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); + while(!atomic_read(&ec->pending_gpe)){ + msleep(1); + } + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + goto retry; + } + + return_VALUE(status); } @@ -347,42 +494,29 @@ acpi_ec_gpe_query ( void *ec_cxt) { struct acpi_ec *ec = (struct acpi_ec *) ec_cxt; - u32 value = 0; - unsigned long flags = 0; + u32 value; + int result = -ENODATA; static char object_name[5] = {'_','Q','0','0','\0'}; const char hex[] = {'0','1','2','3','4','5','6','7', '8','9','A','B','C','D','E','F'}; ACPI_FUNCTION_TRACE("acpi_ec_gpe_query"); - if (!ec_cxt) - goto end; + if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) + result = acpi_ec_query(ec, &value); - spin_lock_irqsave(&ec->lock, flags); - acpi_hw_low_level_read(8, &value, &ec->command_addr); - spin_unlock_irqrestore(&ec->lock, flags); - - /* TBD: Implement asynch events! - * NOTE: All we care about are EC-SCI's. Other EC events are - * handled via polling (yuck!). This is because some systems - * treat EC-SCIs as level (versus EDGE!) triggered, preventing - * a purely interrupt-driven approach (grumble, grumble). - */ - if (!(value & ACPI_EC_FLAG_SCI)) + if (result) goto end; - if (acpi_ec_query(ec, &value)) - goto end; - object_name[2] = hex[((value >> 4) & 0x0F)]; object_name[3] = hex[(value & 0x0F)]; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); acpi_evaluate_object(ec->handle, object_name, NULL, NULL); - -end: - acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); + atomic_dec(&ec->pending_gpe); +end: + return; } static u32 @@ -390,6 +524,7 @@ acpi_ec_gpe_handler ( void *data) { acpi_status status = AE_OK; + u32 value; struct acpi_ec *ec = (struct acpi_ec *) data; if (!ec) @@ -397,13 +532,39 @@ acpi_ec_gpe_handler ( acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR); - status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, - acpi_ec_gpe_query, ec); + value = acpi_ec_read_status(ec); - if (status == AE_OK) - return ACPI_INTERRUPT_HANDLED; - else - return ACPI_INTERRUPT_NOT_HANDLED; + if((value & ACPI_EC_FLAG_IBF) && + !(value & ACPI_EC_FLAG_BURST) && + (atomic_read(&ec->leaving_burst) == 0)) { + /* + * the embedded controller disables + * burst mode for any reason other + * than the burst disable command + * to process critical event. + */ + atomic_set(&ec->leaving_burst , 2); /* block current pending transaction + and retry */ + wake_up(&ec->wait); + }else { + if ((ec->expect_event == ACPI_EC_EVENT_OBF && + (value & ACPI_EC_FLAG_OBF)) || + (ec->expect_event == ACPI_EC_EVENT_IBE && + !(value & ACPI_EC_FLAG_IBF))) { + ec->expect_event = 0; + wake_up(&ec->wait); + + } + } + + if (value & ACPI_EC_FLAG_SCI){ + atomic_add(1, &ec->pending_gpe) ; + status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, + acpi_ec_gpe_query, ec); + } + + return status == AE_OK ? + ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } /* -------------------------------------------------------------------------- @@ -421,10 +582,8 @@ acpi_ec_space_setup ( * The EC object is in the handler context and is needed * when calling the acpi_ec_space_handler. */ - if(function == ACPI_REGION_DEACTIVATE) - *return_context = NULL; - else - *return_context = handler_context; + *return_context = (function != ACPI_REGION_DEACTIVATE) ? + handler_context : NULL; return AE_OK; } @@ -555,7 +714,7 @@ static int acpi_ec_add_fs ( struct acpi_device *device) { - struct proc_dir_entry *entry = NULL; + struct proc_dir_entry *entry; ACPI_FUNCTION_TRACE("acpi_ec_add_fs"); @@ -606,9 +765,9 @@ static int acpi_ec_add ( struct acpi_device *device) { - int result = 0; - acpi_status status = AE_OK; - struct acpi_ec *ec = NULL; + int result; + acpi_status status; + struct acpi_ec *ec; unsigned long uid; ACPI_FUNCTION_TRACE("acpi_ec_add"); @@ -623,7 +782,10 @@ acpi_ec_add ( ec->handle = device->handle; ec->uid = -1; - spin_lock_init(&ec->lock); + atomic_set(&ec->pending_gpe, 0); + atomic_set(&ec->leaving_burst , 1); + init_MUTEX(&ec->sem); + init_waitqueue_head(&ec->wait); strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); acpi_driver_data(device) = ec; @@ -637,7 +799,7 @@ acpi_ec_add ( if (ec_ecdt && ec_ecdt->uid == uid) { acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); - + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); kfree(ec_ecdt); @@ -677,7 +839,7 @@ acpi_ec_remove ( struct acpi_device *device, int type) { - struct acpi_ec *ec = NULL; + struct acpi_ec *ec; ACPI_FUNCTION_TRACE("acpi_ec_remove"); @@ -732,8 +894,8 @@ static int acpi_ec_start ( struct acpi_device *device) { - acpi_status status = AE_OK; - struct acpi_ec *ec = NULL; + acpi_status status; + struct acpi_ec *ec; ACPI_FUNCTION_TRACE("acpi_ec_start"); @@ -789,8 +951,8 @@ acpi_ec_stop ( struct acpi_device *device, int type) { - acpi_status status = AE_OK; - struct acpi_ec *ec = NULL; + acpi_status status; + struct acpi_ec *ec; ACPI_FUNCTION_TRACE("acpi_ec_stop"); @@ -832,7 +994,6 @@ acpi_fake_ecdt_callback ( status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe_bit); if (ACPI_FAILURE(status)) return status; - spin_lock_init(&ec_ecdt->lock); ec_ecdt->global_lock = TRUE; ec_ecdt->handle = handle; @@ -890,7 +1051,7 @@ acpi_ec_get_real_ecdt(void) acpi_status status; struct acpi_table_ecdt *ecdt_ptr; - status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, + status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, (struct acpi_table_header **) &ecdt_ptr); if (ACPI_FAILURE(status)) return -ENODEV; @@ -905,11 +1066,12 @@ acpi_ec_get_real_ecdt(void) return -ENOMEM; memset(ec_ecdt, 0, sizeof(struct acpi_ec)); + init_MUTEX(&ec_ecdt->sem); + init_waitqueue_head(&ec_ecdt->wait); ec_ecdt->command_addr = ecdt_ptr->ec_control; ec_ecdt->status_addr = ecdt_ptr->ec_control; ec_ecdt->data_addr = ecdt_ptr->ec_data; ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit; - spin_lock_init(&ec_ecdt->lock); /* use the GL just to be safe */ ec_ecdt->global_lock = TRUE; ec_ecdt->uid = ecdt_ptr->uid; @@ -978,7 +1140,7 @@ error: static int __init acpi_ec_init (void) { - int result = 0; + int result; ACPI_FUNCTION_TRACE("acpi_ec_init"); -- cgit v1.2.3 From fa9cd547e097df4966b8bd5c94aeed953e32b14d Mon Sep 17 00:00:00 2001 From: Luming Yu Date: Sat, 19 Mar 2005 01:54:47 -0500 Subject: [ACPI] fix EC access width http://bugzilla.kernel.org/show_bug.cgi?id=4346 Written-by: David Shaohua Li and Luming Yu Signed-off-by: Len Brown --- drivers/acpi/ec.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 69b04d430f0..e3716222934 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -600,7 +600,7 @@ acpi_ec_space_handler ( { int result = 0; struct acpi_ec *ec = NULL; - u32 temp = 0; + u64 temp = *value; acpi_integer f_v = 0; int i = 0; @@ -609,10 +609,9 @@ acpi_ec_space_handler ( if ((address > 0xFF) || !value || !handler_context) return_VALUE(AE_BAD_PARAMETER); - if(bit_width != 8) { + if (bit_width != 8 && acpi_strict) { printk(KERN_WARNING PREFIX "acpi_ec_space_handler: bit_width should be 8\n"); - if (acpi_strict) - return_VALUE(AE_BAD_PARAMETER); + return_VALUE(AE_BAD_PARAMETER); } ec = (struct acpi_ec *) handler_context; @@ -620,11 +619,11 @@ acpi_ec_space_handler ( next_byte: switch (function) { case ACPI_READ: - result = acpi_ec_read(ec, (u8) address, &temp); - *value = (acpi_integer) temp; + temp = 0; + result = acpi_ec_read(ec, (u8) address, (u32 *)&temp); break; case ACPI_WRITE: - result = acpi_ec_write(ec, (u8) address, (u8) *value); + result = acpi_ec_write(ec, (u8) address, (u8) temp); break; default: result = -EINVAL; @@ -633,19 +632,18 @@ next_byte: } bit_width -= 8; - if(bit_width){ - - if(function == ACPI_READ) - f_v |= (acpi_integer) (*value) << 8*i; - if(function == ACPI_WRITE) - (*value) >>=8; + if (bit_width) { + if (function == ACPI_READ) + f_v |= temp << 8 * i; + if (function == ACPI_WRITE) + temp >>= 8; i++; + (u8)address ++; goto next_byte; } - - if(function == ACPI_READ){ - f_v |= (acpi_integer) (*value) << 8*i; + if (function == ACPI_READ) { + f_v |= temp << 8 * i; *value = f_v; } @@ -664,8 +662,6 @@ out: default: return_VALUE(AE_OK); } - - } -- cgit v1.2.3 From a406d9e63e1d7088aad22565449de2e109300e5c Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 23 Mar 2005 16:16:03 -0500 Subject: [ACPI] gut acpi_pci_choose_state() to avoid conflict with pending pm_message_t re-definition. Signed-off-by: Len Brown --- drivers/pci/pci-acpi.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index a0d43ea872d..e9e37abe1f7 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -1,6 +1,6 @@ /* * File: pci-acpi.c - * Purpose: Provde PCI support in ACPI + * Purpose: Provide PCI support in ACPI * * Copyright (C) 2005 David Shaohua Li * Copyright (C) 2004 Tom Long Nguyen @@ -237,19 +237,8 @@ EXPORT_SYMBOL(pci_osc_control_set); static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) { - char dstate_str[] = "_S0D"; - acpi_status status; - unsigned long val; - struct device *dev = &pdev->dev; + /* TBD */ - /* Fixme: the check is wrong after pm_message_t is a struct */ - if ((state >= PM_SUSPEND_MAX) || !DEVICE_ACPI_HANDLE(dev)) - return -EINVAL; - dstate_str[2] += state; /* _S1D, _S2D, _S3D, _S4D */ - status = acpi_evaluate_integer(DEVICE_ACPI_HANDLE(dev), dstate_str, - NULL, &val); - if (ACPI_SUCCESS(status)) - return val; return -ENODEV; } -- cgit v1.2.3 From b008b8d7092053fc1f036cfc54dc11740cc424ed Mon Sep 17 00:00:00 2001 From: Matthieu Castet Date: Fri, 25 Mar 2005 12:03:15 -0500 Subject: [ACPI] PNPACPI parse error http://bugzilla.kernel.org/show_bug.cgi?id=3912 Written-by: matthieu castet Acked-by: Shaohua Li Signed-off-by: Len Brown --- drivers/pnp/pnpacpi/rsparser.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index dd61e09029b..ae3819ad7cf 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -444,6 +444,7 @@ pnpacpi_parse_fixed_mem32_option(struct pnp_option *option, struct acpipnp_parse_option_s { struct pnp_option *option; + struct pnp_option *option_independent; struct pnp_dev *dev; }; @@ -507,7 +508,14 @@ static acpi_status pnpacpi_option_resource(struct acpi_resource *res, parse_data->option = option; break; case ACPI_RSTYPE_END_DPF: - return AE_CTRL_TERMINATE; + /*only one EndDependentFn is allowed*/ + if (!parse_data->option_independent) { + pnp_warn("PnPACPI: more than one EndDependentFn"); + return AE_ERROR; + } + parse_data->option = parse_data->option_independent; + parse_data->option_independent = NULL; + break; default: pnp_warn("PnPACPI: unknown resource type %d", res->id); return AE_ERROR; @@ -525,6 +533,7 @@ acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle, parse_data.option = pnp_register_independent_option(dev); if (!parse_data.option) return AE_ERROR; + parse_data.option_independent = parse_data.option; parse_data.dev = dev; status = acpi_walk_resources(handle, METHOD_NAME__PRS, pnpacpi_option_resource, &parse_data); -- cgit v1.2.3 From f165b10f4a9aac7fee9b11a125de20a1712be128 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 30 Mar 2005 21:23:19 -0500 Subject: cleanup: remove unnecessary initializer on static pointers Suggested-by: Greg KH Signed-off-by: Len Brown --- drivers/pci/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a1c66e8ea5f..bdfca32b44a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -235,7 +235,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) * -EIO if device does not support PCI PM. * 0 if we can successfully change the power state. */ -int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t) = NULL; +int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { @@ -311,7 +311,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) return 0; } -int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state) = NULL; +int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state); /** * pci_choose_state - Choose the power state of a PCI device -- cgit v1.2.3 From 83ea7445221651dc43cf8d22f81089e0cbccf22b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 30 Mar 2005 22:12:13 -0500 Subject: [ACPI] fix build warning Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/ec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e3716222934..a4b70dfdcf0 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -638,7 +638,7 @@ next_byte: if (function == ACPI_WRITE) temp >>= 8; i++; - (u8)address ++; + address++; goto next_byte; } -- cgit v1.2.3 From f4224153098c1103db592b28f304beeb9c02481b Mon Sep 17 00:00:00 2001 From: Panagiotis Issaris Date: Wed, 30 Mar 2005 22:15:36 -0500 Subject: [ACPI] check for kmalloc failure in toshiba_acpi.c Signed-off-by: Panagiotis Issaris Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/toshiba_acpi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index bed8e53a5ee..73b1d8aeae9 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -263,6 +263,9 @@ dispatch_write(struct file* file, const char __user * buffer, * destination so that sscanf can be used on it safely. */ tmp_buffer = kmalloc(count + 1, GFP_KERNEL); + if(!tmp_buffer) + return -ENOMEM; + if (copy_from_user(tmp_buffer, buffer, count)) { result = -EFAULT; } -- cgit v1.2.3 From 7334571f724df7a19f48cc974e991e00afde1e2f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 30 Mar 2005 22:31:35 -0500 Subject: [ACPI] fix potential NULL dereference in acpi/video.c Found-by: Adrian Bunk Signed-off-by: Len Brown --- drivers/acpi/video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 71fa1011715..b3b352b8330 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1585,7 +1585,7 @@ acpi_video_switch_output( ACPI_FUNCTION_TRACE("acpi_video_switch_output"); list_for_each_safe(node, next, &video->video_device_list) { - struct acpi_video_device * dev = container_of(node, struct acpi_video_device, entry); + dev = container_of(node, struct acpi_video_device, entry); status = acpi_video_device_get_state(dev, &state); if (state & 0x2){ dev_next = container_of(node->next, struct acpi_video_device, entry); -- cgit v1.2.3 From d1dd0c23916bd781de27bc5ec1c295064e9ce9cc Mon Sep 17 00:00:00 2001 From: Paulo Marques Date: Wed, 30 Mar 2005 22:39:49 -0500 Subject: [ACPI] fix kmalloc size bug in acpi/video.c acpi_video_device_find_cap() used &p instead of *p when calculating storage size, thus allocating only 4 or 8 bytes instead of 12... Also, kfree(NULL) is legal, so remove some unneeded checks. From: Paulo Marques Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/video.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index b3b352b8330..2cf264fd52e 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -564,12 +564,13 @@ acpi_video_device_find_cap (struct acpi_video_device *device) int count = 0; union acpi_object *o; - br = kmalloc(sizeof &br, GFP_KERNEL); + br = kmalloc(sizeof(*br), GFP_KERNEL); if (!br) { printk(KERN_ERR "can't allocate memory\n"); } else { - memset(br, 0, sizeof &br); - br->levels = kmalloc(obj->package.count * sizeof &br->levels, GFP_KERNEL); + memset(br, 0, sizeof(*br)); + br->levels = kmalloc(obj->package.count * + sizeof *(br->levels), GFP_KERNEL); if (!br->levels) goto out; @@ -584,8 +585,7 @@ acpi_video_device_find_cap (struct acpi_video_device *device) } out: if (count < 2) { - if (br->levels) - kfree(br->levels); + kfree(br->levels); kfree(br); } else { br->count = count; @@ -595,8 +595,7 @@ out: } } - if (obj) - kfree(obj); + kfree(obj); return_VOID; } -- cgit v1.2.3 From 8de7a63b69a263b7549599be882d7aa15397f8b3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 30 Mar 2005 22:53:30 -0500 Subject: [ACPI] fix debug-mode build warning in acpi/hotkey.c drivers/acpi/hotkey.c: In function `create_polling_proc': drivers/acpi/hotkey.c:334: warning: ISO C90 forbids mixed declarations and code Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/hotkey.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c index 0aef9fc449c..babdf762ead 100644 --- a/drivers/acpi/hotkey.c +++ b/drivers/acpi/hotkey.c @@ -329,9 +329,10 @@ static int auto_hotkey_remove(struct acpi_device *device, int type) static int create_polling_proc(union acpi_hotkey *device) { struct proc_dir_entry *proc; + mode_t mode; ACPI_FUNCTION_TRACE("create_polling_proc"); - mode_t mode = S_IFREG | S_IRUGO | S_IWUGO; + mode = S_IFREG | S_IRUGO | S_IWUGO; proc = create_proc_entry(device->poll_hotkey.action_method, mode, hotkey_proc_dir); -- cgit v1.2.3 From 6940fabaa35b893163b7043d0d1dc5d715f9e1ca Mon Sep 17 00:00:00 2001 From: Keiichiro Tokunaga Date: Wed, 30 Mar 2005 23:15:47 -0500 Subject: [ACPI] hotplug Processor consideration in acpi_bus_add() Signed-off-by: Keiichiro Tokunaga Signed-off-by: Len Brown --- drivers/acpi/scan.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 119c94093a1..7c26fed0bdf 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1051,13 +1051,15 @@ acpi_bus_add ( /* * Status * ------ - * See if the device is present. We always assume that non-Device() - * objects (e.g. thermal zones, power resources, processors, etc.) are - * present, functioning, etc. (at least when parent object is present). - * Note that _STA has a different meaning for some objects (e.g. - * power resources) so we need to be careful how we use it. + * See if the device is present. We always assume that non-Device + * and non-Processor objects (e.g. thermal zones, power resources, + * etc.) are present, functioning, etc. (at least when parent object + * is present). Note that _STA has a different meaning for some + * objects (e.g. power resources) so we need to be careful how we use + * it. */ switch (type) { + case ACPI_BUS_TYPE_PROCESSOR: case ACPI_BUS_TYPE_DEVICE: result = acpi_bus_get_status(device); if (ACPI_FAILURE(result) || !device->status.present) { -- cgit v1.2.3 From acf05f4b7f558051ea0028e8e617144123650272 Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Thu, 31 Mar 2005 23:23:15 -0500 Subject: [ACPI] update /proc/acpi/processor/*/power even if only C1 support Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index ff64d333e95..79d5ca3066c 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -519,6 +519,29 @@ static int acpi_processor_get_power_info_fadt (struct acpi_processor *pr) } +static int acpi_processor_get_power_info_default_c1 (struct acpi_processor *pr) +{ + int i; + + ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_default_c1"); + + for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++) + memset(pr->power.states, 0, sizeof(struct acpi_processor_cx)); + + /* if info is obtained from pblk/fadt, type equals state */ + pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; + pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2; + pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3; + + /* the C0 state only exists as a filler in our array, + * and all processors need to support C1 */ + pr->power.states[ACPI_STATE_C0].valid = 1; + pr->power.states[ACPI_STATE_C1].valid = 1; + + return_VALUE(0); +} + + static int acpi_processor_get_power_info_cst (struct acpi_processor *pr) { acpi_status status = 0; @@ -787,10 +810,7 @@ static int acpi_processor_get_power_info ( if ((result) || (acpi_processor_power_verify(pr) < 2)) { result = acpi_processor_get_power_info_fadt(pr); if (result) - return_VALUE(result); - - if (acpi_processor_power_verify(pr) < 2) - return_VALUE(-ENODEV); + result = acpi_processor_get_power_info_default_c1(pr); } /* @@ -810,11 +830,10 @@ static int acpi_processor_get_power_info ( * CPU as being "idle manageable" */ for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { - if (pr->power.states[i].valid) + if (pr->power.states[i].valid) { pr->power.count = i; - if ((pr->power.states[i].valid) && - (pr->power.states[i].type >= ACPI_STATE_C2)) pr->flags.power = 1; + } } return_VALUE(0); -- cgit v1.2.3 From c9c3e457de24cca2ca688fa397d93a241f472048 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Fri, 1 Apr 2005 00:07:31 -0500 Subject: [ACPI] PNPACPI vs sound IRQ http://bugme.osdl.org/show_bug.cgi?id=4016 Written-by: David Shaohua Li Acked-by: Adam Belay Signed-off-by: Len Brown --- drivers/acpi/pci_link.c | 7 +++++-- drivers/pnp/pnpacpi/rsparser.c | 4 ++-- drivers/pnp/pnpbios/rsparser.c | 2 +- drivers/pnp/resource.c | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index f2271173bbd..6ad0e77df9b 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -804,9 +804,12 @@ static int __init acpi_irq_penalty_update(char *str, int used) * There is no ISA_POSSIBLE weight, so we simply use * the (small) PCI_USING penalty. */ -void acpi_penalize_isa_irq(int irq) +void acpi_penalize_isa_irq(int irq, int active) { - acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; + if (active) + acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; + else + acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; } /* diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index ae3819ad7cf..75575f6c349 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -160,7 +160,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, acpi_register_gsi(res->data.irq.interrupts[0], res->data.irq.edge_level, res->data.irq.active_high_low)); - pcibios_penalize_isa_irq(res->data.irq.interrupts[0]); + pcibios_penalize_isa_irq(res->data.irq.interrupts[0], 1); } break; @@ -171,7 +171,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, acpi_register_gsi(res->data.extended_irq.interrupts[0], res->data.extended_irq.edge_level, res->data.extended_irq.active_high_low)); - pcibios_penalize_isa_irq(res->data.extended_irq.interrupts[0]); + pcibios_penalize_isa_irq(res->data.extended_irq.interrupts[0], 1); } break; case ACPI_RSTYPE_DMA: diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c index 79bce7b7574..9001b6f0204 100644 --- a/drivers/pnp/pnpbios/rsparser.c +++ b/drivers/pnp/pnpbios/rsparser.c @@ -64,7 +64,7 @@ pnpbios_parse_allocated_irqresource(struct pnp_resource_table * res, int irq) } res->irq_resource[i].start = res->irq_resource[i].end = (unsigned long) irq; - pcibios_penalize_isa_irq(irq); + pcibios_penalize_isa_irq(irq, 1); } } diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index 2d1322dd7e1..887ad893934 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -102,7 +102,7 @@ int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) for (i = 0; i < 16; i++) if (test_bit(i, data->map)) - pcibios_penalize_isa_irq(i); + pcibios_penalize_isa_irq(i, 0); } #endif return 0; -- cgit v1.2.3 From d5950b4355049092739bea97d1bdc14433126cc5 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Mon, 11 Jul 2005 21:03:49 -0700 Subject: [NET]: add a top-level Networking menu to *config Create a new top-level menu named "Networking" thus moving net related options and protocol selection way from the drivers menu and up on the top-level where they belong. To implement this all architectures has to source "net/Kconfig" before drivers/*/Kconfig in their Kconfig file. This change has been implemented for all architectures. Device drivers for ordinary NIC's are still to be found in the Device Drivers section, but Bluetooth, IrDA and ax25 are located with their corresponding menu entries under the new networking menu item. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller --- drivers/Kconfig | 2 +- drivers/net/Kconfig | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index aed4a9b97c1..34efb2150e6 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -28,7 +28,7 @@ source "drivers/message/i2o/Kconfig" source "drivers/macintosh/Kconfig" -source "net/Kconfig" +source "drivers/net/Kconfig" source "drivers/isdn/Kconfig" diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 2b55687f6ee..9a07ff7a777 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -3,6 +3,8 @@ # Network device configuration # +menu "Network device support" + config NETDEVICES depends on NET bool "Network device support" @@ -2547,3 +2549,4 @@ config NETCONSOLE If you want to log kernel messages over the network, enable this. See for details. +endmenu -- cgit v1.2.3 From ebb6e1a6122fd6b7c96470cfd4ce0f04150e5084 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 14 Apr 2005 23:12:56 -0400 Subject: [ACPI] Deprecate /proc/acpi/sleep in favor of /sys/power/state Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 8 ++++++++ drivers/acpi/sleep/proc.c | 9 +++++++++ 2 files changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index fa7f4345189..8b6de146255 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -80,6 +80,14 @@ config ACPI_SLEEP_PROC_FS depends on ACPI_SLEEP && PROC_FS default y +config ACPI_SLEEP_PROC_SLEEP + bool "/proc/acpi/sleep (deprecated)" + depends on ACPI_SLEEP_PROC_FS + default n + ---help--- + Create /proc/acpi/sleep + Deprecated by /sys/power/state + config ACPI_AC tristate "AC Adapter" depends on X86 diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index fd7c5a0649a..1be99f0996d 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -13,13 +13,17 @@ #include "sleep.h" +#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP #define ACPI_SYSTEM_FILE_SLEEP "sleep" +#endif + #define ACPI_SYSTEM_FILE_ALARM "alarm" #define ACPI_SYSTEM_FILE_WAKEUP_DEVICE "wakeup" #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME ("sleep") +#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) { @@ -78,6 +82,7 @@ acpi_system_write_sleep ( Done: return error ? error : count; } +#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) { @@ -452,6 +457,7 @@ static struct file_operations acpi_system_wakeup_device_fops = { .release = single_release, }; +#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP static struct file_operations acpi_system_sleep_fops = { .open = acpi_system_sleep_open_fs, .read = seq_read, @@ -459,6 +465,7 @@ static struct file_operations acpi_system_sleep_fops = { .llseek = seq_lseek, .release = single_release, }; +#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ static struct file_operations acpi_system_alarm_fops = { .open = acpi_system_alarm_open_fs, @@ -484,11 +491,13 @@ static int acpi_sleep_proc_init(void) if (acpi_disabled) return 0; +#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP /* 'sleep' [R/W]*/ entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP, S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); if (entry) entry->proc_fops = &acpi_system_sleep_fops; +#endif /* 'alarm' [R/W] */ entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM, -- cgit v1.2.3 From 44f6c01242da4e162f28d8e1216a8c7a91174605 Mon Sep 17 00:00:00 2001 From: Robert Moore Date: Mon, 18 Apr 2005 22:49:35 -0400 Subject: ACPICA 20050408 from Bob Moore Fixed three cases in the interpreter where an "index" argument to an ASL function was still (internally) 32 bits instead of the required 64 bits. This was the Index argument to the Index, Mid, and Match operators. The "strupr" function is now permanently local (acpi_ut_strupr), since this is not a POSIX-defined function and not present in most kernel-level C libraries. References to the C library strupr function have been removed from the headers. Completed the deployment of static functions/prototypes. All prototypes with the static attribute have been moved from the headers to the owning C file. ACPICA 20050329 from Bob Moore An error is now generated if an attempt is made to create a Buffer Field of length zero (A CreateField with a length operand of zero.) The interpreter now issues a warning whenever executable code at the module level is detected during ACPI table load. This will give some idea of the prevalence of this type of code. Implemented support for references to named objects (other than control methods) within package objects. Enhanced package object output for the debug object. Package objects are now completely dumped, showing all elements. Enhanced miscellaneous object output for the debug object. Any object can now be written to the debug object (for example, a device object can be written, and the type of the object will be displayed.) The "static" qualifier has been added to all local functions across the core subsystem. The number of "long" lines (> 80 chars) within the source has been significantly reduced, by about 1/3. Cleaned up all header files to ensure that all CA/iASL functions are prototyped (even static functions) and the formatting is consistent. Two new header files have been added, acopcode.h and acnames.h. Removed several obsolete functions that were no longer used. Signed-off-by: Len Brown --- drivers/acpi/dispatcher/dsfield.c | 58 +++-- drivers/acpi/dispatcher/dsinit.c | 28 ++- drivers/acpi/dispatcher/dsmethod.c | 11 +- drivers/acpi/dispatcher/dsmthdat.c | 195 ++++++++------- drivers/acpi/dispatcher/dsobject.c | 79 +++--- drivers/acpi/dispatcher/dsopcode.c | 105 +++++--- drivers/acpi/dispatcher/dsutils.c | 41 ++-- drivers/acpi/dispatcher/dswexec.c | 57 +++-- drivers/acpi/dispatcher/dswload.c | 118 +++++---- drivers/acpi/dispatcher/dswscope.c | 31 ++- drivers/acpi/dispatcher/dswstate.c | 458 ++++++++++++++++++----------------- drivers/acpi/events/evevent.c | 33 ++- drivers/acpi/events/evgpe.c | 39 ++- drivers/acpi/events/evgpeblk.c | 63 ++++- drivers/acpi/events/evmisc.c | 97 +++++--- drivers/acpi/events/evregion.c | 35 ++- drivers/acpi/events/evrgnini.c | 14 +- drivers/acpi/events/evsci.c | 12 +- drivers/acpi/events/evxface.c | 19 +- drivers/acpi/events/evxfevnt.c | 25 +- drivers/acpi/executer/exconfig.c | 31 ++- drivers/acpi/executer/exconvrt.c | 44 ++-- drivers/acpi/executer/excreate.c | 50 ++-- drivers/acpi/executer/exdump.c | 105 +++++--- drivers/acpi/executer/exfield.c | 25 +- drivers/acpi/executer/exfldio.c | 133 ++++++---- drivers/acpi/executer/exmisc.c | 7 +- drivers/acpi/executer/exmutex.c | 45 ++-- drivers/acpi/executer/exnames.c | 70 ++++-- drivers/acpi/executer/exoparg1.c | 94 +++++--- drivers/acpi/executer/exoparg2.c | 69 +++--- drivers/acpi/executer/exoparg3.c | 25 +- drivers/acpi/executer/exoparg6.c | 26 +- drivers/acpi/executer/exprep.c | 104 +++++--- drivers/acpi/executer/exregion.c | 34 ++- drivers/acpi/executer/exresnte.c | 24 +- drivers/acpi/executer/exresolv.c | 63 +++-- drivers/acpi/executer/exresop.c | 80 ++++--- drivers/acpi/executer/exstore.c | 260 ++++++++++++++------ drivers/acpi/executer/exstoren.c | 20 +- drivers/acpi/executer/exstorob.c | 9 +- drivers/acpi/executer/exsystem.c | 48 ++-- drivers/acpi/executer/exutils.c | 37 ++- drivers/acpi/hardware/hwacpi.c | 19 +- drivers/acpi/hardware/hwgpe.c | 31 ++- drivers/acpi/hardware/hwregs.c | 114 +++++---- drivers/acpi/hardware/hwsleep.c | 101 ++++---- drivers/acpi/hardware/hwtimer.c | 4 +- drivers/acpi/namespace/nsaccess.c | 5 +- drivers/acpi/namespace/nsalloc.c | 121 +++++----- drivers/acpi/namespace/nsdump.c | 109 +++++---- drivers/acpi/namespace/nsdumpdv.c | 18 +- drivers/acpi/namespace/nseval.c | 70 ++++-- drivers/acpi/namespace/nsinit.c | 28 ++- drivers/acpi/namespace/nsload.c | 28 ++- drivers/acpi/namespace/nsnames.c | 12 +- drivers/acpi/namespace/nsobject.c | 14 +- drivers/acpi/namespace/nssearch.c | 29 ++- drivers/acpi/namespace/nsutils.c | 167 +++++++------ drivers/acpi/namespace/nswalk.c | 2 +- drivers/acpi/namespace/nsxfeval.c | 16 +- drivers/acpi/namespace/nsxfname.c | 8 +- drivers/acpi/namespace/nsxfobj.c | 4 +- drivers/acpi/parser/psargs.c | 55 +++-- drivers/acpi/parser/psopcode.c | 298 +---------------------- drivers/acpi/parser/psparse.c | 144 +++++++---- drivers/acpi/parser/psscope.c | 45 ++-- drivers/acpi/parser/pstree.c | 159 ++++++------ drivers/acpi/parser/psutils.c | 15 +- drivers/acpi/parser/pswalk.c | 11 +- drivers/acpi/parser/psxface.c | 21 +- drivers/acpi/resources/rsaddr.c | 480 ++++++++++++++++--------------------- drivers/acpi/resources/rscalc.c | 144 ++++++----- drivers/acpi/resources/rscreate.c | 45 ++-- drivers/acpi/resources/rsdump.c | 402 ++++++++++++++++--------------- drivers/acpi/resources/rsio.c | 197 +++++++-------- drivers/acpi/resources/rsirq.c | 167 ++++++------- drivers/acpi/resources/rslist.c | 68 +++--- drivers/acpi/resources/rsmemory.c | 236 ++++++++---------- drivers/acpi/resources/rsmisc.c | 160 +++++-------- drivers/acpi/resources/rsutils.c | 53 ++-- drivers/acpi/resources/rsxface.c | 43 ++-- drivers/acpi/tables/tbconvrt.c | 105 +++++--- drivers/acpi/tables/tbget.c | 63 +++-- drivers/acpi/tables/tbgetall.c | 45 ++-- drivers/acpi/tables/tbinstal.c | 31 ++- drivers/acpi/tables/tbrsdt.c | 19 +- drivers/acpi/tables/tbutils.c | 97 ++++---- drivers/acpi/tables/tbxface.c | 39 ++- drivers/acpi/tables/tbxfroot.c | 123 ++++++---- drivers/acpi/utilities/utalloc.c | 84 +++++-- drivers/acpi/utilities/utcopy.c | 126 +++++++--- drivers/acpi/utilities/utdebug.c | 106 ++++---- drivers/acpi/utilities/utdelete.c | 63 +++-- drivers/acpi/utilities/uteval.c | 36 ++- drivers/acpi/utilities/utglobal.c | 133 +++++----- drivers/acpi/utilities/utinit.c | 36 ++- drivers/acpi/utilities/utmath.c | 2 + drivers/acpi/utilities/utmisc.c | 187 ++++++++------- drivers/acpi/utilities/utobject.c | 68 ++++-- drivers/acpi/utilities/utxface.c | 61 +++-- 101 files changed, 4390 insertions(+), 3598 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c index 2779211be75..84193983d6b 100644 --- a/drivers/acpi/dispatcher/dsfield.c +++ b/drivers/acpi/dispatcher/dsfield.c @@ -53,13 +53,20 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsfield") +/* Local prototypes */ + +static acpi_status +acpi_ds_get_field_names ( + struct acpi_create_field_info *info, + struct acpi_walk_state *walk_state, + union acpi_parse_object *arg); + /******************************************************************************* * * FUNCTION: acpi_ds_create_buffer_field * - * PARAMETERS: Opcode - The opcode to be executed - * Operands - List of operands for the opcode + * PARAMETERS: Op - Current parse op (create_xXField) * walk_state - Current state * * RETURN: Status @@ -70,7 +77,7 @@ * create_word_field_op, * create_dword_field_op, * create_qword_field_op, - * create_field_op (all of which define fields in buffers) + * create_field_op (all of which define a field in a buffer) * ******************************************************************************/ @@ -119,7 +126,8 @@ acpi_ds_create_buffer_field ( flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE; } else { - flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND; + flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | + ACPI_NS_ERROR_IF_FOUND; } /* @@ -134,16 +142,16 @@ acpi_ds_create_buffer_field ( } } - /* We could put the returned object (Node) on the object stack for later, but - * for now, we will put it in the "op" object that the parser uses, so we - * can get it again at the end of this scope + /* We could put the returned object (Node) on the object stack for later, + * but for now, we will put it in the "op" object that the parser uses, + * so we can get it again at the end of this scope */ op->common.node = node; /* - * If there is no object attached to the node, this node was just created and - * we need to create the field object. Otherwise, this was a lookup of an - * existing node and we don't want to create the field object again. + * If there is no object attached to the node, this node was just created + * and we need to create the field object. Otherwise, this was a lookup + * of an existing node and we don't want to create the field object again. */ obj_desc = acpi_ns_get_attached_object (node); if (obj_desc) { @@ -205,7 +213,7 @@ cleanup: * ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_get_field_names ( struct acpi_create_field_info *info, struct acpi_walk_state *walk_state, @@ -238,7 +246,8 @@ acpi_ds_get_field_names ( + (acpi_integer) arg->common.value.size; if (position > ACPI_UINT32_MAX) { - ACPI_REPORT_ERROR (("Bit offset within field too large (> 0xFFFFFFFF)\n")); + ACPI_REPORT_ERROR (( + "Bit offset within field too large (> 0xFFFFFFFF)\n")); return_ACPI_STATUS (AE_SUPPORT); } @@ -250,12 +259,15 @@ acpi_ds_get_field_names ( /* * Get a new access_type and access_attribute -- to be used for all - * field units that follow, until field end or another access_as keyword. + * field units that follow, until field end or another access_as + * keyword. * - * In field_flags, preserve the flag bits other than the ACCESS_TYPE bits + * In field_flags, preserve the flag bits other than the + * ACCESS_TYPE bits */ - info->field_flags = (u8) ((info->field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | - ((u8) ((u32) arg->common.value.integer >> 8))); + info->field_flags = (u8) + ((info->field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | + ((u8) ((u32) arg->common.value.integer >> 8))); info->attribute = (u8) (arg->common.value.integer); break; @@ -267,7 +279,8 @@ acpi_ds_get_field_names ( status = acpi_ns_lookup (walk_state->scope_info, (char *) &arg->named.name, - info->field_type, ACPI_IMODE_EXECUTE, ACPI_NS_DONT_OPEN_SCOPE, + info->field_type, ACPI_IMODE_EXECUTE, + ACPI_NS_DONT_OPEN_SCOPE, walk_state, &info->field_node); if (ACPI_FAILURE (status)) { ACPI_REPORT_NSERROR ((char *) &arg->named.name, status); @@ -295,8 +308,9 @@ acpi_ds_get_field_names ( + (acpi_integer) arg->common.value.size; if (position > ACPI_UINT32_MAX) { - ACPI_REPORT_ERROR (("Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n", - (char *) &info->field_node->name)); + ACPI_REPORT_ERROR (( + "Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n", + (char *) &info->field_node->name)); return_ACPI_STATUS (AE_SUPPORT); } @@ -306,7 +320,8 @@ acpi_ds_get_field_names ( default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid opcode in field list: %X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Invalid opcode in field list: %X\n", arg->common.aml_opcode)); return_ACPI_STATUS (AE_AML_BAD_OPCODE); } @@ -435,7 +450,8 @@ acpi_ds_init_field_objects ( status = acpi_ns_lookup (walk_state->scope_info, (char *) &arg->named.name, type, ACPI_IMODE_LOAD_PASS1, - ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, + ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | + ACPI_NS_ERROR_IF_FOUND, walk_state, &node); if (ACPI_FAILURE (status)) { ACPI_REPORT_NSERROR ((char *) &arg->named.name, status); diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c index b4d264dbbf6..d7790db5017 100644 --- a/drivers/acpi/dispatcher/dsinit.c +++ b/drivers/acpi/dispatcher/dsinit.c @@ -49,12 +49,21 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsinit") +/* Local prototypes */ + +static acpi_status +acpi_ds_init_one_object ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); + /******************************************************************************* * * FUNCTION: acpi_ds_init_one_object * - * PARAMETERS: obj_handle - Node + * PARAMETERS: obj_handle - Node for the object * Level - Current nesting level * Context - Points to a init info struct * return_value - Not used @@ -70,7 +79,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_init_one_object ( acpi_handle obj_handle, u32 level, @@ -105,7 +114,8 @@ acpi_ds_init_one_object ( status = acpi_ds_initialize_region (obj_handle); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %p [%4.4s] - Init failure, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Region %p [%4.4s] - Init failure, %s\n", obj_handle, acpi_ut_get_node_name (obj_handle), acpi_format_exception (status))); } @@ -118,8 +128,10 @@ acpi_ds_init_one_object ( info->method_count++; - /* Print a dot for each method unless we are going to print the entire pathname */ - + /* + * Print a dot for each method unless we are going to print + * the entire pathname + */ if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) { ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); } @@ -140,7 +152,8 @@ acpi_ds_init_one_object ( */ status = acpi_ds_parse_method (obj_handle); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Method %p [%4.4s] - parse failure, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Method %p [%4.4s] - parse failure, %s\n", obj_handle, acpi_ut_get_node_name (obj_handle), acpi_format_exception (status))); @@ -154,7 +167,8 @@ acpi_ds_init_one_object ( * for every execution since there isn't much overhead */ acpi_ns_delete_namespace_subtree (obj_handle); - acpi_ns_delete_namespace_by_owner (((struct acpi_namespace_node *) obj_handle)->object->method.owning_id); + acpi_ns_delete_namespace_by_owner ( + ((struct acpi_namespace_node *) obj_handle)->object->method.owning_id); break; diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 9f0456cb9bb..9fc3f4c033e 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -153,12 +153,11 @@ acpi_ds_parse_method ( /* * Parse the method, first pass * - * The first pass load is where newly declared named objects are - * added into the namespace. Actual evaluation of - * the named objects (what would be called a "second - * pass") happens during the actual execution of the - * method so that operands to the named objects can - * take on dynamic run-time values. + * The first pass load is where newly declared named objects are added into + * the namespace. Actual evaluation of the named objects (what would be + * called a "second pass") happens during the actual execution of the + * method so that operands to the named objects can take on dynamic + * run-time values. */ status = acpi_ps_parse_aml (walk_state); if (ACPI_FAILURE (status)) { diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index f31d095f983..f7998306f75 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -52,6 +52,29 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsmthdat") +/* Local prototypes */ + +static void +acpi_ds_method_data_delete_value ( + u16 opcode, + u32 index, + struct acpi_walk_state *walk_state); + +static acpi_status +acpi_ds_method_data_set_value ( + u16 opcode, + u32 index, + union acpi_operand_object *object, + struct acpi_walk_state *walk_state); + +#ifdef ACPI_OBSOLETE_FUNCTIONS +acpi_object_type +acpi_ds_method_data_get_type ( + u16 opcode, + u32 index, + struct acpi_walk_state *walk_state); +#endif + /******************************************************************************* * @@ -62,8 +85,8 @@ * RETURN: Status * * DESCRIPTION: Initialize the data structures that hold the method's arguments - * and locals. The data struct is an array of NTEs for each. - * This allows ref_of and de_ref_of to work properly for these + * and locals. The data struct is an array of namespace nodes for + * each - this allows ref_of and de_ref_of to work properly for these * special data types. * * NOTES: walk_state fields are initialized to zero by the @@ -92,7 +115,8 @@ acpi_ds_method_data_init ( walk_state->arguments[i].name.integer |= (i << 24); walk_state->arguments[i].descriptor = ACPI_DESC_TYPE_NAMED; walk_state->arguments[i].type = ACPI_TYPE_ANY; - walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG; + walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | + ANOBJ_METHOD_ARG; } /* Init the method locals */ @@ -104,7 +128,8 @@ acpi_ds_method_data_init ( walk_state->local_variables[i].name.integer |= (i << 24); walk_state->local_variables[i].descriptor = ACPI_DESC_TYPE_NAMED; walk_state->local_variables[i].type = ACPI_TYPE_ANY; - walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL; + walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | + ANOBJ_METHOD_LOCAL; } return_VOID; @@ -198,15 +223,18 @@ acpi_ds_method_data_init_args ( return_ACPI_STATUS (AE_OK); } - /* Copy passed parameters into the new method stack frame */ + /* Copy passed parameters into the new method stack frame */ - while ((index < ACPI_METHOD_NUM_ARGS) && (index < max_param_count) && params[index]) { + while ((index < ACPI_METHOD_NUM_ARGS) && + (index < max_param_count) && + params[index]) { /* * A valid parameter. * Store the argument in the method/walk descriptor. * Do not copy the arg in order to implement call by reference */ - status = acpi_ds_method_data_set_value (AML_ARG_OP, index, params[index], walk_state); + status = acpi_ds_method_data_set_value (AML_ARG_OP, index, + params[index], walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -224,11 +252,13 @@ acpi_ds_method_data_init_args ( * FUNCTION: acpi_ds_method_data_get_node * * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - which local_var or argument whose type - * to get + * Index - Which Local or Arg whose type to get * walk_state - Current walk state object + * Node - Where the node is returned. * - * RETURN: Get the Node associated with a local or arg. + * RETURN: Status and node + * + * DESCRIPTION: Get the Node associated with a local or arg. * ******************************************************************************/ @@ -249,7 +279,8 @@ acpi_ds_method_data_get_node ( case AML_LOCAL_OP: if (index > ACPI_METHOD_MAX_LOCAL) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Local index %d is invalid (max %d)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Local index %d is invalid (max %d)\n", index, ACPI_METHOD_MAX_LOCAL)); return_ACPI_STATUS (AE_AML_INVALID_INDEX); } @@ -262,7 +293,8 @@ acpi_ds_method_data_get_node ( case AML_ARG_OP: if (index > ACPI_METHOD_MAX_ARG) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Arg index %d is invalid (max %d)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Arg index %d is invalid (max %d)\n", index, ACPI_METHOD_MAX_ARG)); return_ACPI_STATUS (AE_AML_INVALID_INDEX); } @@ -286,7 +318,7 @@ acpi_ds_method_data_get_node ( * FUNCTION: acpi_ds_method_data_set_value * * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - which local_var or argument to get + * Index - Which Local or Arg to get * Object - Object to be inserted into the stack entry * walk_state - Current walk state object * @@ -297,7 +329,7 @@ acpi_ds_method_data_get_node ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_method_data_set_value ( u16 opcode, u32 index, @@ -338,56 +370,6 @@ acpi_ds_method_data_set_value ( } -/******************************************************************************* - * - * FUNCTION: acpi_ds_method_data_get_type - * - * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - which local_var or argument whose type - * to get - * walk_state - Current walk state object - * - * RETURN: Data type of current value of the selected Arg or Local - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE -acpi_object_type -acpi_ds_method_data_get_type ( - u16 opcode, - u32 index, - struct acpi_walk_state *walk_state) -{ - acpi_status status; - struct acpi_namespace_node *node; - union acpi_operand_object *object; - - - ACPI_FUNCTION_TRACE ("ds_method_data_get_type"); - - - /* Get the namespace node for the arg/local */ - - status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); - if (ACPI_FAILURE (status)) { - return_VALUE ((ACPI_TYPE_NOT_FOUND)); - } - - /* Get the object */ - - object = acpi_ns_get_attached_object (node); - if (!object) { - /* Uninitialized local/arg, return TYPE_ANY */ - - return_VALUE (ACPI_TYPE_ANY); - } - - /* Get the object type */ - - return_VALUE (ACPI_GET_OBJECT_TYPE (object)); -} -#endif /* ACPI_FUTURE_USAGE */ - - /******************************************************************************* * * FUNCTION: acpi_ds_method_data_get_value @@ -395,13 +377,11 @@ acpi_ds_method_data_get_type ( * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP * Index - which local_var or argument to get * walk_state - Current walk state object - * *dest_desc - Ptr to Descriptor into which selected Arg - * or Local value should be copied + * dest_desc - Where Arg or Local value is returned * * RETURN: Status * - * DESCRIPTION: Retrieve value of selected Arg or Local from the method frame - * at the current top of the method stack. + * DESCRIPTION: Retrieve value of selected Arg or Local for this method * Used only in acpi_ex_resolve_to_value(). * ******************************************************************************/ @@ -467,14 +447,16 @@ acpi_ds_method_data_get_value ( else switch (opcode) { case AML_ARG_OP: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Arg[%d] at node %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Uninitialized Arg[%d] at node %p\n", index, node)); return_ACPI_STATUS (AE_AML_UNINITIALIZED_ARG); case AML_LOCAL_OP: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Local[%d] at node %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Uninitialized Local[%d] at node %p\n", index, node)); return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL); @@ -506,12 +488,12 @@ acpi_ds_method_data_get_value ( * * RETURN: None * - * DESCRIPTION: Delete the entry at Opcode:Index on the method stack. Inserts + * DESCRIPTION: Delete the entry at Opcode:Index. Inserts * a null into the stack slot after the object is deleted. * ******************************************************************************/ -void +static void acpi_ds_method_data_delete_value ( u16 opcode, u32 index, @@ -562,7 +544,7 @@ acpi_ds_method_data_delete_value ( * FUNCTION: acpi_ds_store_object_to_local * * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP - * Index - which local_var or argument to set + * Index - Which Local or Arg to set * obj_desc - Value to be stored * walk_state - Current walk state * @@ -651,19 +633,20 @@ acpi_ds_store_object_to_local ( */ if (opcode == AML_ARG_OP) { /* - * Make sure that the object is the correct type. This may be overkill, but - * it is here because references were NS nodes in the past. Now they are - * operand objects of type Reference. + * Make sure that the object is the correct type. This may be + * overkill, butit is here because references were NS nodes in + * the past. Now they are operand objects of type Reference. */ if (ACPI_GET_DESCRIPTOR_TYPE (current_obj_desc) != ACPI_DESC_TYPE_OPERAND) { - ACPI_REPORT_ERROR (("Invalid descriptor type while storing to method arg: [%s]\n", - acpi_ut_get_descriptor_name (current_obj_desc))); + ACPI_REPORT_ERROR (( + "Invalid descriptor type while storing to method arg: [%s]\n", + acpi_ut_get_descriptor_name (current_obj_desc))); return_ACPI_STATUS (AE_AML_INTERNAL); } /* - * If we have a valid reference object that came from ref_of(), do the - * indirect store + * If we have a valid reference object that came from ref_of(), + * do the indirect store */ if ((current_obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) && (current_obj_desc->reference.opcode == AML_REF_OF_OP)) { @@ -713,3 +696,55 @@ acpi_ds_store_object_to_local ( } +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: acpi_ds_method_data_get_type + * + * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - Which Local or Arg whose type to get + * walk_state - Current walk state object + * + * RETURN: Data type of current value of the selected Arg or Local + * + * DESCRIPTION: Get the type of the object stored in the Local or Arg + * + ******************************************************************************/ + +acpi_object_type +acpi_ds_method_data_get_type ( + u16 opcode, + u32 index, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + struct acpi_namespace_node *node; + union acpi_operand_object *object; + + + ACPI_FUNCTION_TRACE ("ds_method_data_get_type"); + + + /* Get the namespace node for the arg/local */ + + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); + if (ACPI_FAILURE (status)) { + return_VALUE ((ACPI_TYPE_NOT_FOUND)); + } + + /* Get the object */ + + object = acpi_ns_get_attached_object (node); + if (!object) { + /* Uninitialized local/arg, return TYPE_ANY */ + + return_VALUE (ACPI_TYPE_ANY); + } + + /* Get the object type */ + + return_VALUE (ACPI_GET_OBJECT_TYPE (object)); +} +#endif + + diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index eb8af4785bc..bfbae4e4c66 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c @@ -52,9 +52,15 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsobject") +static acpi_status +acpi_ds_build_internal_object ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + union acpi_operand_object **obj_desc_ptr); + #ifndef ACPI_NO_METHOD_EXECUTION -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_build_internal_object * @@ -67,9 +73,9 @@ * DESCRIPTION: Translate a parser Op object to the equivalent namespace object * Simple objects are any objects other than a package object! * - ****************************************************************************/ + ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_build_internal_object ( struct acpi_walk_state *walk_state, union acpi_parse_object *op, @@ -90,9 +96,11 @@ acpi_ds_build_internal_object ( * Otherwise, go ahead and look it up now */ if (!op->common.node) { - status = acpi_ns_lookup (walk_state->scope_info, op->common.value.string, + status = acpi_ns_lookup (walk_state->scope_info, + op->common.value.string, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, - ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + NULL, (struct acpi_namespace_node **) &(op->common.node)); if (ACPI_FAILURE (status)) { @@ -104,12 +112,14 @@ acpi_ds_build_internal_object ( /* Create and init the internal ACPI object */ - obj_desc = acpi_ut_create_internal_object ((acpi_ps_get_opcode_info (op->common.aml_opcode))->object_type); + obj_desc = acpi_ut_create_internal_object ( + (acpi_ps_get_opcode_info (op->common.aml_opcode))->object_type); if (!obj_desc) { return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ds_init_object_from_op (walk_state, op, op->common.aml_opcode, &obj_desc); + status = acpi_ds_init_object_from_op (walk_state, op, op->common.aml_opcode, + &obj_desc); if (ACPI_FAILURE (status)) { acpi_ut_remove_reference (obj_desc); return_ACPI_STATUS (status); @@ -120,7 +130,7 @@ acpi_ds_build_internal_object ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_build_internal_buffer_obj * @@ -134,7 +144,7 @@ acpi_ds_build_internal_object ( * DESCRIPTION: Translate a parser Op package object to the equivalent * namespace object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_build_internal_buffer_obj ( @@ -229,7 +239,7 @@ acpi_ds_build_internal_buffer_obj ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_build_internal_package_obj * @@ -243,7 +253,7 @@ acpi_ds_build_internal_buffer_obj ( * DESCRIPTION: Translate a parser Op package object to the equivalent * namespace object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_build_internal_package_obj ( @@ -331,11 +341,12 @@ acpi_ds_build_internal_package_obj ( if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { /* Object (package or buffer) is already built */ - obj_desc->package.elements[i] = ACPI_CAST_PTR (union acpi_operand_object, arg->common.node); + obj_desc->package.elements[i] = + ACPI_CAST_PTR (union acpi_operand_object, arg->common.node); } else { status = acpi_ds_build_internal_object (walk_state, arg, - &obj_desc->package.elements[i]); + &obj_desc->package.elements[i]); } i++; @@ -348,7 +359,7 @@ acpi_ds_build_internal_package_obj ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_create_node * @@ -360,7 +371,7 @@ acpi_ds_build_internal_package_obj ( * * DESCRIPTION: Create the object to be associated with a namespace node * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_create_node ( @@ -392,7 +403,8 @@ acpi_ds_create_node ( /* Build an internal object for the argument(s) */ - status = acpi_ds_build_internal_object (walk_state, op->common.value.arg, &obj_desc); + status = acpi_ds_build_internal_object (walk_state, op->common.value.arg, + &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -414,7 +426,7 @@ acpi_ds_create_node ( #endif /* ACPI_NO_METHOD_EXECUTION */ -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_init_object_from_op * @@ -429,7 +441,7 @@ acpi_ds_create_node ( * associated arguments. The namespace object is a more compact * representation of the Op and its arguments. * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_init_object_from_op ( @@ -462,7 +474,8 @@ acpi_ds_init_object_from_op ( /* * Defer evaluation of Buffer term_arg operand */ - obj_desc->buffer.node = (struct acpi_namespace_node *) walk_state->operands[0]; + obj_desc->buffer.node = (struct acpi_namespace_node *) + walk_state->operands[0]; obj_desc->buffer.aml_start = op->named.data; obj_desc->buffer.aml_length = op->named.length; break; @@ -473,7 +486,8 @@ acpi_ds_init_object_from_op ( /* * Defer evaluation of Package term_arg operand */ - obj_desc->package.node = (struct acpi_namespace_node *) walk_state->operands[0]; + obj_desc->package.node = (struct acpi_namespace_node *) + walk_state->operands[0]; obj_desc->package.aml_start = op->named.data; obj_desc->package.aml_length = op->named.length; break; @@ -486,9 +500,10 @@ acpi_ds_init_object_from_op ( /* * Resolve AML Constants here - AND ONLY HERE! * All constants are integers. - * We mark the integer with a flag that indicates that it started life - * as a constant -- so that stores to constants will perform as expected (noop). - * (zero_op is used as a placeholder for optional target operands.) + * We mark the integer with a flag that indicates that it started + * life as a constant -- so that stores to constants will perform + * as expected (noop). zero_op is used as a placeholder for optional + * target operands. */ obj_desc->common.flags = AOPOBJ_AML_CONSTANT; @@ -521,7 +536,8 @@ acpi_ds_init_object_from_op ( default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown constant opcode %X\n", opcode)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown constant opcode %X\n", opcode)); status = AE_AML_OPERAND_TYPE; break; } @@ -535,7 +551,8 @@ acpi_ds_init_object_from_op ( default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n", op_info->type)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n", + op_info->type)); status = AE_AML_OPERAND_TYPE; break; } @@ -570,8 +587,10 @@ acpi_ds_init_object_from_op ( obj_desc->reference.offset = opcode - AML_LOCAL_OP; #ifndef ACPI_NO_METHOD_EXECUTION - status = acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset, - walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object); + status = acpi_ds_method_data_get_node (AML_LOCAL_OP, + obj_desc->reference.offset, + walk_state, + (struct acpi_namespace_node **) &obj_desc->reference.object); #endif break; @@ -584,8 +603,10 @@ acpi_ds_init_object_from_op ( obj_desc->reference.offset = opcode - AML_ARG_OP; #ifndef ACPI_NO_METHOD_EXECUTION - status = acpi_ds_method_data_get_node (AML_ARG_OP, obj_desc->reference.offset, - walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object); + status = acpi_ds_method_data_get_node (AML_ARG_OP, + obj_desc->reference.offset, + walk_state, + (struct acpi_namespace_node **) &obj_desc->reference.object); #endif break; diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index 5c987a0e7b7..ba13bca28be 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -54,12 +54,31 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dsopcode") +/* Local prototypes */ -/***************************************************************************** +static acpi_status +acpi_ds_execute_arguments ( + struct acpi_namespace_node *node, + struct acpi_namespace_node *scope_node, + u32 aml_length, + u8 *aml_start); + +static acpi_status +acpi_ds_init_buffer_field ( + u16 aml_opcode, + union acpi_operand_object *obj_desc, + union acpi_operand_object *buffer_desc, + union acpi_operand_object *offset_desc, + union acpi_operand_object *length_desc, + union acpi_operand_object *result_desc); + + +/******************************************************************************* * * FUNCTION: acpi_ds_execute_arguments * - * PARAMETERS: Node - Parent NS node + * PARAMETERS: Node - Object NS node + * scope_node - Parent NS node * aml_length - Length of executable AML * aml_start - Pointer to the AML * @@ -67,9 +86,9 @@ * * DESCRIPTION: Late (deferred) execution of region or field arguments * - ****************************************************************************/ + ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_execute_arguments ( struct acpi_namespace_node *node, struct acpi_namespace_node *scope_node, @@ -162,7 +181,7 @@ acpi_ds_execute_arguments ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_get_buffer_field_arguments * @@ -173,7 +192,7 @@ acpi_ds_execute_arguments ( * DESCRIPTION: Get buffer_field Buffer and Index. This implements the late * evaluation of these field attributes. * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_get_buffer_field_arguments ( @@ -208,7 +227,7 @@ acpi_ds_get_buffer_field_arguments ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_get_buffer_arguments * @@ -219,7 +238,7 @@ acpi_ds_get_buffer_field_arguments ( * DESCRIPTION: Get Buffer length and initializer byte list. This implements * the late evaluation of these attributes. * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_get_buffer_arguments ( @@ -255,7 +274,7 @@ acpi_ds_get_buffer_arguments ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_get_package_arguments * @@ -266,7 +285,7 @@ acpi_ds_get_buffer_arguments ( * DESCRIPTION: Get Package length and initializer byte list. This implements * the late evaluation of these attributes. * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_get_package_arguments ( @@ -353,17 +372,17 @@ acpi_ds_get_region_arguments ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_initialize_region * - * PARAMETERS: Op - A valid region Op object + * PARAMETERS: obj_handle - Region namespace node * * RETURN: Status * * DESCRIPTION: Front end to ev_initialize_region * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_initialize_region ( @@ -382,7 +401,7 @@ acpi_ds_initialize_region ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_init_buffer_field * @@ -390,16 +409,16 @@ acpi_ds_initialize_region ( * obj_desc - buffer_field object * buffer_desc - Host Buffer * offset_desc - Offset into buffer - * Length - Length of field (CREATE_FIELD_OP only) - * Result - Where to store the result + * length_desc - Length of field (CREATE_FIELD_OP only) + * result_desc - Where to store the result * * RETURN: Status * * DESCRIPTION: Perform actual initialization of a buffer field * - ****************************************************************************/ + ******************************************************************************/ -acpi_status +static acpi_status acpi_ds_init_buffer_field ( u16 aml_opcode, union acpi_operand_object *obj_desc, @@ -435,8 +454,10 @@ acpi_ds_init_buffer_field ( * after resolution in acpi_ex_resolve_operands(). */ if (ACPI_GET_DESCRIPTOR_TYPE (result_desc) != ACPI_DESC_TYPE_NAMED) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) destination not a NS Node [%s]\n", - acpi_ps_get_opcode_name (aml_opcode), acpi_ut_get_descriptor_name (result_desc))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "(%s) destination not a NS Node [%s]\n", + acpi_ps_get_opcode_name (aml_opcode), + acpi_ut_get_descriptor_name (result_desc))); status = AE_AML_OPERAND_TYPE; goto cleanup; @@ -452,9 +473,18 @@ acpi_ds_init_buffer_field ( /* Offset is in bits, count is in bits */ + field_flags = AML_FIELD_ACCESS_BYTE; bit_offset = offset; bit_count = (u32) length_desc->integer.value; - field_flags = AML_FIELD_ACCESS_BYTE; + + /* Must have a valid (>0) bit count */ + + if (bit_count == 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Attempt to create_field of length 0\n")); + status = AE_AML_OPERAND_VALUE; + goto cleanup; + } break; case AML_CREATE_BIT_FIELD_OP: @@ -527,7 +557,8 @@ acpi_ds_init_buffer_field ( /* * Initialize areas of the field object that are common to all fields - * For field_flags, use LOCK_RULE = 0 (NO_LOCK), UPDATE_RULE = 0 (UPDATE_PRESERVE) + * For field_flags, use LOCK_RULE = 0 (NO_LOCK), + * UPDATE_RULE = 0 (UPDATE_PRESERVE) */ status = acpi_ex_prep_common_field_object (obj_desc, field_flags, 0, bit_offset, bit_count); @@ -539,8 +570,8 @@ acpi_ds_init_buffer_field ( /* Reference count for buffer_desc inherits obj_desc count */ - buffer_desc->common.reference_count = (u16) (buffer_desc->common.reference_count + - obj_desc->common.reference_count); + buffer_desc->common.reference_count = (u16) + (buffer_desc->common.reference_count + obj_desc->common.reference_count); cleanup: @@ -569,7 +600,7 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_eval_buffer_field_operands * @@ -581,7 +612,7 @@ cleanup: * DESCRIPTION: Get buffer_field Buffer and Index * Called from acpi_ds_exec_end_op during buffer_field parse tree walk * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_eval_buffer_field_operands ( @@ -656,7 +687,7 @@ acpi_ds_eval_buffer_field_operands ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_eval_region_operands * @@ -668,7 +699,7 @@ acpi_ds_eval_buffer_field_operands ( * DESCRIPTION: Get region address and length * Called from acpi_ds_exec_end_op during op_region parse tree walk * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_eval_region_operands ( @@ -686,7 +717,8 @@ acpi_ds_eval_region_operands ( /* - * This is where we evaluate the address and length fields of the op_region declaration + * This is where we evaluate the address and length fields of the + * op_region declaration */ node = op->common.node; @@ -707,7 +739,8 @@ acpi_ds_eval_region_operands ( /* Resolve the length and address operands to numbers */ - status = acpi_ex_resolve_operands (op->common.aml_opcode, ACPI_WALK_OPERANDS, walk_state); + status = acpi_ex_resolve_operands (op->common.aml_opcode, + ACPI_WALK_OPERANDS, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -736,7 +769,8 @@ acpi_ds_eval_region_operands ( */ operand_desc = walk_state->operands[walk_state->num_operands - 2]; - obj_desc->region.address = (acpi_physical_address) operand_desc->integer.value; + obj_desc->region.address = (acpi_physical_address) + operand_desc->integer.value; acpi_ut_remove_reference (operand_desc); ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "rgn_obj %p Addr %8.8X%8.8X Len %X\n", @@ -752,7 +786,7 @@ acpi_ds_eval_region_operands ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ds_eval_data_object_operands * @@ -765,7 +799,7 @@ acpi_ds_eval_region_operands ( * DESCRIPTION: Get the operands and complete the following data object types: * Buffer, Package. * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ds_eval_data_object_operands ( @@ -830,7 +864,7 @@ acpi_ds_eval_data_object_operands ( if (ACPI_SUCCESS (status)) { /* - * Return the object in the walk_state, unless the parent is a package -- + * Return the object in the walk_state, unless the parent is a package - * in this case, the return object will be stored in the parse tree * for the package. */ @@ -988,7 +1022,8 @@ acpi_ds_exec_end_control_op ( status = AE_CTRL_PENDING; } - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[WHILE_OP] termination! Op=%p\n", op)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "[WHILE_OP] termination! Op=%p\n",op)); /* Pop this control state and free it */ diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index 462c5d83e74..9613349ac31 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -100,7 +100,6 @@ acpi_ds_clear_implicit_return ( #ifndef ACPI_NO_METHOD_EXECUTION - /******************************************************************************* * * FUNCTION: acpi_ds_do_implicit_return @@ -205,7 +204,7 @@ acpi_ds_is_result_used ( * NOTE: this is optional because the ASL language does not actually * support this behavior. */ - acpi_ds_do_implicit_return (walk_state->result_obj, walk_state, TRUE); + (void) acpi_ds_do_implicit_return (walk_state->result_obj, walk_state, TRUE); /* * Now determine if the parent will use the result @@ -219,8 +218,9 @@ acpi_ds_is_result_used ( (op->common.parent->common.aml_opcode == AML_SCOPE_OP)) { /* No parent, the return value cannot possibly be used */ - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "At Method level, result of [%s] not used\n", - acpi_ps_get_opcode_name (op->common.aml_opcode))); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "At Method level, result of [%s] not used\n", + acpi_ps_get_opcode_name (op->common.aml_opcode))); return_VALUE (FALSE); } @@ -228,7 +228,8 @@ acpi_ds_is_result_used ( parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode); if (parent_info->class == AML_CLASS_UNKNOWN) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown parent opcode. Op=%p\n", op)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown parent opcode. Op=%p\n", op)); return_VALUE (FALSE); } @@ -309,17 +310,19 @@ acpi_ds_is_result_used ( result_used: - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] used by Parent [%s] Op=%p\n", - acpi_ps_get_opcode_name (op->common.aml_opcode), - acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Result of [%s] used by Parent [%s] Op=%p\n", + acpi_ps_get_opcode_name (op->common.aml_opcode), + acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); return_VALUE (TRUE); result_not_used: - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] not used by Parent [%s] Op=%p\n", - acpi_ps_get_opcode_name (op->common.aml_opcode), - acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Result of [%s] not used by Parent [%s] Op=%p\n", + acpi_ps_get_opcode_name (op->common.aml_opcode), + acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); return_VALUE (FALSE); } @@ -522,7 +525,8 @@ acpi_ds_create_operand ( if ((walk_state->deferred_node) && (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD) && (arg_index != 0)) { - obj_desc = ACPI_CAST_PTR (union acpi_operand_object, walk_state->deferred_node); + obj_desc = ACPI_CAST_PTR ( + union acpi_operand_object, walk_state->deferred_node); status = AE_OK; } else /* All other opcodes */ { @@ -565,7 +569,8 @@ acpi_ds_create_operand ( * indicate this to the interpreter, set the * object to the root */ - obj_desc = ACPI_CAST_PTR (union acpi_operand_object, acpi_gbl_root_node); + obj_desc = ACPI_CAST_PTR ( + union acpi_operand_object, acpi_gbl_root_node); status = AE_OK; } else { @@ -612,7 +617,8 @@ acpi_ds_create_operand ( */ opcode = AML_ZERO_OP; /* Has no arguments! */ - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Null namepath: Arg=%p\n", arg)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Null namepath: Arg=%p\n", arg)); } else { opcode = arg->common.aml_opcode; @@ -642,7 +648,8 @@ acpi_ds_create_operand ( * Only error is underflow, and this indicates * a missing or null operand! */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Missing or null operand, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Missing or null operand, %s\n", acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -657,8 +664,8 @@ acpi_ds_create_operand ( /* Initialize the new object */ - status = acpi_ds_init_object_from_op (walk_state, arg, - opcode, &obj_desc); + status = acpi_ds_init_object_from_op ( + walk_state, arg, opcode, &obj_desc); if (ACPI_FAILURE (status)) { acpi_ut_delete_object_desc (obj_desc); return_ACPI_STATUS (status); diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index 2071a0d2bbb..10f71318e23 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -73,11 +73,13 @@ static ACPI_EXECUTE_OP acpi_gbl_op_type_dispatch [] = { acpi_ex_opcode_3A_1T_1R, acpi_ex_opcode_6A_0T_1R}; + /***************************************************************************** * * FUNCTION: acpi_ds_get_predicate_value * * PARAMETERS: walk_state - Current state of the parse tree walk + * result_obj - if non-zero, pop result from result stack * * RETURN: Status * @@ -124,7 +126,8 @@ acpi_ds_get_predicate_value ( } if (!obj_desc) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No predicate obj_desc=%p State=%p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No predicate obj_desc=%p State=%p\n", obj_desc, walk_state)); return_ACPI_STATUS (AE_AML_NO_OPERAND); @@ -197,7 +200,7 @@ cleanup: * FUNCTION: acpi_ds_exec_begin_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * out_op - Return op if a new one is created + * out_op - Where to return op if a new one is created * * RETURN: Status * @@ -233,7 +236,8 @@ acpi_ds_exec_begin_op ( walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); if (acpi_ns_opens_scope (walk_state->op_info->object_type)) { - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "(%s) Popping scope for Op %p\n", acpi_ut_get_type_name (walk_state->op_info->object_type), op)); status = acpi_ds_scope_stack_pop (walk_state); @@ -297,11 +301,10 @@ acpi_ds_exec_begin_op ( if (walk_state->walk_type == ACPI_WALK_METHOD) { /* - * Found a named object declaration during method - * execution; we must enter this object into the - * namespace. The created object is temporary and - * will be deleted upon completion of the execution - * of this method. + * Found a named object declaration during method execution; + * we must enter this object into the namespace. The created + * object is temporary and will be deleted upon completion of + * the execution of this method. */ status = acpi_ds_load2_begin_op (walk_state, NULL); } @@ -338,8 +341,6 @@ acpi_ds_exec_begin_op ( * FUNCTION: acpi_ds_exec_end_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * Op - Op that has been just been completed in the - * walk; Arguments have now been evaluated. * * RETURN: Status * @@ -389,7 +390,7 @@ acpi_ds_exec_end_op ( /* Decode the Opcode Class */ switch (op_class) { - case AML_CLASS_ARGUMENT: /* constants, literals, etc. -- do nothing */ + case AML_CLASS_ARGUMENT: /* constants, literals, etc. - do nothing */ break; @@ -417,12 +418,12 @@ acpi_ds_exec_end_op ( /* Resolve all operands */ status = acpi_ex_resolve_operands (walk_state->opcode, - &(walk_state->operands [walk_state->num_operands -1]), - walk_state); + &(walk_state->operands [walk_state->num_operands -1]), + walk_state); if (ACPI_SUCCESS (status)) { ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, - acpi_ps_get_opcode_name (walk_state->opcode), - walk_state->num_operands, "after ex_resolve_operands"); + acpi_ps_get_opcode_name (walk_state->opcode), + walk_state->num_operands, "after ex_resolve_operands"); } } @@ -506,7 +507,8 @@ acpi_ds_exec_end_op ( if ((op->asl.parent) && ((op->asl.parent->asl.aml_opcode == AML_PACKAGE_OP) || (op->asl.parent->asl.aml_opcode == AML_VAR_PACKAGE_OP))) { - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Method Reference in a Package, Op=%p\n", op)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Method Reference in a Package, Op=%p\n", op)); op->common.node = (struct acpi_namespace_node *) op->asl.value.arg->asl.node->object; acpi_ut_add_reference (op->asl.value.arg->asl.node->object); return_ACPI_STATUS (AE_OK); @@ -583,13 +585,15 @@ acpi_ds_exec_end_op ( case AML_NAME_OP: /* - * Put the Node on the object stack (Contains the ACPI Name of - * this object) + * Put the Node on the object stack (Contains the ACPI Name + * of this object) */ walk_state->operands[0] = (void *) op->common.parent->common.node; walk_state->num_operands = 1; - status = acpi_ds_create_node (walk_state, op->common.parent->common.node, op->common.parent); + status = acpi_ds_create_node (walk_state, + op->common.parent->common.node, + op->common.parent); if (ACPI_FAILURE (status)) { break; } @@ -600,7 +604,7 @@ acpi_ds_exec_end_op ( case AML_INT_EVAL_SUBTREE_OP: status = acpi_ds_eval_data_object_operands (walk_state, op, - acpi_ns_get_attached_object (op->common.parent->common.node)); + acpi_ns_get_attached_object (op->common.parent->common.node)); break; default: @@ -609,7 +613,7 @@ acpi_ds_exec_end_op ( break; } - /* Done with this result state (Now that operand stack is built) */ + /* Done with result state (Now that operand stack is built) */ status = acpi_ds_result_stack_pop (walk_state); if (ACPI_FAILURE (status)) { @@ -620,8 +624,7 @@ acpi_ds_exec_end_op ( * If a result object was returned from above, push it on the * current result stack */ - if (ACPI_SUCCESS (status) && - walk_state->result_obj) { + if (walk_state->result_obj) { status = acpi_ds_result_push (walk_state->result_obj, walk_state); } break; @@ -654,7 +657,8 @@ acpi_ds_exec_end_op ( case AML_TYPE_UNDEFINED: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Undefined opcode type Op=%p\n", op)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Undefined opcode type Op=%p\n", op)); return_ACPI_STATUS (AE_NOT_IMPLEMENTED); @@ -709,13 +713,14 @@ cleanup: status = acpi_gbl_exception_handler (status, walk_state->method_node->name.integer, walk_state->opcode, walk_state->aml_offset, NULL); - acpi_ex_enter_interpreter (); + (void) acpi_ex_enter_interpreter (); } if (walk_state->result_obj) { /* Break to debugger to display result */ - ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (walk_state->result_obj, walk_state)); + ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (walk_state->result_obj, + walk_state)); /* * Delete the result op if and only if: diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c index 06d75867958..1ac197ccfc8 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/dispatcher/dswload.c @@ -79,20 +79,23 @@ acpi_ds_init_callbacks ( switch (pass_number) { case 1: - walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE; + walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | + ACPI_PARSE_DELETE_TREE; walk_state->descending_callback = acpi_ds_load1_begin_op; walk_state->ascending_callback = acpi_ds_load1_end_op; break; case 2: - walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE; + walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | + ACPI_PARSE_DELETE_TREE; walk_state->descending_callback = acpi_ds_load2_begin_op; walk_state->ascending_callback = acpi_ds_load2_end_op; break; case 3: #ifndef ACPI_NO_METHOD_EXECUTION - walk_state->parse_flags |= ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE; + walk_state->parse_flags |= ACPI_PARSE_EXECUTE | + ACPI_PARSE_DELETE_TREE; walk_state->descending_callback = acpi_ds_exec_begin_op; walk_state->ascending_callback = acpi_ds_exec_end_op; #endif @@ -111,8 +114,7 @@ acpi_ds_init_callbacks ( * FUNCTION: acpi_ds_load1_begin_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * Op - Op that has been just been reached in the - * walk; Arguments have not been evaluated yet. + * out_op - Where to return op if a new one is created * * RETURN: Status * @@ -146,7 +148,8 @@ acpi_ds_load1_begin_op ( #if 0 if ((walk_state->op_info->class == AML_CLASS_EXECUTE) || (walk_state->op_info->class == AML_CLASS_CONTROL)) { - acpi_os_printf ("\n\n***EXECUTABLE OPCODE %s***\n\n", walk_state->op_info->name); + acpi_os_printf ("\n\n***EXECUTABLE OPCODE %s***\n\n", + walk_state->op_info->name); *out_op = op; return (AE_CTRL_SKIP); } @@ -191,7 +194,8 @@ acpi_ds_load1_begin_op ( */ acpi_dm_add_to_external_list (path); status = acpi_ns_lookup (walk_state->scope_info, path, object_type, - ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); + ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, + walk_state, &(node)); } #endif if (ACPI_FAILURE (status)) { @@ -224,10 +228,12 @@ acpi_ds_load1_begin_op ( * Name (DEB, 0) * Scope (DEB) { ... } * - * Note: silently change the type here. On the second pass, we will report a warning + * Note: silently change the type here. On the second pass, we will report + * a warning */ - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", path, acpi_ut_get_type_name (node->type))); node->type = ACPI_TYPE_ANY; @@ -238,7 +244,8 @@ acpi_ds_load1_begin_op ( /* All other types are an error */ - ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)\n", + ACPI_REPORT_ERROR (( + "Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)\n", acpi_ut_get_type_name (node->type), path)); return (AE_AML_OPERAND_TYPE); @@ -249,7 +256,8 @@ acpi_ds_load1_begin_op ( default: /* - * For all other named opcodes, we will enter the name into the namespace. + * For all other named opcodes, we will enter the name into + * the namespace. * * Setup the search flags. * Since we are entering a name into the namespace, we do not want to @@ -279,14 +287,16 @@ acpi_ds_load1_begin_op ( acpi_ut_get_type_name (object_type))); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Both Find or Create allowed\n", + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "[%s] Both Find or Create allowed\n", acpi_ut_get_type_name (object_type))); } /* * Enter the named type into the internal namespace. We enter the name - * as we go downward in the parse tree. Any necessary subobjects that involve - * arguments to the opcode must be created as we go back up the parse tree later. + * as we go downward in the parse tree. Any necessary subobjects that + * involve arguments to the opcode must be created as we go back up the + * parse tree later. */ status = acpi_ns_lookup (walk_state->scope_info, path, object_type, ACPI_IMODE_LOAD_PASS1, flags, walk_state, &(node)); @@ -335,8 +345,6 @@ acpi_ds_load1_begin_op ( * FUNCTION: acpi_ds_load1_end_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * Op - Op that has been just been completed in the - * walk; Arguments have now been evaluated. * * RETURN: Status * @@ -383,7 +391,9 @@ acpi_ds_load1_end_op ( if (op->common.aml_opcode == AML_REGION_OP) { status = acpi_ex_create_region (op->named.data, op->named.length, - (acpi_adr_space_type) ((op->common.value.arg)->common.value.integer), walk_state); + (acpi_adr_space_type) + ((op->common.value.arg)->common.value.integer), + walk_state); if (ACPI_FAILURE (status)) { return (status); } @@ -394,7 +404,8 @@ acpi_ds_load1_end_op ( /* For Name opcode, get the object type from the argument */ if (op->common.value.arg) { - object_type = (acpi_ps_get_opcode_info ((op->common.value.arg)->common.aml_opcode))->object_type; + object_type = (acpi_ps_get_opcode_info ( + (op->common.value.arg)->common.aml_opcode))->object_type; op->common.node->type = (u8) object_type; } } @@ -448,8 +459,7 @@ acpi_ds_load1_end_op ( * FUNCTION: acpi_ds_load2_begin_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * Op - Op that has been just been reached in the - * walk; Arguments have not been evaluated yet. + * out_op - Wher to return op if a new one is created * * RETURN: Status * @@ -478,14 +488,20 @@ acpi_ds_load2_begin_op ( if (op) { /* We only care about Namespace opcodes here */ - if ((!(walk_state->op_info->flags & AML_NSOPCODE) && (walk_state->opcode != AML_INT_NAMEPATH_OP)) || + if ((!(walk_state->op_info->flags & AML_NSOPCODE) && + (walk_state->opcode != AML_INT_NAMEPATH_OP)) || (!(walk_state->op_info->flags & AML_NAMED))) { + if ((walk_state->op_info->class == AML_CLASS_EXECUTE) || + (walk_state->op_info->class == AML_CLASS_CONTROL)) { + ACPI_REPORT_WARNING (( + "Encountered executable code at module level, [%s]\n", + acpi_ps_get_opcode_name (walk_state->opcode))); + } return_ACPI_STATUS (AE_OK); } - /* - * Get the name we are going to enter or lookup in the namespace - */ + /* Get the name we are going to enter or lookup in the namespace */ + if (walk_state->opcode == AML_INT_NAMEPATH_OP) { /* For Namepath op, get the path string */ @@ -528,21 +544,25 @@ acpi_ds_load2_begin_op ( case AML_INT_NAMEPATH_OP: /* - * The name_path is an object reference to an existing object. Don't enter the - * name into the namespace, but look it up for use later + * The name_path is an object reference to an existing object. + * Don't enter the name into the namespace, but look it up + * for use later. */ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, - ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, + walk_state, &(node)); break; case AML_SCOPE_OP: /* - * The Path is an object reference to an existing object. Don't enter the - * name into the namespace, but look it up for use later + * The Path is an object reference to an existing object. + * Don't enter the name into the namespace, but look it up + * for use later. */ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, - ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, + walk_state, &(node)); if (ACPI_FAILURE (status)) { #ifdef _ACPI_ASL_COMPILER if (status == AE_NOT_FOUND) { @@ -582,7 +602,8 @@ acpi_ds_load2_begin_op ( * Scope (DEB) { ... } */ - ACPI_REPORT_WARNING (("Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", + ACPI_REPORT_WARNING (( + "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", buffer_ptr, acpi_ut_get_type_name (node->type))); node->type = ACPI_TYPE_ANY; @@ -593,7 +614,8 @@ acpi_ds_load2_begin_op ( /* All other types are an error */ - ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n", + ACPI_REPORT_ERROR (( + "Invalid type (%s) for target of Scope operator [%4.4s]\n", acpi_ut_get_type_name (node->type), buffer_ptr)); return (AE_AML_OPERAND_TYPE); @@ -621,8 +643,9 @@ acpi_ds_load2_begin_op ( /* * Enter the named type into the internal namespace. We enter the name - * as we go downward in the parse tree. Any necessary subobjects that involve - * arguments to the opcode must be created as we go back up the parse tree later. + * as we go downward in the parse tree. Any necessary subobjects that + * involve arguments to the opcode must be created as we go back up the + * parse tree later. * * Note: Name may already exist if we are executing a deferred opcode. */ @@ -635,7 +658,8 @@ acpi_ds_load2_begin_op ( } status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, - ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, walk_state, &(node)); + ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, + walk_state, &(node)); break; } @@ -678,8 +702,6 @@ acpi_ds_load2_begin_op ( * FUNCTION: acpi_ds_load2_end_op * * PARAMETERS: walk_state - Current state of the parse tree walk - * Op - Op that has been just been completed in the - * walk; Arguments have now been evaluated. * * RETURN: Status * @@ -738,7 +760,8 @@ acpi_ds_load2_end_op ( /* Pop the scope stack */ - if (acpi_ns_opens_scope (object_type) && (op->common.aml_opcode != AML_INT_METHODCALL_OP)) { + if (acpi_ns_opens_scope (object_type) && + (op->common.aml_opcode != AML_INT_METHODCALL_OP)) { ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n", acpi_ut_get_type_name (object_type), op)); @@ -803,7 +826,7 @@ acpi_ds_load2_end_op ( case AML_INDEX_FIELD_OP: status = acpi_ds_create_index_field (op, (acpi_handle) arg->common.node, - walk_state); + walk_state); break; case AML_BANK_FIELD_OP: @@ -884,14 +907,16 @@ acpi_ds_load2_end_op ( #ifndef ACPI_NO_METHOD_EXECUTION case AML_REGION_OP: /* - * The op_region is not fully parsed at this time. Only valid argument is the space_id. - * (We must save the address of the AML of the address and length operands) + * The op_region is not fully parsed at this time. Only valid + * argument is the space_id. (We must save the address of the + * AML of the address and length operands) */ /* * If we have a valid region, initialize it * Namespace is NOT locked at this point. */ - status = acpi_ev_initialize_region (acpi_ns_get_attached_object (node), FALSE); + status = acpi_ev_initialize_region (acpi_ns_get_attached_object (node), + FALSE); if (ACPI_FAILURE (status)) { /* * If AE_NOT_EXIST is returned, it is not fatal @@ -942,15 +967,16 @@ acpi_ds_load2_end_op ( if (ACPI_SUCCESS (status)) { /* * Make sure that what we found is indeed a method - * We didn't search for a method on purpose, to see if the name would resolve + * We didn't search for a method on purpose, to see if the name + * would resolve */ if (new_node->type != ACPI_TYPE_METHOD) { status = AE_AML_OPERAND_TYPE; } - /* We could put the returned object (Node) on the object stack for later, but - * for now, we will put it in the "op" object that the parser uses, so we - * can get it again at the end of this scope + /* We could put the returned object (Node) on the object stack for + * later, but for now, we will put it in the "op" object that the + * parser uses, so we can get it again at the end of this scope */ op->common.node = new_node; } diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c index 65f456151e2..21f4548ff32 100644 --- a/drivers/acpi/dispatcher/dswscope.c +++ b/drivers/acpi/dispatcher/dswscope.c @@ -50,14 +50,13 @@ ACPI_MODULE_NAME ("dswscope") -#define STACK_POP(head) head - - /**************************************************************************** * * FUNCTION: acpi_ds_scope_stack_clear * - * PARAMETERS: None + * PARAMETERS: walk_state - Current state + * + * RETURN: None * * DESCRIPTION: Pop (and free) everything on the scope stack except the * root scope object (which remains at the stack top.) @@ -80,7 +79,8 @@ acpi_ds_scope_stack_clear ( walk_state->scope_info = scope_info->scope.next; ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, - "Popped object type (%s)\n", acpi_ut_get_type_name (scope_info->common.value))); + "Popped object type (%s)\n", + acpi_ut_get_type_name (scope_info->common.value))); acpi_ut_delete_generic_state (scope_info); } } @@ -90,8 +90,11 @@ acpi_ds_scope_stack_clear ( * * FUNCTION: acpi_ds_scope_stack_push * - * PARAMETERS: *Node, - Name to be made current - * Type, - Type of frame being pushed + * PARAMETERS: Node - Name to be made current + * Type - Type of frame being pushed + * walk_state - Current state + * + * RETURN: Status * * DESCRIPTION: Push the current scope on the scope stack, and make the * passed Node current. @@ -121,7 +124,8 @@ acpi_ds_scope_stack_push ( /* Make sure object type is valid */ if (!acpi_ut_valid_object_type (type)) { - ACPI_REPORT_WARNING (("ds_scope_stack_push: Invalid object type: 0x%X\n", type)); + ACPI_REPORT_WARNING (( + "ds_scope_stack_push: Invalid object type: 0x%X\n", type)); } /* Allocate a new scope object */ @@ -170,16 +174,11 @@ acpi_ds_scope_stack_push ( * * FUNCTION: acpi_ds_scope_stack_pop * - * PARAMETERS: Type - The type of frame to be found + * PARAMETERS: walk_state - Current state * - * DESCRIPTION: Pop the scope stack until a frame of the requested type - * is found. + * RETURN: Status * - * RETURN: Count of frames popped. If no frame of the requested type - * was found, the count is returned as a negative number and - * the scope stack is emptied (which sets the current scope - * to the root). If the scope stack was empty at entry, the - * function is a no-op and returns 0. + * DESCRIPTION: Pop the scope stack once. * ***************************************************************************/ diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index e555b3fbd5e..9cd3db652b3 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -50,67 +50,31 @@ #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME ("dswstate") +/* Local prototypes */ -#ifdef ACPI_FUTURE_USAGE - -/******************************************************************************* - * - * FUNCTION: acpi_ds_result_insert - * - * PARAMETERS: Object - Object to push - * Index - Where to insert the object - * walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Insert an object onto this walk's result stack - * - ******************************************************************************/ - +#ifdef ACPI_OBSOLETE_FUNCTIONS acpi_status acpi_ds_result_insert ( void *object, u32 index, - struct acpi_walk_state *walk_state) -{ - union acpi_generic_state *state; - + struct acpi_walk_state *walk_state); - ACPI_FUNCTION_NAME ("ds_result_insert"); - - - state = walk_state->results; - if (!state) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n", - walk_state)); - return (AE_NOT_EXIST); - } - - if (index >= ACPI_OBJ_NUM_OPERANDS) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Index out of range: %X Obj=%p State=%p Num=%X\n", - index, object, walk_state, state->results.num_results)); - return (AE_BAD_PARAMETER); - } - - if (!object) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Null Object! Index=%X Obj=%p State=%p Num=%X\n", - index, object, walk_state, state->results.num_results)); - return (AE_BAD_PARAMETER); - } - - state->results.obj_desc [index] = object; - state->results.num_results++; +acpi_status +acpi_ds_obj_stack_delete_all ( + struct acpi_walk_state *walk_state); - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, - "Obj=%p [%s] State=%p Num=%X Cur=%X\n", - object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL", - walk_state, state->results.num_results, walk_state->current_result)); +acpi_status +acpi_ds_obj_stack_pop_object ( + union acpi_operand_object **object, + struct acpi_walk_state *walk_state); - return (AE_OK); -} +void * +acpi_ds_obj_stack_get_value ( + u32 index, + struct acpi_walk_state *walk_state); +#endif +#ifdef ACPI_FUTURE_USAGE /******************************************************************************* * @@ -178,7 +142,6 @@ acpi_ds_result_remove ( #endif /* ACPI_FUTURE_USAGE */ - /******************************************************************************* * * FUNCTION: acpi_ds_result_pop @@ -227,15 +190,18 @@ acpi_ds_result_pop ( *object = state->results.obj_desc [index -1]; state->results.obj_desc [index -1] = NULL; - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] Index=%X State=%p Num=%X\n", - *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Obj=%p [%s] Index=%X State=%p Num=%X\n", + *object, + (*object) ? acpi_ut_get_object_type_name (*object) : "NULL", (u32) index -1, walk_state, state->results.num_results)); return (AE_OK); } } - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No result objects! State=%p\n", walk_state)); return (AE_AML_NO_RETURN_VALUE); } @@ -274,7 +240,8 @@ acpi_ds_result_pop_from_bottom ( } if (!state->results.num_results) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", + walk_state)); return (AE_AML_NO_RETURN_VALUE); } @@ -293,7 +260,8 @@ acpi_ds_result_pop_from_bottom ( /* Check for a valid result object */ if (!*object) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null operand! State=%p #Ops=%X, Index=%X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null operand! State=%p #Ops=%X, Index=%X\n", walk_state, state->results.num_results, (u32) index)); return (AE_AML_NO_RETURN_VALUE); } @@ -344,7 +312,8 @@ acpi_ds_result_push ( } if (!object) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Object! Obj=%p State=%p Num=%X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null Object! Obj=%p State=%p Num=%X\n", object, walk_state, state->results.num_results)); return (AE_BAD_PARAMETER); } @@ -437,43 +406,6 @@ acpi_ds_result_stack_pop ( } -/******************************************************************************* - * - * FUNCTION: acpi_ds_obj_stack_delete_all - * - * PARAMETERS: walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Clear the object stack by deleting all objects that are on it. - * Should be used with great care, if at all! - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE -acpi_status -acpi_ds_obj_stack_delete_all ( - struct acpi_walk_state *walk_state) -{ - u32 i; - - - ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_delete_all", walk_state); - - - /* The stack size is configurable, but fixed */ - - for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) { - if (walk_state->operands[i]) { - acpi_ut_remove_reference (walk_state->operands[i]); - walk_state->operands[i] = NULL; - } - } - - return_ACPI_STATUS (AE_OK); -} -#endif /* ACPI_FUTURE_USAGE */ - - /******************************************************************************* * * FUNCTION: acpi_ds_obj_stack_push @@ -517,67 +449,6 @@ acpi_ds_obj_stack_push ( } -#if 0 -/******************************************************************************* - * - * FUNCTION: acpi_ds_obj_stack_pop_object - * - * PARAMETERS: pop_count - Number of objects/entries to pop - * walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT - * deleted by this routine. - * - ******************************************************************************/ - -acpi_status -acpi_ds_obj_stack_pop_object ( - union acpi_operand_object **object, - struct acpi_walk_state *walk_state) -{ - ACPI_FUNCTION_NAME ("ds_obj_stack_pop_object"); - - - /* Check for stack underflow */ - - if (walk_state->num_operands == 0) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Missing operand/stack empty! State=%p #Ops=%X\n", - walk_state, walk_state->num_operands)); - *object = NULL; - return (AE_AML_NO_OPERAND); - } - - /* Pop the stack */ - - walk_state->num_operands--; - - /* Check for a valid operand */ - - if (!walk_state->operands [walk_state->num_operands]) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Null operand! State=%p #Ops=%X\n", - walk_state, walk_state->num_operands)); - *object = NULL; - return (AE_AML_NO_OPERAND); - } - - /* Get operand and set stack entry to null */ - - *object = walk_state->operands [walk_state->num_operands]; - walk_state->operands [walk_state->num_operands] = NULL; - - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", - *object, acpi_ut_get_object_type_name (*object), - walk_state, walk_state->num_operands)); - - return (AE_OK); -} -#endif - - /******************************************************************************* * * FUNCTION: acpi_ds_obj_stack_pop @@ -678,48 +549,6 @@ acpi_ds_obj_stack_pop_and_delete ( } -/******************************************************************************* - * - * FUNCTION: acpi_ds_obj_stack_get_value - * - * PARAMETERS: Index - Stack index whose value is desired. Based - * on the top of the stack (index=0 == top) - * walk_state - Current Walk state - * - * RETURN: Status - * - * DESCRIPTION: Retrieve an object from this walk's object stack. Index must - * be within the range of the current stack pointer. - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE -void * -acpi_ds_obj_stack_get_value ( - u32 index, - struct acpi_walk_state *walk_state) -{ - - ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_get_value", walk_state); - - - /* Can't do it if the stack is empty */ - - if (walk_state->num_operands == 0) { - return_PTR (NULL); - } - - /* or if the index is past the top of the stack */ - - if (index > (walk_state->num_operands - (u32) 1)) { - return_PTR (NULL); - } - - return_PTR (walk_state->operands[(acpi_native_uint)(walk_state->num_operands - 1) - - index]); -} -#endif /* ACPI_FUTURE_USAGE */ - - /******************************************************************************* * * FUNCTION: acpi_ds_get_current_walk_state @@ -757,11 +586,11 @@ acpi_ds_get_current_walk_state ( * FUNCTION: acpi_ds_push_walk_state * * PARAMETERS: walk_state - State to push - * walk_list - The list that owns the walk stack + * Thread - Thread state object * * RETURN: None * - * DESCRIPTION: Place the walk_state at the head of the state list. + * DESCRIPTION: Place the Thread state at the head of the state list. * ******************************************************************************/ @@ -784,9 +613,9 @@ acpi_ds_push_walk_state ( * * FUNCTION: acpi_ds_pop_walk_state * - * PARAMETERS: walk_list - The list that owns the walk stack + * PARAMETERS: Thread - Current thread state * - * RETURN: A walk_state object popped from the stack + * RETURN: A walk_state object popped from the thread's stack * * DESCRIPTION: Remove and return the walkstate object that is at the head of * the walk stack for the given walk list. NULL indicates that @@ -814,7 +643,7 @@ acpi_ds_pop_walk_state ( /* * Don't clear the NEXT field, this serves as an indicator * that there is a parent WALK STATE - * NO: walk_state->Next = NULL; + * Do Not: walk_state->Next = NULL; */ } @@ -826,7 +655,9 @@ acpi_ds_pop_walk_state ( * * FUNCTION: acpi_ds_create_walk_state * - * PARAMETERS: Origin - Starting point for this walk + * PARAMETERS: owner_id - ID for object creation + * Origin - Starting point for this walk + * mth_desc - Method object * Thread - Current thread state * * RETURN: Pointer to the new walk state. @@ -896,8 +727,7 @@ acpi_ds_create_walk_state ( * method_node - Control method NS node, if any * aml_start - Start of AML * aml_length - Length of AML - * Params - Method args, if any - * return_obj_desc - Where to store a return object, if any + * Info - Method info block (params, etc.) * pass_number - 1, 2, or 3 * * RETURN: Status @@ -931,7 +761,7 @@ acpi_ds_init_aml_walk ( /* The next_op of the next_walk will be the beginning of the method */ - walk_state->next_op = NULL; + walk_state->next_op = NULL; if (info) { if (info->parameter_type == ACPI_PARAM_GPE) { @@ -939,8 +769,8 @@ acpi_ds_init_aml_walk ( info->parameters); } else { - walk_state->params = info->parameters; - walk_state->caller_return_desc = &info->return_object; + walk_state->params = info->parameters; + walk_state->caller_return_desc = &info->return_object; } } @@ -964,7 +794,8 @@ acpi_ds_init_aml_walk ( /* Init the method arguments */ - status = acpi_ds_method_data_init_args (walk_state->params, ACPI_METHOD_NUM_ARGS, walk_state); + status = acpi_ds_method_data_init_args (walk_state->params, + ACPI_METHOD_NUM_ARGS, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -1031,12 +862,14 @@ acpi_ds_delete_walk_state ( } if (walk_state->data_type != ACPI_DESC_TYPE_WALK) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p is not a valid walk state\n", walk_state)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p is not a valid walk state\n", + walk_state)); return; } if (walk_state->parser_state.scope) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p walk still has a scope list\n", walk_state)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p walk still has a scope list\n", + walk_state)); } /* Always must free any linked control states */ @@ -1078,7 +911,7 @@ acpi_ds_delete_walk_state ( * * PARAMETERS: None * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Purge the global state object cache. Used during subsystem * termination. @@ -1098,3 +931,200 @@ acpi_ds_delete_walk_state_cache ( #endif +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: acpi_ds_result_insert + * + * PARAMETERS: Object - Object to push + * Index - Where to insert the object + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Insert an object onto this walk's result stack + * + ******************************************************************************/ + +acpi_status +acpi_ds_result_insert ( + void *object, + u32 index, + struct acpi_walk_state *walk_state) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_NAME ("ds_result_insert"); + + + state = walk_state->results; + if (!state) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n", + walk_state)); + return (AE_NOT_EXIST); + } + + if (index >= ACPI_OBJ_NUM_OPERANDS) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Index out of range: %X Obj=%p State=%p Num=%X\n", + index, object, walk_state, state->results.num_results)); + return (AE_BAD_PARAMETER); + } + + if (!object) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null Object! Index=%X Obj=%p State=%p Num=%X\n", + index, object, walk_state, state->results.num_results)); + return (AE_BAD_PARAMETER); + } + + state->results.obj_desc [index] = object; + state->results.num_results++; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Obj=%p [%s] State=%p Num=%X Cur=%X\n", + object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL", + walk_state, state->results.num_results, walk_state->current_result)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_delete_all + * + * PARAMETERS: walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Clear the object stack by deleting all objects that are on it. + * Should be used with great care, if at all! + * + ******************************************************************************/ + +acpi_status +acpi_ds_obj_stack_delete_all ( + struct acpi_walk_state *walk_state) +{ + u32 i; + + + ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_delete_all", walk_state); + + + /* The stack size is configurable, but fixed */ + + for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) { + if (walk_state->operands[i]) { + acpi_ut_remove_reference (walk_state->operands[i]); + walk_state->operands[i] = NULL; + } + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_pop_object + * + * PARAMETERS: Object - Where to return the popped object + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT + * deleted by this routine. + * + ******************************************************************************/ + +acpi_status +acpi_ds_obj_stack_pop_object ( + union acpi_operand_object **object, + struct acpi_walk_state *walk_state) +{ + ACPI_FUNCTION_NAME ("ds_obj_stack_pop_object"); + + + /* Check for stack underflow */ + + if (walk_state->num_operands == 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Missing operand/stack empty! State=%p #Ops=%X\n", + walk_state, walk_state->num_operands)); + *object = NULL; + return (AE_AML_NO_OPERAND); + } + + /* Pop the stack */ + + walk_state->num_operands--; + + /* Check for a valid operand */ + + if (!walk_state->operands [walk_state->num_operands]) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null operand! State=%p #Ops=%X\n", + walk_state, walk_state->num_operands)); + *object = NULL; + return (AE_AML_NO_OPERAND); + } + + /* Get operand and set stack entry to null */ + + *object = walk_state->operands [walk_state->num_operands]; + walk_state->operands [walk_state->num_operands] = NULL; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", + *object, acpi_ut_get_object_type_name (*object), + walk_state, walk_state->num_operands)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_get_value + * + * PARAMETERS: Index - Stack index whose value is desired. Based + * on the top of the stack (index=0 == top) + * walk_state - Current Walk state + * + * RETURN: Pointer to the requested operand + * + * DESCRIPTION: Retrieve an object from this walk's operand stack. Index must + * be within the range of the current stack pointer. + * + ******************************************************************************/ + +void * +acpi_ds_obj_stack_get_value ( + u32 index, + struct acpi_walk_state *walk_state) +{ + + ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_get_value", walk_state); + + + /* Can't do it if the stack is empty */ + + if (walk_state->num_operands == 0) { + return_PTR (NULL); + } + + /* or if the index is past the top of the stack */ + + if (index > (walk_state->num_operands - (u32) 1)) { + return_PTR (NULL); + } + + return_PTR (walk_state->operands[(acpi_native_uint)(walk_state->num_operands - 1) - + index]); +} +#endif + + diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c index 2a213604ae5..dd3a72a869f 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/events/evevent.c @@ -47,6 +47,16 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evevent") +/* Local prototypes */ + +static acpi_status +acpi_ev_fixed_event_initialize ( + void); + +static u32 +acpi_ev_fixed_event_dispatch ( + u32 event); + /******************************************************************************* * @@ -56,7 +66,7 @@ * * RETURN: Status * - * DESCRIPTION: Initialize global data structures for events. + * DESCRIPTION: Initialize global data structures for ACPI events (Fixed, GPE) * ******************************************************************************/ @@ -78,9 +88,9 @@ acpi_ev_initialize_events ( } /* - * Initialize the Fixed and General Purpose Events. This is - * done prior to enabling SCIs to prevent interrupts from - * occurring before handers are installed. + * Initialize the Fixed and General Purpose Events. This is done prior to + * enabling SCIs to prevent interrupts from occurring before the handlers are + * installed. */ status = acpi_ev_fixed_event_initialize (); if (ACPI_FAILURE (status)) { @@ -161,7 +171,7 @@ acpi_ev_install_xrupt_handlers ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ev_fixed_event_initialize ( void) { @@ -180,7 +190,8 @@ acpi_ev_fixed_event_initialize ( /* Enable the fixed event */ if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) { - status = acpi_set_register (acpi_gbl_fixed_event_info[i].enable_register_id, + status = acpi_set_register ( + acpi_gbl_fixed_event_info[i].enable_register_id, 0, ACPI_MTX_LOCK); if (ACPI_FAILURE (status)) { return (status); @@ -200,7 +211,7 @@ acpi_ev_fixed_event_initialize ( * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * - * DESCRIPTION: Checks the PM status register for fixed events + * DESCRIPTION: Checks the PM status register for active fixed events * ******************************************************************************/ @@ -221,8 +232,10 @@ acpi_ev_fixed_event_detect ( * Read the fixed feature status and enable registers, as all the cases * depend on their values. Ignore errors here. */ - (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, &fixed_status); - (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE, &fixed_enable); + (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, + &fixed_status); + (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE, + &fixed_enable); ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, "Fixed Event Block: Enable %08X Status %08X\n", @@ -259,7 +272,7 @@ acpi_ev_fixed_event_detect ( * ******************************************************************************/ -u32 +static u32 acpi_ev_fixed_event_dispatch ( u32 event) { diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index 118d72ac7c7..081120b109b 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -48,6 +48,12 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evgpe") +/* Local prototypes */ + +static void ACPI_SYSTEM_XFACE +acpi_ev_asynch_execute_gpe_method ( + void *context); + /******************************************************************************* * @@ -335,8 +341,10 @@ acpi_ev_get_gpe_event_info ( gpe_block = acpi_gbl_gpe_fadt_blocks[i]; if (gpe_block) { if ((gpe_number >= gpe_block->block_base_number) && - (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) { - return (&gpe_block->event_info[gpe_number - gpe_block->block_base_number]); + (gpe_number < gpe_block->block_base_number + + (gpe_block->register_count * 8))) { + return (&gpe_block->event_info[gpe_number - + gpe_block->block_base_number]); } } } @@ -437,7 +445,7 @@ acpi_ev_gpe_detect ( "Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n", gpe_register_info->base_gpe_number, status_reg, enable_reg)); - /* First check if there is anything active at all in this register */ + /* Check if there is anything active at all in this register */ enabled_status_byte = (u8) (status_reg & enable_reg); if (!enabled_status_byte) { @@ -457,8 +465,8 @@ acpi_ev_gpe_detect ( * or method. */ int_status |= acpi_ev_gpe_dispatch ( - &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j], - (u32) j + gpe_register_info->base_gpe_number); + &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j], + (u32) j + gpe_register_info->base_gpe_number); } } } @@ -523,7 +531,8 @@ acpi_ev_asynch_execute_gpe_method ( * Take a snapshot of the GPE info for this level - we copy the * info to prevent a race condition with remove_handler/remove_block. */ - ACPI_MEMCPY (&local_gpe_event_info, gpe_event_info, sizeof (struct acpi_gpe_event_info)); + ACPI_MEMCPY (&local_gpe_event_info, gpe_event_info, + sizeof (struct acpi_gpe_event_info)); status = acpi_ut_release_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { @@ -534,7 +543,8 @@ acpi_ev_asynch_execute_gpe_method ( * Must check for control method type dispatch one more * time to avoid race with ev_gpe_install_handler */ - if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { + if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == + ACPI_GPE_DISPATCH_METHOD) { /* * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx * control method that corresponds to this GPE @@ -553,7 +563,8 @@ acpi_ev_asynch_execute_gpe_method ( } } - if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { + if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == + ACPI_GPE_LEVEL_TRIGGERED) { /* * GPE is level-triggered, we clear the GPE status bit after * handling the event. @@ -575,7 +586,7 @@ acpi_ev_asynch_execute_gpe_method ( * * FUNCTION: acpi_ev_gpe_dispatch * - * PARAMETERS: gpe_event_info - info for this GPE + * PARAMETERS: gpe_event_info - Info for this GPE * gpe_number - Number relative to the parent GPE block * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED @@ -602,10 +613,12 @@ acpi_ev_gpe_dispatch ( * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ - if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) { + if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == + ACPI_GPE_EDGE_TRIGGERED) { status = acpi_hw_clear_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X]\n", + ACPI_REPORT_ERROR (( + "acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X]\n", acpi_format_exception (status), gpe_number)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } @@ -639,7 +652,8 @@ acpi_ev_gpe_dispatch ( /* It is now safe to clear level-triggered events. */ - if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { + if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == + ACPI_GPE_LEVEL_TRIGGERED) { status = acpi_hw_clear_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( @@ -704,7 +718,6 @@ acpi_ev_gpe_dispatch ( #ifdef ACPI_GPE_NOTIFY_CHECK - /******************************************************************************* * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED * diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index 00d981f53c6..84186a7d17b 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -48,6 +48,39 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evgpeblk") +/* Local prototypes */ + +static acpi_status +acpi_ev_save_method_info ( + acpi_handle obj_handle, + u32 level, + void *obj_desc, + void **return_value); + +static acpi_status +acpi_ev_match_prw_and_gpe ( + acpi_handle obj_handle, + u32 level, + void *info, + void **return_value); + +static struct acpi_gpe_xrupt_info * +acpi_ev_get_gpe_xrupt_block ( + u32 interrupt_level); + +static acpi_status +acpi_ev_delete_gpe_xrupt ( + struct acpi_gpe_xrupt_info *gpe_xrupt); + +static acpi_status +acpi_ev_install_gpe_block ( + struct acpi_gpe_block_info *gpe_block, + u32 interrupt_level); + +static acpi_status +acpi_ev_create_gpe_info_blocks ( + struct acpi_gpe_block_info *gpe_block); + /******************************************************************************* * @@ -155,7 +188,7 @@ unlock_and_exit: } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ev_delete_gpe_handlers * @@ -190,7 +223,8 @@ acpi_ev_delete_gpe_handlers ( for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j]; - if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { + if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == + ACPI_GPE_DISPATCH_HANDLER) { ACPI_MEM_FREE (gpe_event_info->dispatch.handler); gpe_event_info->dispatch.handler = NULL; gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; @@ -471,7 +505,7 @@ acpi_ev_get_gpe_xrupt_block ( ACPI_FUNCTION_TRACE ("ev_get_gpe_xrupt_block"); - /* No need for spin lock since we are not changing any list elements here */ + /* No need for lock since we are not changing any list elements here */ next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; while (next_gpe_xrupt) { @@ -619,7 +653,7 @@ acpi_ev_install_gpe_block ( goto unlock_and_exit; } - /* Install the new block at the end of the list for this interrupt with lock */ + /* Install the new block at the end of the list with lock */ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); if (gpe_xrupt_block->gpe_block_list_head) { @@ -756,10 +790,12 @@ acpi_ev_create_gpe_info_blocks ( * per register. Initialization to zeros is sufficient. */ gpe_event_info = ACPI_MEM_CALLOCATE ( - ((acpi_size) gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) * + ((acpi_size) gpe_block->register_count * + ACPI_GPE_REGISTER_WIDTH) * sizeof (struct acpi_gpe_event_info)); if (!gpe_event_info) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not allocate the gpe_event_info table\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not allocate the gpe_event_info table\n")); status = AE_NO_MEMORY; goto error_exit; } @@ -899,7 +935,8 @@ acpi_ev_create_gpe_block ( gpe_block->block_base_number = gpe_block_base_number; gpe_block->node = gpe_device; - ACPI_MEMCPY (&gpe_block->block_address, gpe_block_address, sizeof (struct acpi_generic_address)); + ACPI_MEMCPY (&gpe_block->block_address, gpe_block_address, + sizeof (struct acpi_generic_address)); /* Create the register_info and event_info sub-structures */ @@ -1061,8 +1098,9 @@ acpi_ev_gpe_initialize ( /* Install GPE Block 0 */ - status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe0_blk, - register_count0, 0, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]); + status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, + &acpi_gbl_FADT->xgpe0_blk, register_count0, 0, + acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( @@ -1094,8 +1132,9 @@ acpi_ev_gpe_initialize ( else { /* Install GPE Block 1 */ - status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe1_blk, - register_count1, acpi_gbl_FADT->gpe1_base, + status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, + &acpi_gbl_FADT->xgpe1_blk, register_count1, + acpi_gbl_FADT->gpe1_base, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[1]); if (ACPI_FAILURE (status)) { @@ -1109,7 +1148,7 @@ acpi_ev_gpe_initialize ( * space. However, GPE0 always starts at GPE number zero. */ gpe_number_max = acpi_gbl_FADT->gpe1_base + - ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1); + ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1); } } diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index 2548efa7a45..659e9095611 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -50,6 +50,35 @@ ACPI_MODULE_NAME ("evmisc") +#ifdef ACPI_DEBUG_OUTPUT +static const char *acpi_notify_value_names[] = +{ + "Bus Check", + "Device Check", + "Device Wake", + "Eject request", + "Device Check Light", + "Frequency Mismatch", + "Bus Mode Mismatch", + "Power Fault" +}; +#endif + +/* Local prototypes */ + +static void ACPI_SYSTEM_XFACE +acpi_ev_notify_dispatch ( + void *context); + +static void ACPI_SYSTEM_XFACE +acpi_ev_global_lock_thread ( + void *context); + +static u32 +acpi_ev_global_lock_handler ( + void *context); + + /******************************************************************************* * * FUNCTION: acpi_ev_is_notify_object @@ -98,20 +127,6 @@ acpi_ev_is_notify_object ( * ******************************************************************************/ -#ifdef ACPI_DEBUG_OUTPUT -static const char *acpi_notify_value_names[] = -{ - "Bus Check", - "Device Check", - "Device Wake", - "Eject request", - "Device Check Light", - "Frequency Mismatch", - "Bus Mode Mismatch", - "Power Fault" -}; -#endif - acpi_status acpi_ev_queue_notify_request ( struct acpi_namespace_node *node, @@ -128,9 +143,10 @@ acpi_ev_queue_notify_request ( /* * For value 3 (Ejection Request), some device method may need to be run. - * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run. + * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need + * to be run. * For value 0x80 (Status Change) on the power button or sleep button, - * initiate soft-off or sleep operation? + * initiate soft-off or sleep operation? */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Dispatching Notify(%X) on node %p\n", notify_value, node)); @@ -140,8 +156,9 @@ acpi_ev_queue_notify_request ( acpi_notify_value_names[notify_value])); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: 0x%2.2X **Device Specific**\n", - notify_value)); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Notify value: 0x%2.2X **Device Specific**\n", + notify_value)); } /* Get the notify object attached to the NS Node */ @@ -210,7 +227,7 @@ acpi_ev_queue_notify_request ( * * FUNCTION: acpi_ev_notify_dispatch * - * PARAMETERS: Context - To be passsed to the notify handler + * PARAMETERS: Context - To be passed to the notify handler * * RETURN: None. * @@ -219,7 +236,7 @@ acpi_ev_queue_notify_request ( * ******************************************************************************/ -void ACPI_SYSTEM_XFACE +static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch ( void *context) { @@ -234,7 +251,8 @@ acpi_ev_notify_dispatch ( /* * We will invoke a global notify handler if installed. - * This is done _before_ we invoke the per-device handler attached to the device. + * This is done _before_ we invoke the per-device handler attached + * to the device. */ if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) { /* Global system notification handler */ @@ -256,15 +274,17 @@ acpi_ev_notify_dispatch ( /* Invoke the system handler first, if present */ if (global_handler) { - global_handler (notify_info->notify.node, notify_info->notify.value, global_context); + global_handler (notify_info->notify.node, notify_info->notify.value, + global_context); } /* Now invoke the per-device handler, if present */ handler_obj = notify_info->notify.handler_obj; if (handler_obj) { - handler_obj->notify.handler (notify_info->notify.node, notify_info->notify.value, - handler_obj->notify.context); + handler_obj->notify.handler (notify_info->notify.node, + notify_info->notify.value, + handler_obj->notify.context); } /* All done with the info object */ @@ -370,7 +390,8 @@ acpi_ev_global_lock_handler ( ******************************************************************************/ acpi_status -acpi_ev_init_global_lock_handler (void) +acpi_ev_init_global_lock_handler ( + void) { acpi_status status; @@ -380,7 +401,7 @@ acpi_ev_init_global_lock_handler (void) acpi_gbl_global_lock_present = TRUE; status = acpi_install_fixed_event_handler (ACPI_EVENT_GLOBAL, - acpi_ev_global_lock_handler, NULL); + acpi_ev_global_lock_handler, NULL); /* * If the global lock does not exist on this platform, the attempt @@ -433,8 +454,10 @@ acpi_ev_acquire_global_lock ( acpi_gbl_global_lock_thread_count++; - /* If we (OS side vs. BIOS side) have the hardware lock already, we are done */ - + /* + * If we (OS side vs. BIOS side) have the hardware lock already, + * we are done + */ if (acpi_gbl_global_lock_acquired) { return_ACPI_STATUS (AE_OK); } @@ -480,7 +503,8 @@ acpi_ev_acquire_global_lock ( ******************************************************************************/ acpi_status -acpi_ev_release_global_lock (void) +acpi_ev_release_global_lock ( + void) { u8 pending = FALSE; acpi_status status = AE_OK; @@ -490,7 +514,8 @@ acpi_ev_release_global_lock (void) if (!acpi_gbl_global_lock_thread_count) { - ACPI_REPORT_WARNING(("Cannot release HW Global Lock, it has not been acquired\n")); + ACPI_REPORT_WARNING(( + "Cannot release HW Global Lock, it has not been acquired\n")); return_ACPI_STATUS (AE_NOT_ACQUIRED); } @@ -515,7 +540,8 @@ acpi_ev_release_global_lock (void) * register */ if (pending) { - status = acpi_set_register (ACPI_BITREG_GLOBAL_LOCK_RELEASE, 1, ACPI_MTX_LOCK); + status = acpi_set_register (ACPI_BITREG_GLOBAL_LOCK_RELEASE, + 1, ACPI_MTX_LOCK); } return_ACPI_STATUS (status); @@ -535,7 +561,8 @@ acpi_ev_release_global_lock (void) ******************************************************************************/ void -acpi_ev_terminate (void) +acpi_ev_terminate ( + void) { acpi_native_uint i; acpi_status status; @@ -555,7 +582,8 @@ acpi_ev_terminate (void) for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { status = acpi_disable_event ((u32) i, 0); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not disable fixed event %d\n", (u32) i)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not disable fixed event %d\n", (u32) i)); } } @@ -567,7 +595,8 @@ acpi_ev_terminate (void) status = acpi_ev_remove_sci_handler (); if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not remove SCI handler\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not remove SCI handler\n")); } } diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 772342708a7..a1d7276c574 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -58,6 +58,22 @@ static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPA ACPI_ADR_SPACE_PCI_CONFIG, ACPI_ADR_SPACE_DATA_TABLE}; +/* Local prototypes */ + +static acpi_status +acpi_ev_reg_run ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); + +static acpi_status +acpi_ev_install_handler ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); + /******************************************************************************* * @@ -179,8 +195,8 @@ acpi_ev_initialize_op_regions ( * * FUNCTION: acpi_ev_execute_reg_method * - * PARAMETERS: region_obj - Object structure - * Function - Passed to _REG: On (1) or Off (0) + * PARAMETERS: region_obj - Region object + * Function - Passed to _REG: On (1) or Off (0) * * RETURN: Status * @@ -323,14 +339,16 @@ acpi_ev_address_space_dispatch ( if (!region_setup) { /* No initialization routine, exit with error */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No init routine for region(%p) [%s]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No init routine for region(%p) [%s]\n", region_obj, acpi_ut_get_region_name (region_obj->region.space_id))); return_ACPI_STATUS (AE_NOT_EXIST); } /* - * We must exit the interpreter because the region setup will potentially - * execute control methods (e.g., _REG method for this region) + * We must exit the interpreter because the region + * setup will potentially execute control methods + * (e.g., _REG method for this region) */ acpi_ex_exit_interpreter (); @@ -621,7 +639,7 @@ acpi_ev_attach_region ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ev_install_handler ( acpi_handle obj_handle, u32 level, @@ -848,7 +866,8 @@ acpi_ev_install_space_handler ( if (handler_obj->address_space.handler == handler) { /* * It is (relatively) OK to attempt to install the SAME - * handler twice. This can easily happen with PCI_Config space. + * handler twice. This can easily happen + * with PCI_Config space. */ status = AE_SAME_HANDLER; goto unlock_and_exit; @@ -1011,7 +1030,7 @@ acpi_ev_execute_reg_methods ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ev_reg_run ( acpi_handle obj_handle, u32 level, diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index 4983a3378be..95bc09c73a6 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -61,7 +61,7 @@ * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling, a nop for now + * DESCRIPTION: Setup a system_memory operation region * ******************************************************************************/ @@ -115,7 +115,7 @@ acpi_ev_system_memory_region_setup ( * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling + * DESCRIPTION: Setup a IO operation region * ******************************************************************************/ @@ -144,14 +144,14 @@ acpi_ev_io_space_region_setup ( * * FUNCTION: acpi_ev_pci_config_region_setup * - * PARAMETERS: Handle - Region we are interested in + * PARAMETERS: Handle - Region we are interested in * Function - Start or stop * handler_context - Address space handler context * region_context - Region specific context * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling + * DESCRIPTION: Setup a PCI_Config operation region * * MUTEX: Assumes namespace is not locked * @@ -324,7 +324,7 @@ acpi_ev_pci_config_region_setup ( * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling + * DESCRIPTION: Setup a pci_bAR operation region * * MUTEX: Assumes namespace is not locked * @@ -355,7 +355,7 @@ acpi_ev_pci_bar_region_setup ( * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling + * DESCRIPTION: Setup a CMOS operation region * * MUTEX: Assumes namespace is not locked * @@ -386,7 +386,7 @@ acpi_ev_cmos_region_setup ( * * RETURN: Status * - * DESCRIPTION: Do any prep work for region handling + * DESCRIPTION: Default region initialization * ******************************************************************************/ diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c index 46b31995c82..f3123c26ae9 100644 --- a/drivers/acpi/events/evsci.c +++ b/drivers/acpi/events/evsci.c @@ -49,6 +49,12 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evsci") +/* Local prototypes */ + +static u32 ACPI_SYSTEM_XFACE +acpi_ev_sci_xrupt_handler ( + void *context); + /******************************************************************************* * @@ -146,7 +152,8 @@ acpi_ev_gpe_xrupt_handler ( ******************************************************************************/ u32 -acpi_ev_install_sci_handler (void) +acpi_ev_install_sci_handler ( + void) { u32 status = AE_OK; @@ -180,7 +187,8 @@ acpi_ev_install_sci_handler (void) ******************************************************************************/ acpi_status -acpi_ev_remove_sci_handler (void) +acpi_ev_remove_sci_handler ( + void) { acpi_status status; diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index 0bfec10a5f1..4092d47f675 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -64,6 +64,7 @@ * DESCRIPTION: Saves the pointer to the handler function * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_install_exception_handler ( @@ -457,7 +458,8 @@ acpi_remove_notify_handler ( /* Root Object */ if (device == ACPI_ROOT_OBJECT) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for ROOT object.\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Removing notify handler for ROOT object.\n")); if (((handler_type & ACPI_SYSTEM_NOTIFY) && !acpi_gbl_system_notify.handler) || @@ -564,8 +566,9 @@ EXPORT_SYMBOL(acpi_remove_notify_handler); * * FUNCTION: acpi_install_gpe_handler * - * PARAMETERS: gpe_number - The GPE number within the GPE block - * gpe_block - GPE block (NULL == FADT GPEs) + * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * gpe_number - The GPE number within the GPE block * Type - Whether this GPE should be treated as an * edge- or level-triggered interrupt. * Address - Address of the handler @@ -662,8 +665,9 @@ EXPORT_SYMBOL(acpi_install_gpe_handler); * * FUNCTION: acpi_remove_gpe_handler * - * PARAMETERS: gpe_number - The event to remove a handler - * gpe_block - GPE block (NULL == FADT GPEs) + * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT + * defined GPEs) + * gpe_number - The event to remove a handler * Address - Address of the handler * * RETURN: Status @@ -766,7 +770,8 @@ EXPORT_SYMBOL(acpi_remove_gpe_handler); * FUNCTION: acpi_acquire_global_lock * * PARAMETERS: Timeout - How long the caller is willing to wait - * out_handle - A handle to the lock if acquired + * Handle - Where the handle to the lock is returned + * (if acquired) * * RETURN: Status * @@ -812,7 +817,7 @@ EXPORT_SYMBOL(acpi_acquire_global_lock); * * RETURN: Status * - * DESCRIPTION: Release the ACPI Global Lock + * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid. * ******************************************************************************/ diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c index fa8d5f25be6..f337dc2cc56 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/events/evxfevnt.c @@ -64,7 +64,8 @@ ******************************************************************************/ acpi_status -acpi_enable (void) +acpi_enable ( + void) { acpi_status status = AE_OK; @@ -91,7 +92,8 @@ acpi_enable (void) return_ACPI_STATUS (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Transition to ACPI mode successful\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "Transition to ACPI mode successful\n")); } return_ACPI_STATUS (status); @@ -106,12 +108,13 @@ acpi_enable (void) * * RETURN: Status * - * DESCRIPTION: Transfers the system into LEGACY mode. + * DESCRIPTION: Transfers the system into LEGACY (non-ACPI) mode. * ******************************************************************************/ acpi_status -acpi_disable (void) +acpi_disable ( + void) { acpi_status status = AE_OK; @@ -125,7 +128,8 @@ acpi_disable (void) } if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) { - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "System is already in legacy (non-ACPI) mode\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "System is already in legacy (non-ACPI) mode\n")); } else { /* Transition to LEGACY mode */ @@ -133,7 +137,8 @@ acpi_disable (void) status = acpi_hw_set_mode (ACPI_SYS_MODE_LEGACY); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not exit ACPI mode to legacy mode")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not exit ACPI mode to legacy mode")); return_ACPI_STATUS (status); } @@ -214,7 +219,7 @@ EXPORT_SYMBOL(acpi_enable_event); * * RETURN: Status * - * DESCRIPTION: Enable an ACPI event (general purpose) + * DESCRIPTION: Set the type of an individual GPE * ******************************************************************************/ @@ -519,13 +524,12 @@ unlock_and_exit: #ifdef ACPI_FUTURE_USAGE - /******************************************************************************* * * FUNCTION: acpi_get_event_status * * PARAMETERS: Event - The fixed event - * Event Status - Where the current status of the event will + * event_status - Where the current status of the event will * be returned * * RETURN: Status @@ -571,7 +575,7 @@ acpi_get_event_status ( * PARAMETERS: gpe_device - Parent GPE Device * gpe_number - GPE level within the GPE block * Flags - Called from an ISR or not - * Event Status - Where the current status of the event will + * event_status - Where the current status of the event will * be returned * * RETURN: Status @@ -775,4 +779,5 @@ unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); } + EXPORT_SYMBOL(acpi_remove_gpe_block); diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index ac3c061967f..734b2f24af4 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -54,6 +54,14 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exconfig") +/* Local prototypes */ + +static acpi_status +acpi_ex_add_table ( + struct acpi_table_header *table, + struct acpi_namespace_node *parent_node, + union acpi_operand_object **ddb_handle); + /******************************************************************************* * @@ -70,7 +78,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_add_table ( struct acpi_table_header *table, struct acpi_namespace_node *parent_node, @@ -95,10 +103,10 @@ acpi_ex_add_table ( ACPI_MEMSET (&table_info, 0, sizeof (struct acpi_table_desc)); - table_info.type = ACPI_TABLE_SSDT; - table_info.pointer = table; - table_info.length = (acpi_size) table->length; - table_info.allocation = ACPI_MEM_ALLOCATED; + table_info.type = ACPI_TABLE_SSDT; + table_info.pointer = table; + table_info.length = (acpi_size) table->length; + table_info.allocation = ACPI_MEM_ALLOCATED; status = acpi_tb_install_table (&table_info); if (ACPI_FAILURE (status)) { @@ -226,11 +234,10 @@ acpi_ex_load_table_op ( start_node = parent_node; } - /* - * Find the node referenced by the parameter_path_string - */ + /* Find the node referenced by the parameter_path_string */ + status = acpi_ns_get_node_by_path (operand[4]->string.pointer, start_node, - ACPI_NS_SEARCH_PARENT, ¶meter_node); + ACPI_NS_SEARCH_PARENT, ¶meter_node); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -248,7 +255,8 @@ acpi_ex_load_table_op ( if (parameter_node) { /* Store the parameter data into the optional parameter object */ - status = acpi_ex_store (operand[5], ACPI_CAST_PTR (union acpi_operand_object, parameter_node), + status = acpi_ex_store (operand[5], + ACPI_CAST_PTR (union acpi_operand_object, parameter_node), walk_state); if (ACPI_FAILURE (status)) { (void) acpi_ex_unload_table (ddb_handle); @@ -371,7 +379,8 @@ acpi_ex_load_op ( goto cleanup; } - table_ptr = ACPI_CAST_PTR (struct acpi_table_header, buffer_desc->buffer.pointer); + table_ptr = ACPI_CAST_PTR (struct acpi_table_header, + buffer_desc->buffer.pointer); /* Sanity check the table length */ diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c index df7ba1219bf..97856c48bd7 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/executer/exconvrt.c @@ -50,6 +50,15 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exconvrt") +/* Local prototypes */ + +static u32 +acpi_ex_convert_to_ascii ( + acpi_integer integer, + u16 base, + u8 *string, + u8 max_length); + /******************************************************************************* * @@ -115,9 +124,8 @@ acpi_ex_convert_to_integer ( */ result = 0; - /* - * String conversion is different than Buffer conversion - */ + /* String conversion is different than Buffer conversion */ + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { case ACPI_TYPE_STRING: @@ -168,9 +176,8 @@ acpi_ex_convert_to_integer ( break; } - /* - * Create a new integer - */ + /* Create a new integer */ + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); if (!return_desc) { return_ACPI_STATUS (AE_NO_MEMORY); @@ -251,7 +258,8 @@ acpi_ex_convert_to_buffer ( * ASL/AML code that depends on the null being transferred to the new * buffer. */ - return_desc = acpi_ut_create_buffer_object ((acpi_size) obj_desc->string.length + 1); + return_desc = acpi_ut_create_buffer_object ( + (acpi_size) obj_desc->string.length + 1); if (!return_desc) { return_ACPI_STATUS (AE_NO_MEMORY); } @@ -291,7 +299,7 @@ acpi_ex_convert_to_buffer ( * ******************************************************************************/ -u32 +static u32 acpi_ex_convert_to_ascii ( acpi_integer integer, u16 base, @@ -357,8 +365,9 @@ acpi_ex_convert_to_ascii ( case 16: - hex_length = ACPI_MUL_2 (data_width); /* 2 ascii hex chars per data byte */ + /* hex_length: 2 ascii hex chars per data byte */ + hex_length = ACPI_MUL_2 (data_width); for (i = 0, j = (hex_length-1); i < hex_length; i++, j--) { /* Get one hex digit, most significant digits first */ @@ -475,7 +484,7 @@ acpi_ex_convert_to_string ( /* Setup string length, base, and separator */ switch (type) { - case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by to_decimal_string operator */ + case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by to_decimal_string */ /* * From ACPI: "If Data is a buffer, it is converted to a string of * decimal values separated by commas." @@ -509,7 +518,7 @@ acpi_ex_convert_to_string ( string_length = (obj_desc->buffer.length * 3); break; - case ACPI_EXPLICIT_CONVERT_HEX: /* Used by to_hex_string operator */ + case ACPI_EXPLICIT_CONVERT_HEX: /* Used by to_hex_string */ /* * From ACPI: "If Data is a buffer, it is converted to a string of * hexadecimal values separated by commas." @@ -530,9 +539,8 @@ acpi_ex_convert_to_string ( return_ACPI_STATUS (AE_AML_STRING_LIMIT); } - /* - * Create a new string object and string buffer - */ + /* Create a new string object and string buffer */ + return_desc = acpi_ut_create_string_object ((acpi_size) string_length); if (!return_desc) { return_ACPI_STATUS (AE_NO_MEMORY); @@ -551,8 +559,10 @@ acpi_ex_convert_to_string ( *new_buf++ = separator; /* each separated by a comma or space */ } - /* Null terminate the string (overwrites final comma/space from above) */ - + /* + * Null terminate the string + * (overwrites final comma/space from above) + */ new_buf--; *new_buf = 0; break; @@ -645,7 +655,6 @@ acpi_ex_convert_to_target_type ( case ACPI_TYPE_STRING: - /* * The operand must be a String. We can convert an * Integer or Buffer if necessary @@ -656,7 +665,6 @@ acpi_ex_convert_to_target_type ( case ACPI_TYPE_BUFFER: - /* * The operand must be a Buffer. We can convert an * Integer or String if necessary diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c index d94c260dac6..812cdcb2e37 100644 --- a/drivers/acpi/executer/excreate.c +++ b/drivers/acpi/executer/excreate.c @@ -55,7 +55,7 @@ #ifndef ACPI_NO_METHOD_EXECUTION -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_alias * @@ -65,7 +65,7 @@ * * DESCRIPTION: Create a new named alias * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_alias ( @@ -140,8 +140,7 @@ acpi_ex_create_alias ( * target node or the alias Node */ status = acpi_ns_attach_object (alias_node, - acpi_ns_get_attached_object (target_node), - target_node->type); + acpi_ns_get_attached_object (target_node), target_node->type); break; } @@ -151,7 +150,7 @@ acpi_ex_create_alias ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_event * @@ -161,7 +160,7 @@ acpi_ex_create_alias ( * * DESCRIPTION: Create a new event object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_event ( @@ -185,7 +184,7 @@ acpi_ex_create_event ( * that the event is created in an unsignalled state */ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0, - &obj_desc->event.semaphore); + &obj_desc->event.semaphore); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -193,7 +192,7 @@ acpi_ex_create_event ( /* Attach object to the Node */ status = acpi_ns_attach_object ((struct acpi_namespace_node *) walk_state->operands[0], - obj_desc, ACPI_TYPE_EVENT); + obj_desc, ACPI_TYPE_EVENT); cleanup: /* @@ -205,7 +204,7 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_mutex * @@ -217,7 +216,7 @@ cleanup: * * Mutex (Name[0], sync_level[1]) * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_mutex ( @@ -267,20 +266,20 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_region * * PARAMETERS: aml_start - Pointer to the region declaration AML * aml_length - Max length of the declaration AML - * Operands - List of operands for the opcode + * region_space - space_iD for the region * walk_state - Current state * * RETURN: Status * * DESCRIPTION: Create a new operation region object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_region ( @@ -321,7 +320,7 @@ acpi_ex_create_region ( } ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Region Type - %s (%X)\n", - acpi_ut_get_region_name (region_space), region_space)); + acpi_ut_get_region_name (region_space), region_space)); /* Create the region descriptor */ @@ -360,7 +359,7 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_table_region * @@ -370,7 +369,7 @@ cleanup: * * DESCRIPTION: Create a new data_table_region object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_table_region ( @@ -455,7 +454,7 @@ cleanup: } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_processor * @@ -467,7 +466,7 @@ cleanup: * * Processor (Name[0], cpu_iD[1], pblock_addr[2], pblock_length[3]) * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_processor ( @@ -488,9 +487,8 @@ acpi_ex_create_processor ( return_ACPI_STATUS (AE_NO_MEMORY); } - /* - * Initialize the processor object from the operands - */ + /* Initialize the processor object from the operands */ + obj_desc->processor.proc_id = (u8) operand[1]->integer.value; obj_desc->processor.address = (acpi_io_address) operand[2]->integer.value; obj_desc->processor.length = (u8) operand[3]->integer.value; @@ -507,7 +505,7 @@ acpi_ex_create_processor ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_create_power_resource * @@ -519,7 +517,7 @@ acpi_ex_create_processor ( * * power_resource (Name[0], system_level[1], resource_order[2]) * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_power_resource ( @@ -555,10 +553,10 @@ acpi_ex_create_power_resource ( acpi_ut_remove_reference (obj_desc); return_ACPI_STATUS (status); } - #endif -/***************************************************************************** + +/******************************************************************************* * * FUNCTION: acpi_ex_create_method * @@ -570,7 +568,7 @@ acpi_ex_create_power_resource ( * * DESCRIPTION: Create a new method object * - ****************************************************************************/ + ******************************************************************************/ acpi_status acpi_ex_create_method ( diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index e2f7c32f28d..40850064811 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -51,23 +51,48 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exdump") +/* Local prototypes */ + +#ifdef ACPI_FUTURE_USAGE +static void +acpi_ex_out_string ( + char *title, + char *value); + +static void +acpi_ex_out_pointer ( + char *title, + void *value); + +static void +acpi_ex_out_integer ( + char *title, + u32 value); + +static void +acpi_ex_out_address ( + char *title, + acpi_physical_address value); +#endif /* ACPI_FUTURE_USAGE */ + /* * The following routines are used for debug output only */ #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_dump_operand * - * PARAMETERS: *obj_desc - Pointer to entry to be dumped + * PARAMETERS: *obj_desc - Pointer to entry to be dumped + * Depth - Current nesting depth * * RETURN: None * * DESCRIPTION: Dump an operand object * - ****************************************************************************/ + ******************************************************************************/ void acpi_ex_dump_operand ( @@ -86,9 +111,8 @@ acpi_ex_dump_operand ( } if (!obj_desc) { - /* - * This could be a null element of a package - */ + /* This could be a null element of a package */ + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Null Object Descriptor\n")); return; } @@ -117,6 +141,8 @@ acpi_ex_dump_operand ( ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p ", obj_desc)); } + /* Decode object type */ + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { case ACPI_TYPE_LOCAL_REFERENCE: @@ -274,7 +300,9 @@ acpi_ex_dump_operand ( case ACPI_TYPE_STRING: acpi_os_printf ("String length %X @ %p ", - obj_desc->string.length, obj_desc->string.pointer); + obj_desc->string.length, + obj_desc->string.pointer); + acpi_ut_print_string (obj_desc->string.pointer, ACPI_UINT8_MAX); acpi_os_printf ("\n"); break; @@ -290,10 +318,13 @@ acpi_ex_dump_operand ( acpi_os_printf ( "region_field: Bits=%X acc_width=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n", - obj_desc->field.bit_length, obj_desc->field.access_byte_width, + obj_desc->field.bit_length, + obj_desc->field.access_byte_width, obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK, obj_desc->field.field_flags & AML_FIELD_UPDATE_RULE_MASK, - obj_desc->field.base_byte_offset, obj_desc->field.start_field_bit_offset); + obj_desc->field.base_byte_offset, + obj_desc->field.start_field_bit_offset); + acpi_ex_dump_operand (obj_desc->field.region_obj, depth+1); break; @@ -308,13 +339,15 @@ acpi_ex_dump_operand ( acpi_os_printf ( "buffer_field: %X bits at byte %X bit %X of \n", - obj_desc->buffer_field.bit_length, obj_desc->buffer_field.base_byte_offset, + obj_desc->buffer_field.bit_length, + obj_desc->buffer_field.base_byte_offset, obj_desc->buffer_field.start_field_bit_offset); if (!obj_desc->buffer_field.buffer_obj) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*NULL* \n")); } - else if (ACPI_GET_OBJECT_TYPE (obj_desc->buffer_field.buffer_obj) != ACPI_TYPE_BUFFER) { + else if (ACPI_GET_OBJECT_TYPE (obj_desc->buffer_field.buffer_obj) != + ACPI_TYPE_BUFFER) { acpi_os_printf ("*not a Buffer* \n"); } else { @@ -331,10 +364,10 @@ acpi_ex_dump_operand ( case ACPI_TYPE_METHOD: - acpi_os_printf ( - "Method(%X) @ %p:%X\n", + acpi_os_printf ("Method(%X) @ %p:%X\n", obj_desc->method.param_count, - obj_desc->method.aml_start, obj_desc->method.aml_length); + obj_desc->method.aml_start, + obj_desc->method.aml_length); break; @@ -379,7 +412,7 @@ acpi_ex_dump_operand ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_dump_operands * @@ -393,7 +426,7 @@ acpi_ex_dump_operand ( * * DESCRIPTION: Dump the object stack * - ****************************************************************************/ + ******************************************************************************/ void acpi_ex_dump_operands ( @@ -441,10 +474,9 @@ acpi_ex_dump_operands ( #ifdef ACPI_FUTURE_USAGE - -/***************************************************************************** +/******************************************************************************* * - * FUNCTION: acpi_ex_out* + * FUNCTION: acpi_ex_out* functions * * PARAMETERS: Title - Descriptive text * Value - Value to be displayed @@ -453,9 +485,9 @@ acpi_ex_dump_operands ( * reduce the number of format strings required and keeps them * all in one place for easy modification. * - ****************************************************************************/ + ******************************************************************************/ -void +static void acpi_ex_out_string ( char *title, char *value) @@ -463,7 +495,7 @@ acpi_ex_out_string ( acpi_os_printf ("%20s : %s\n", title, value); } -void +static void acpi_ex_out_pointer ( char *title, void *value) @@ -471,7 +503,7 @@ acpi_ex_out_pointer ( acpi_os_printf ("%20s : %p\n", title, value); } -void +static void acpi_ex_out_integer ( char *title, u32 value) @@ -479,7 +511,7 @@ acpi_ex_out_integer ( acpi_os_printf ("%20s : %X\n", title, value); } -void +static void acpi_ex_out_address ( char *title, acpi_physical_address value) @@ -493,16 +525,16 @@ acpi_ex_out_address ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_dump_node * * PARAMETERS: *Node - Descriptor to dump - * Flags - Force display + * Flags - Force display if TRUE * * DESCRIPTION: Dumps the members of the given.Node * - ****************************************************************************/ + ******************************************************************************/ void acpi_ex_dump_node ( @@ -531,16 +563,16 @@ acpi_ex_dump_node ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ex_dump_object_descriptor * * PARAMETERS: *Object - Descriptor to dump - * Flags - Force display + * Flags - Force display if TRUE * * DESCRIPTION: Dumps the members of the object descriptor given. * - ****************************************************************************/ + ******************************************************************************/ void acpi_ex_dump_object_descriptor ( @@ -553,6 +585,10 @@ acpi_ex_dump_object_descriptor ( ACPI_FUNCTION_TRACE ("ex_dump_object_descriptor"); + if (!obj_desc) { + return_VOID; + } + if (!flags) { if (!((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { return_VOID; @@ -747,11 +783,17 @@ acpi_ex_dump_object_descriptor ( case ACPI_TYPE_LOCAL_REFERENCE: acpi_ex_out_integer ("target_type", obj_desc->reference.target_type); - acpi_ex_out_string ("Opcode", (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name); + acpi_ex_out_string ("Opcode", (acpi_ps_get_opcode_info ( + obj_desc->reference.opcode))->name); acpi_ex_out_integer ("Offset", obj_desc->reference.offset); acpi_ex_out_pointer ("obj_desc", obj_desc->reference.object); acpi_ex_out_pointer ("Node", obj_desc->reference.node); acpi_ex_out_pointer ("Where", obj_desc->reference.where); + + if (obj_desc->reference.object) { + acpi_os_printf ("\nReferenced Object:\n"); + acpi_ex_dump_object_descriptor (obj_desc->reference.object, flags); + } break; @@ -788,6 +830,5 @@ acpi_ex_dump_object_descriptor ( } #endif /* ACPI_FUTURE_USAGE */ - #endif diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c index be7f2124fa0..22c8fa480f6 100644 --- a/drivers/acpi/executer/exfield.c +++ b/drivers/acpi/executer/exfield.c @@ -120,8 +120,8 @@ acpi_ex_read_data_from_field ( * Note: Smbus protocol value is passed in upper 16-bits of Function */ status = acpi_ex_access_region (obj_desc, 0, - ACPI_CAST_PTR (acpi_integer, buffer_desc->buffer.pointer), - ACPI_READ | (obj_desc->field.attribute << 16)); + ACPI_CAST_PTR (acpi_integer, buffer_desc->buffer.pointer), + ACPI_READ | (obj_desc->field.attribute << 16)); acpi_ex_release_global_lock (locked); goto exit; } @@ -196,6 +196,7 @@ exit: * * PARAMETERS: source_desc - Contains data to write * obj_desc - The named field + * result_desc - Where the return value is returned, if any * * RETURN: Status * @@ -250,12 +251,15 @@ acpi_ex_write_data_to_field ( if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) { ACPI_REPORT_ERROR (("SMBus write requires Buffer, found type %s\n", acpi_ut_get_object_type_name (source_desc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) { - ACPI_REPORT_ERROR (("SMBus write requires Buffer of length %X, found length %X\n", + ACPI_REPORT_ERROR (( + "SMBus write requires Buffer of length %X, found length %X\n", ACPI_SMBUS_BUFFER_SIZE, source_desc->buffer.length)); + return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); } @@ -265,14 +269,16 @@ acpi_ex_write_data_to_field ( } buffer = buffer_desc->buffer.pointer; - ACPI_MEMCPY (buffer, source_desc->buffer.pointer, ACPI_SMBUS_BUFFER_SIZE); + ACPI_MEMCPY (buffer, source_desc->buffer.pointer, + ACPI_SMBUS_BUFFER_SIZE); /* Lock entire transaction if requested */ locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); /* - * Perform the write (returns status and perhaps data in the same buffer) + * Perform the write (returns status and perhaps data in the + * same buffer) * Note: SMBus protocol type is passed in upper 16-bits of Function. */ status = acpi_ex_access_region (obj_desc, 0, @@ -284,9 +290,8 @@ acpi_ex_write_data_to_field ( return_ACPI_STATUS (status); } - /* - * Get a pointer to the data to be written - */ + /* Get a pointer to the data to be written */ + switch (ACPI_GET_OBJECT_TYPE (source_desc)) { case ACPI_TYPE_INTEGER: buffer = &source_desc->integer.value; @@ -314,7 +319,8 @@ acpi_ex_write_data_to_field ( * the ACPI specification. */ new_buffer = NULL; - required_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); + required_length = ACPI_ROUND_BITS_UP_TO_BYTES ( + obj_desc->common_field.bit_length); if (length < required_length) { /* We need to create a new buffer */ @@ -338,6 +344,7 @@ acpi_ex_write_data_to_field ( "field_write [FROM]: Obj %p (%s:%X), Buf %p, byte_len %X\n", source_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (source_desc)), ACPI_GET_OBJECT_TYPE (source_desc), buffer, length)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "field_write [TO]: Obj %p (%s:%X), bit_len %X, bit_off %X, byte_off %X\n", obj_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (obj_desc)), diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c index 9d0f9d2e906..3c2f89e00f7 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/executer/exfldio.c @@ -52,12 +52,31 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exfldio") +/* Local prototypes */ + +static acpi_status +acpi_ex_field_datum_io ( + union acpi_operand_object *obj_desc, + u32 field_datum_byte_offset, + acpi_integer *value, + u32 read_write); + +static u8 +acpi_ex_register_overflow ( + union acpi_operand_object *obj_desc, + acpi_integer value); + +static acpi_status +acpi_ex_setup_region ( + union acpi_operand_object *obj_desc, + u32 field_datum_byte_offset); + /******************************************************************************* * * FUNCTION: acpi_ex_setup_region * - * PARAMETERS: *obj_desc - Field to be read or written + * PARAMETERS: obj_desc - Field to be read or written * field_datum_byte_offset - Byte offset of this datum within the * parent field * @@ -69,7 +88,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_setup_region ( union acpi_operand_object *obj_desc, u32 field_datum_byte_offset) @@ -127,9 +146,9 @@ acpi_ex_setup_region ( * length of one field datum (access width) must fit within the region. * (Region length is specified in bytes) */ - if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset - + field_datum_byte_offset - + obj_desc->common_field.access_byte_width)) { + if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + + field_datum_byte_offset + + obj_desc->common_field.access_byte_width)) { if (acpi_gbl_enable_interpreter_slack) { /* * Slack mode only: We will go ahead and allow access to this @@ -155,7 +174,8 @@ acpi_ex_setup_region ( "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", acpi_ut_get_node_name (obj_desc->common_field.node), obj_desc->common_field.access_byte_width, - acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); + acpi_ut_get_node_name (rgn_desc->region.node), + rgn_desc->region.length)); } /* @@ -167,7 +187,8 @@ acpi_ex_setup_region ( acpi_ut_get_node_name (obj_desc->common_field.node), obj_desc->common_field.base_byte_offset, field_datum_byte_offset, obj_desc->common_field.access_byte_width, - acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); + acpi_ut_get_node_name (rgn_desc->region.node), + rgn_desc->region.length)); return_ACPI_STATUS (AE_AML_REGION_LIMIT); } @@ -180,10 +201,10 @@ acpi_ex_setup_region ( * * FUNCTION: acpi_ex_access_region * - * PARAMETERS: *obj_desc - Field to be read + * PARAMETERS: obj_desc - Field to be read * field_datum_byte_offset - Byte offset of this datum within the * parent field - * *Value - Where to store value (must at least + * Value - Where to store value (must at least * the size of acpi_integer) * Function - Read or Write flag plus other region- * dependent flags @@ -226,9 +247,9 @@ acpi_ex_access_region ( * 3) The current offset into the field */ rgn_desc = obj_desc->common_field.region_obj; - address = rgn_desc->region.address - + obj_desc->common_field.base_byte_offset - + field_datum_byte_offset; + address = rgn_desc->region.address + + obj_desc->common_field.base_byte_offset + + field_datum_byte_offset; if ((function & ACPI_IO_MASK) == ACPI_READ) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); @@ -249,7 +270,8 @@ acpi_ex_access_region ( /* Invoke the appropriate address_space/op_region handler */ status = acpi_ev_address_space_dispatch (rgn_desc, function, - address, ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value); + address, + ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value); if (ACPI_FAILURE (status)) { if (status == AE_NOT_IMPLEMENTED) { @@ -274,7 +296,7 @@ acpi_ex_access_region ( * * FUNCTION: acpi_ex_register_overflow * - * PARAMETERS: *obj_desc - Register(Field) to be written + * PARAMETERS: obj_desc - Register(Field) to be written * Value - Value to be stored * * RETURN: TRUE if value overflows the field, FALSE otherwise @@ -287,7 +309,7 @@ acpi_ex_access_region ( * ******************************************************************************/ -u8 +static u8 acpi_ex_register_overflow ( union acpi_operand_object *obj_desc, acpi_integer value) @@ -319,10 +341,10 @@ acpi_ex_register_overflow ( * * FUNCTION: acpi_ex_field_datum_io * - * PARAMETERS: *obj_desc - Field to be read + * PARAMETERS: obj_desc - Field to be read * field_datum_byte_offset - Byte offset of this datum within the * parent field - * *Value - Where to store value (must be 64 bits) + * Value - Where to store value (must be 64 bits) * read_write - Read or Write flag * * RETURN: Status @@ -333,7 +355,7 @@ acpi_ex_register_overflow ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_field_datum_io ( union acpi_operand_object *obj_desc, u32 field_datum_byte_offset, @@ -350,7 +372,9 @@ acpi_ex_field_datum_io ( if (read_write == ACPI_READ) { if (!value) { local_value = 0; - value = &local_value; /* To support reads without saving return value */ + + /* To support reads without saving return value */ + value = &local_value; } /* Clear the entire return buffer first, [Very Important!] */ @@ -363,8 +387,10 @@ acpi_ex_field_datum_io ( * * buffer_field - Read/write from/to a Buffer * region_field - Read/write from/to a Operation Region. - * bank_field - Write to a Bank Register, then read/write from/to an op_region - * index_field - Write to an Index Register, then read/write from/to a Data Register + * bank_field - Write to a Bank Register, then read/write from/to an + * operation_region + * index_field - Write to an Index Register, then read/write from/to a + * Data Register */ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { case ACPI_TYPE_BUFFER_FIELD: @@ -384,19 +410,20 @@ acpi_ex_field_datum_io ( * Copy the data from the source buffer. * Length is the field width in bytes. */ - ACPI_MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer - + obj_desc->buffer_field.base_byte_offset - + field_datum_byte_offset, - obj_desc->common_field.access_byte_width); + ACPI_MEMCPY (value, + (obj_desc->buffer_field.buffer_obj)->buffer.pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, + obj_desc->common_field.access_byte_width); } else { /* * Copy the data to the target buffer. * Length is the field width in bytes. */ - ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer - + obj_desc->buffer_field.base_byte_offset - + field_datum_byte_offset, + ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, value, obj_desc->common_field.access_byte_width); } @@ -406,8 +433,10 @@ acpi_ex_field_datum_io ( case ACPI_TYPE_LOCAL_BANK_FIELD: - /* Ensure that the bank_value is not beyond the capacity of the register */ - + /* + * Ensure that the bank_value is not beyond the capacity of + * the register + */ if (acpi_ex_register_overflow (obj_desc->bank_field.bank_obj, (acpi_integer) obj_desc->bank_field.value)) { return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); @@ -445,8 +474,10 @@ acpi_ex_field_datum_io ( case ACPI_TYPE_LOCAL_INDEX_FIELD: - /* Ensure that the index_value is not beyond the capacity of the register */ - + /* + * Ensure that the index_value is not beyond the capacity of + * the register + */ if (acpi_ex_register_overflow (obj_desc->index_field.index_obj, (acpi_integer) obj_desc->index_field.value)) { return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); @@ -496,14 +527,16 @@ acpi_ex_field_datum_io ( if (ACPI_SUCCESS (status)) { if (read_write == ACPI_READ) { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n", - ACPI_FORMAT_UINT64 (*value), - obj_desc->common_field.access_byte_width)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Value Read %8.8X%8.8X, Width %d\n", + ACPI_FORMAT_UINT64 (*value), + obj_desc->common_field.access_byte_width)); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n", - ACPI_FORMAT_UINT64 (*value), - obj_desc->common_field.access_byte_width)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Value Written %8.8X%8.8X, Width %d\n", + ACPI_FORMAT_UINT64 (*value), + obj_desc->common_field.access_byte_width)); } } @@ -515,8 +548,10 @@ acpi_ex_field_datum_io ( * * FUNCTION: acpi_ex_write_with_update_rule * - * PARAMETERS: *obj_desc - Field to be set - * Value - Value to store + * PARAMETERS: obj_desc - Field to be written + * Mask - bitmask within field datum + * field_value - Value to write + * field_datum_byte_offset - Offset of datum within field * * RETURN: Status * @@ -689,7 +724,8 @@ acpi_ex_extract_from_field ( /* Merge with previous datum if necessary */ merged_datum |= raw_datum << - (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset); + (obj_desc->common_field.access_bit_width - + obj_desc->common_field.start_field_bit_offset); if (i == datum_count) { break; @@ -707,7 +743,8 @@ acpi_ex_extract_from_field ( /* Mask off any extra bits in the last datum */ - buffer_tail_bits = obj_desc->common_field.bit_length % obj_desc->common_field.access_bit_width; + buffer_tail_bits = obj_desc->common_field.bit_length % + obj_desc->common_field.access_bit_width; if (buffer_tail_bits) { merged_datum &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits); } @@ -791,7 +828,8 @@ acpi_ex_insert_into_field ( /* Write merged datum to the target field */ merged_datum &= mask; - status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset); + status = acpi_ex_write_with_update_rule (obj_desc, mask, + merged_datum, field_offset); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -800,7 +838,8 @@ acpi_ex_insert_into_field ( field_offset += obj_desc->common_field.access_byte_width; merged_datum = raw_datum >> - (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset); + (obj_desc->common_field.access_bit_width - + obj_desc->common_field.start_field_bit_offset); mask = ACPI_INTEGER_MAX; if (i == datum_count) { @@ -819,7 +858,8 @@ acpi_ex_insert_into_field ( /* Mask off any extra bits in the last datum */ buffer_tail_bits = (obj_desc->common_field.bit_length + - obj_desc->common_field.start_field_bit_offset) % obj_desc->common_field.access_bit_width; + obj_desc->common_field.start_field_bit_offset) % + obj_desc->common_field.access_bit_width; if (buffer_tail_bits) { mask &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits); } @@ -827,7 +867,8 @@ acpi_ex_insert_into_field ( /* Write the last datum to the field */ merged_datum &= mask; - status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset); + status = acpi_ex_write_with_update_rule (obj_desc, + mask, merged_datum, field_offset); return_ACPI_STATUS (status); } diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c index b542dcd58c0..022f281345b 100644 --- a/drivers/acpi/executer/exmisc.c +++ b/drivers/acpi/executer/exmisc.c @@ -139,8 +139,9 @@ acpi_ex_get_object_reference ( reference_obj->reference.object = referenced_obj; *return_desc = reference_obj; - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Object %p Type [%s], returning Reference %p\n", - obj_desc, acpi_ut_get_object_type_name (obj_desc), *return_desc)); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Object %p Type [%s], returning Reference %p\n", + obj_desc, acpi_ut_get_object_type_name (obj_desc), *return_desc)); return_ACPI_STATUS (AE_OK); } @@ -456,7 +457,7 @@ acpi_ex_do_math_op ( return (integer0 * integer1); - case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result) */ + case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result)*/ return (integer0 << integer1); diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index 68c4bb1970a..c3cb714d2cb 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -49,6 +49,13 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exmutex") +/* Local prototypes */ + +static void +acpi_ex_link_mutex ( + union acpi_operand_object *obj_desc, + struct acpi_thread_state *thread); + /******************************************************************************* * @@ -56,7 +63,7 @@ * * PARAMETERS: obj_desc - The mutex to be unlinked * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Remove a mutex from the "acquired_mutex" list * @@ -92,16 +99,16 @@ acpi_ex_unlink_mutex ( * * FUNCTION: acpi_ex_link_mutex * - * PARAMETERS: obj_desc - The mutex to be linked - * list_head - head of the "acquired_mutex" list + * PARAMETERS: obj_desc - The mutex to be linked + * Thread - Current executing thread object * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Add a mutex to the "acquired_mutex" list for this walk * ******************************************************************************/ -void +static void acpi_ex_link_mutex ( union acpi_operand_object *obj_desc, struct acpi_thread_state *thread) @@ -132,8 +139,9 @@ acpi_ex_link_mutex ( * * FUNCTION: acpi_ex_acquire_mutex * - * PARAMETERS: time_desc - The 'time to delay' object descriptor - * obj_desc - The object descriptor for this op + * PARAMETERS: time_desc - Timeout integer + * obj_desc - Mutex object + * walk_state - Current method execution state * * RETURN: Status * @@ -161,7 +169,7 @@ acpi_ex_acquire_mutex ( if (!walk_state->thread) { ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], null thread info\n", - acpi_ut_get_node_name (obj_desc->mutex.node))); + acpi_ut_get_node_name (obj_desc->mutex.node))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -170,8 +178,9 @@ acpi_ex_acquire_mutex ( * mutex. This mechanism provides some deadlock prevention */ if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { - ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], incorrect sync_level\n", - acpi_ut_get_node_name (obj_desc->mutex.node))); + ACPI_REPORT_ERROR (( + "Cannot acquire Mutex [%4.4s], incorrect sync_level\n", + acpi_ut_get_node_name (obj_desc->mutex.node))); return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } @@ -180,8 +189,10 @@ acpi_ex_acquire_mutex ( if (obj_desc->mutex.owner_thread) { /* Special case for Global Lock, allow all threads */ - if ((obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id) || - (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore)) { + if ((obj_desc->mutex.owner_thread->thread_id == + walk_state->thread->thread_id) || + (obj_desc->mutex.semaphore == + acpi_gbl_global_lock_semaphore)) { /* * The mutex is already owned by this thread, * just increment the acquisition depth @@ -221,6 +232,7 @@ acpi_ex_acquire_mutex ( * FUNCTION: acpi_ex_release_mutex * * PARAMETERS: obj_desc - The object descriptor for this op + * walk_state - Current method execution state * * RETURN: Status * @@ -278,8 +290,9 @@ acpi_ex_release_mutex ( * equal to the current sync level */ if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { - ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], incorrect sync_level\n", - acpi_ut_get_node_name (obj_desc->mutex.node))); + ACPI_REPORT_ERROR (( + "Cannot release Mutex [%4.4s], incorrect sync_level\n", + acpi_ut_get_node_name (obj_desc->mutex.node))); return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } @@ -313,11 +326,11 @@ acpi_ex_release_mutex ( * * FUNCTION: acpi_ex_release_all_mutexes * - * PARAMETERS: mutex_list - Head of the mutex list + * PARAMETERS: Thread - Current executing thread object * * RETURN: Status * - * DESCRIPTION: Release all mutexes in the list + * DESCRIPTION: Release all mutexes held by this thread * ******************************************************************************/ diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c index 7911c533c26..639f0bd3f6d 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/executer/exnames.c @@ -50,13 +50,17 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exnames") +/* Local prototypes */ -/* AML Package Length encodings */ +static char * +acpi_ex_allocate_name_string ( + u32 prefix_count, + u32 num_name_segs); -#define ACPI_AML_PACKAGE_TYPE1 0x40 -#define ACPI_AML_PACKAGE_TYPE2 0x4000 -#define ACPI_AML_PACKAGE_TYPE3 0x400000 -#define ACPI_AML_PACKAGE_TYPE4 0x40000000 +static acpi_status +acpi_ex_name_segment ( + u8 **in_aml_address, + char *name_string); /******************************************************************************* @@ -64,7 +68,7 @@ * FUNCTION: acpi_ex_allocate_name_string * * PARAMETERS: prefix_count - Count of parent levels. Special cases: - * (-1) = root, 0 = none + * (-1)==root, 0==none * num_name_segs - count of 4-character name segments * * RETURN: A pointer to the allocated string segment. This segment must @@ -75,7 +79,7 @@ * ******************************************************************************/ -char * +static char * acpi_ex_allocate_name_string ( u32 prefix_count, u32 num_name_segs) @@ -88,7 +92,7 @@ acpi_ex_allocate_name_string ( /* - * Allow room for all \ and ^ prefixes, all segments, and a multi_name_prefix. + * Allow room for all \ and ^ prefixes, all segments and a multi_name_prefix. * Also, one byte for the null terminator. * This may actually be somewhat longer than needed. */ @@ -107,7 +111,8 @@ acpi_ex_allocate_name_string ( */ name_string = ACPI_MEM_ALLOCATE (size_needed); if (!name_string) { - ACPI_REPORT_ERROR (("ex_allocate_name_string: Could not allocate size %d\n", size_needed)); + ACPI_REPORT_ERROR (( + "ex_allocate_name_string: Could not allocate size %d\n", size_needed)); return_PTR (NULL); } @@ -152,15 +157,17 @@ acpi_ex_allocate_name_string ( * * FUNCTION: acpi_ex_name_segment * - * PARAMETERS: interpreter_mode - Current running mode (load1/Load2/Exec) + * PARAMETERS: in_aml_address - Pointer to the name in the AML code + * name_string - Where to return the name. The name is appended + * to any existing string to form a namepath * * RETURN: Status * - * DESCRIPTION: Execute a name segment (4 bytes) + * DESCRIPTION: Extract an ACPI name (4 bytes) from the AML byte stream * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_name_segment ( u8 **in_aml_address, char *name_string) @@ -223,10 +230,13 @@ acpi_ex_name_segment ( status = AE_CTRL_PENDING; } else { - /* Segment started with one or more valid characters, but fewer than 4 */ - + /* + * Segment started with one or more valid characters, but fewer than + * the required 4 + */ status = AE_AML_BAD_NAME; - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad character %02x in name, at %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Bad character %02x in name, at %p\n", *aml_address, aml_address)); } @@ -239,11 +249,16 @@ acpi_ex_name_segment ( * * FUNCTION: acpi_ex_get_name_string * - * PARAMETERS: data_type - Data type to be associated with this name + * PARAMETERS: data_type - Object type to be associated with this + * name + * in_aml_address - Pointer to the namestring in the AML code + * out_name_string - Where the namestring is returned + * out_name_length - Length of the returned string * - * RETURN: Status + * RETURN: Status, namestring and length * - * DESCRIPTION: Get a name, including any prefixes. + * DESCRIPTION: Extract a full namepath from the AML byte stream, + * including any prefixes. * ******************************************************************************/ @@ -286,7 +301,8 @@ acpi_ex_get_name_string ( switch (*aml_address) { case AML_ROOT_PREFIX: - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "root_prefix(\\) at %p\n", aml_address)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "root_prefix(\\) at %p\n", + aml_address)); /* * Remember that we have a root_prefix -- @@ -303,7 +319,8 @@ acpi_ex_get_name_string ( /* Increment past possibly multiple parent prefixes */ do { - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "parent_prefix (^) at %p\n", aml_address)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "parent_prefix (^) at %p\n", + aml_address)); aml_address++; prefix_count++; @@ -321,13 +338,13 @@ acpi_ex_get_name_string ( break; } - /* Examine first character of name for name segment prefix operator */ switch (*aml_address) { case AML_DUAL_NAME_PREFIX: - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "dual_name_prefix at %p\n", aml_address)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "dual_name_prefix at %p\n", + aml_address)); aml_address++; name_string = acpi_ex_allocate_name_string (prefix_count, 2); @@ -349,7 +366,8 @@ acpi_ex_get_name_string ( case AML_MULTI_NAME_PREFIX_OP: - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "multi_name_prefix at %p\n", aml_address)); + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "multi_name_prefix at %p\n", + aml_address)); /* Fetch count of segments remaining in name path */ @@ -368,7 +386,8 @@ acpi_ex_get_name_string ( has_prefix = TRUE; while (num_segments && - (status = acpi_ex_name_segment (&aml_address, name_string)) == AE_OK) { + (status = acpi_ex_name_segment (&aml_address, name_string)) == + AE_OK) { num_segments--; } @@ -380,7 +399,8 @@ acpi_ex_get_name_string ( /* null_name valid as of 8-12-98 ASL/AML Grammar Update */ if (prefix_count == ACPI_UINT32_MAX) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "name_seg is \"\\\" followed by NULL\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "name_seg is \"\\\" followed by NULL\n")); } /* Consume the NULL byte */ diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c index 8482aefaf38..dbdf8262ba0 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/executer/exoparg1.c @@ -97,7 +97,8 @@ acpi_ex_opcode_0A_0T_1R ( union acpi_operand_object *return_desc = NULL; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_0A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_0A_0T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); /* Examine the AML opcode */ @@ -161,7 +162,8 @@ acpi_ex_opcode_1A_0T_0R ( acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_0R", + acpi_ps_get_opcode_name (walk_state->opcode)); /* Examine the AML opcode */ @@ -236,7 +238,8 @@ acpi_ex_opcode_1A_1T_0R ( union acpi_operand_object **operand = &walk_state->operands[0]; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_0R", + acpi_ps_get_opcode_name (walk_state->opcode)); /* Examine the AML opcode */ @@ -289,7 +292,8 @@ acpi_ex_opcode_1A_1T_1R ( acpi_integer digit; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); /* Examine the AML opcode */ @@ -409,8 +413,10 @@ acpi_ex_opcode_1A_1T_1R ( for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) { (void) acpi_ut_short_divide (digit, 10, &digit, &temp32); - /* Insert the BCD digit that resides in the remainder from above */ - + /* + * Insert the BCD digit that resides in the + * remainder from above + */ return_desc->integer.value |= (((acpi_integer) temp32) << ACPI_MUL_4 (i)); } @@ -445,7 +451,8 @@ acpi_ex_opcode_1A_1T_1R ( /* Get the object reference, store it, and remove our reference */ - status = acpi_ex_get_object_reference (operand[0], &return_desc2, walk_state); + status = acpi_ex_get_object_reference (operand[0], + &return_desc2, walk_state); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -482,10 +489,10 @@ acpi_ex_opcode_1A_1T_1R ( if (!walk_state->result_obj) { /* - * Normally, we would remove a reference on the Operand[0] parameter; - * But since it is being used as the internal return object - * (meaning we would normally increment it), the two cancel out, - * and we simply don't do anything. + * Normally, we would remove a reference on the Operand[0] + * parameter; But since it is being used as the internal return + * object (meaning we would normally increment it), the two + * cancel out, and we simply don't do anything. */ walk_state->result_obj = operand[0]; walk_state->operands[0] = NULL; /* Prevent deletion */ @@ -549,9 +556,8 @@ acpi_ex_opcode_1A_1T_1R ( case AML_SHIFT_LEFT_BIT_OP: /* shift_left_bit (Source, bit_num) */ case AML_SHIFT_RIGHT_BIT_OP: /* shift_right_bit (Source, bit_num) */ - /* - * These are two obsolete opcodes - */ + /* These are two obsolete opcodes */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s is obsolete and not implemented\n", acpi_ps_get_opcode_name (walk_state->opcode))); @@ -568,9 +574,8 @@ acpi_ex_opcode_1A_1T_1R ( } if (ACPI_SUCCESS (status)) { - /* - * Store the return value computed above into the target object - */ + /* Store the return value computed above into the target object */ + status = acpi_ex_store (return_desc, operand[1], walk_state); } @@ -615,7 +620,8 @@ acpi_ex_opcode_1A_0T_1R ( acpi_integer value; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); /* Examine the AML opcode */ @@ -706,9 +712,9 @@ acpi_ex_opcode_1A_0T_1R ( /* * Note: The operand is not resolved at this point because we want to - * get the associated object, not its value. For example, we don't want - * to resolve a field_unit to its value, we want the actual field_unit - * object. + * get the associated object, not its value. For example, we don't + * want to resolve a field_unit to its value, we want the actual + * field_unit object. */ /* Get the type of the base object */ @@ -738,7 +744,8 @@ acpi_ex_opcode_1A_0T_1R ( /* Get the base object */ - status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, &temp_desc); + status = acpi_ex_resolve_multiple (walk_state, + operand[0], &type, &temp_desc); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -818,8 +825,10 @@ acpi_ex_opcode_1A_0T_1R ( /* Set Operand[0] to the value of the local/arg */ - status = acpi_ds_method_data_get_value (operand[0]->reference.opcode, - operand[0]->reference.offset, walk_state, &temp_desc); + status = acpi_ds_method_data_get_value ( + operand[0]->reference.opcode, + operand[0]->reference.offset, + walk_state, &temp_desc); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -852,21 +861,26 @@ acpi_ex_opcode_1A_0T_1R ( case ACPI_TYPE_STRING: /* - * This is a deref_of (String). The string is a reference to a named ACPI object. + * This is a deref_of (String). The string is a reference + * to a named ACPI object. * * 1) Find the owning Node - * 2) Dereference the node to an actual object. Could be a Field, so we nee - * to resolve the node to a value. + * 2) Dereference the node to an actual object. Could be a + * Field, so we need to resolve the node to a value. */ status = acpi_ns_get_node_by_path (operand[0]->string.pointer, - walk_state->scope_info->scope.node, ACPI_NS_SEARCH_PARENT, - ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &return_desc)); + walk_state->scope_info->scope.node, + ACPI_NS_SEARCH_PARENT, + ACPI_CAST_INDIRECT_PTR ( + struct acpi_namespace_node, &return_desc)); if (ACPI_FAILURE (status)) { goto cleanup; } status = acpi_ex_resolve_node_to_value ( - ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &return_desc), walk_state); + ACPI_CAST_INDIRECT_PTR ( + struct acpi_namespace_node, &return_desc), + walk_state); goto cleanup; @@ -883,14 +897,16 @@ acpi_ex_opcode_1A_0T_1R ( /* * This is a deref_of (object_reference) * Get the actual object from the Node (This is the dereference). - * -- This case may only happen when a local_x or arg_x is dereferenced above. + * This case may only happen when a local_x or arg_x is + * dereferenced above. */ - return_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) operand[0]); + return_desc = acpi_ns_get_attached_object ( + (struct acpi_namespace_node *) operand[0]); } else { /* - * This must be a reference object produced by either the Index() or - * ref_of() operator + * This must be a reference object produced by either the + * Index() or ref_of() operator */ switch (operand[0]->reference.opcode) { case AML_INDEX_OP: @@ -931,8 +947,8 @@ acpi_ex_opcode_1A_0T_1R ( case ACPI_TYPE_PACKAGE: /* - * Return the referenced element of the package. We must add - * another reference to the referenced object, however. + * Return the referenced element of the package. We must + * add another reference to the referenced object, however. */ return_desc = *(operand[0]->reference.where); if (!return_desc) { @@ -967,9 +983,11 @@ acpi_ex_opcode_1A_0T_1R ( return_desc = operand[0]->reference.object; - if (ACPI_GET_DESCRIPTOR_TYPE (return_desc) == ACPI_DESC_TYPE_NAMED) { + if (ACPI_GET_DESCRIPTOR_TYPE (return_desc) == + ACPI_DESC_TYPE_NAMED) { - return_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) return_desc); + return_desc = acpi_ns_get_attached_object ( + (struct acpi_namespace_node *) return_desc); } /* Add another reference to the object! */ diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c index 8be4d80ceed..7429032c2b6 100644 --- a/drivers/acpi/executer/exoparg2.c +++ b/drivers/acpi/executer/exoparg2.c @@ -118,7 +118,7 @@ acpi_ex_opcode_2A_0T_0R ( value = (u32) operand[1]->integer.value; - /* Notifies allowed on this object? */ + /* Are notifies allowed on this object? */ if (!acpi_ev_is_notify_object (node)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, @@ -203,11 +203,12 @@ acpi_ex_opcode_2A_2T_1R ( acpi_ps_get_opcode_name (walk_state->opcode)); - /* - * Execute the opcode - */ + /* Execute the opcode */ + switch (walk_state->opcode) { - case AML_DIVIDE_OP: /* Divide (Dividend, Divisor, remainder_result quotient_result) */ + case AML_DIVIDE_OP: + + /* Divide (Dividend, Divisor, remainder_result quotient_result) */ return_desc1 = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); if (!return_desc1) { @@ -241,7 +242,6 @@ acpi_ex_opcode_2A_2T_1R ( goto cleanup; } - /* Store the results to the target reference operands */ status = acpi_ex_store (return_desc2, operand[2], walk_state); @@ -295,7 +295,7 @@ acpi_ex_opcode_2A_1T_1R ( { union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *return_desc = NULL; - u32 index; + acpi_integer index; acpi_status status = AE_OK; acpi_size length; @@ -304,9 +304,8 @@ acpi_ex_opcode_2A_1T_1R ( acpi_ps_get_opcode_name (walk_state->opcode)); - /* - * Execute the opcode - */ + /* Execute the opcode */ + if (walk_state->op_info->flags & AML_MATH) { /* All simple math opcodes (add, etc.) */ @@ -322,9 +321,8 @@ acpi_ex_opcode_2A_1T_1R ( goto store_result_to_target; } - switch (walk_state->opcode) { - case AML_MOD_OP: /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */ + case AML_MOD_OP: /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); if (!return_desc) { @@ -341,18 +339,19 @@ acpi_ex_opcode_2A_1T_1R ( break; - case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ + case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ status = acpi_ex_do_concatenate (operand[0], operand[1], &return_desc, walk_state); break; - case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */ + case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */ /* * Input object is guaranteed to be a buffer at this point (it may have - * been converted.) Copy the raw buffer data to a new object of type String. + * been converted.) Copy the raw buffer data to a new object of + * type String. */ /* @@ -383,14 +382,16 @@ acpi_ex_opcode_2A_1T_1R ( goto cleanup; } - /* Copy the raw buffer data with no transform. NULL terminated already. */ + /* Copy the raw buffer data with no transform. NULL terminated already*/ ACPI_MEMCPY (return_desc->string.pointer, operand[0]->buffer.pointer, length); break; - case AML_CONCAT_RES_OP: /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ + case AML_CONCAT_RES_OP: + + /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ status = acpi_ex_concat_template (operand[0], operand[1], &return_desc, walk_state); @@ -407,33 +408,33 @@ acpi_ex_opcode_2A_1T_1R ( goto cleanup; } - index = (u32) operand[1]->integer.value; + index = operand[1]->integer.value; + + /* At this point, the Source operand is a Package, Buffer, or String */ - /* - * At this point, the Source operand is a Package, Buffer, or String - */ if (ACPI_GET_OBJECT_TYPE (operand[0]) == ACPI_TYPE_PACKAGE) { /* Object to be indexed is a Package */ if (index >= operand[0]->package.count) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Index value (%X) beyond package end (%X)\n", - index, operand[0]->package.count)); + "Index value (%X%8.8X) beyond package end (%X)\n", + ACPI_FORMAT_UINT64 (index), operand[0]->package.count)); status = AE_AML_PACKAGE_LIMIT; goto cleanup; } return_desc->reference.target_type = ACPI_TYPE_PACKAGE; return_desc->reference.object = operand[0]; - return_desc->reference.where = &operand[0]->package.elements [index]; + return_desc->reference.where = &operand[0]->package.elements [ + index]; } else { /* Object to be indexed is a Buffer/String */ if (index >= operand[0]->buffer.length) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Index value (%X) beyond end of buffer (%X)\n", - index, operand[0]->buffer.length)); + "Index value (%X%8.8X) beyond end of buffer (%X)\n", + ACPI_FORMAT_UINT64 (index), operand[0]->buffer.length)); status = AE_AML_BUFFER_LIMIT; goto cleanup; } @@ -451,7 +452,7 @@ acpi_ex_opcode_2A_1T_1R ( /* Complete the Index reference object */ return_desc->reference.opcode = AML_INDEX_OP; - return_desc->reference.offset = index; + return_desc->reference.offset = (u32) index; /* Store the reference to the Target */ @@ -536,22 +537,24 @@ acpi_ex_opcode_2A_0T_1R ( goto cleanup; } - /* - * Execute the Opcode - */ - if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) /* logical_op (Operand0, Operand1) */ { + /* Execute the Opcode */ + + if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) { + /* logical_op (Operand0, Operand1) */ + status = acpi_ex_do_logical_numeric_op (walk_state->opcode, operand[0]->integer.value, operand[1]->integer.value, &logical_result); goto store_logical_result; } - else if (walk_state->op_info->flags & AML_LOGICAL) /* logical_op (Operand0, Operand1) */ { + else if (walk_state->op_info->flags & AML_LOGICAL) { + /* logical_op (Operand0, Operand1) */ + status = acpi_ex_do_logical_op (walk_state->opcode, operand[0], operand[1], &logical_result); goto store_logical_result; } - switch (walk_state->opcode) { case AML_ACQUIRE_OP: /* Acquire (mutex_object, Timeout) */ diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c index 29d0b167745..23b068adbf5 100644 --- a/drivers/acpi/executer/exoparg3.c +++ b/drivers/acpi/executer/exoparg3.c @@ -97,11 +97,12 @@ acpi_ex_opcode_3A_0T_0R ( acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_0T_0R", + acpi_ps_get_opcode_name (walk_state->opcode)); switch (walk_state->opcode) { - case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */ + case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "fatal_op: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", @@ -116,9 +117,8 @@ acpi_ex_opcode_3A_0T_0R ( fatal->argument = (u32) operand[2]->integer.value; } - /* - * Always signal the OS! - */ + /* Always signal the OS! */ + status = acpi_os_signal (ACPI_SIGNAL_FATAL, fatal); /* Might return while OS is shutting down, just continue */ @@ -162,21 +162,23 @@ acpi_ex_opcode_3A_1T_1R ( union acpi_operand_object *return_desc = NULL; char *buffer; acpi_status status = AE_OK; - acpi_native_uint index; + acpi_integer index; acpi_size length; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_1T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); switch (walk_state->opcode) { - case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ + case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ /* * Create the return object. The Source operand is guaranteed to be * either a String or a Buffer, so just use its type. */ - return_desc = acpi_ut_create_internal_object (ACPI_GET_OBJECT_TYPE (operand[0])); + return_desc = acpi_ut_create_internal_object ( + ACPI_GET_OBJECT_TYPE (operand[0])); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; @@ -184,7 +186,7 @@ acpi_ex_opcode_3A_1T_1R ( /* Get the Integer values from the objects */ - index = (acpi_native_uint) operand[1]->integer.value; + index = operand[1]->integer.value; length = (acpi_size) operand[2]->integer.value; /* @@ -197,7 +199,8 @@ acpi_ex_opcode_3A_1T_1R ( if ((index + length) > operand[0]->string.length) { - length = (acpi_size) operand[0]->string.length - index; + length = (acpi_size) operand[0]->string.length - + (acpi_size) index; } /* Allocate a new buffer for the String/Buffer */ diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c index d3262433162..17f81d42ee4 100644 --- a/drivers/acpi/executer/exoparg6.c +++ b/drivers/acpi/executer/exoparg6.c @@ -75,6 +75,14 @@ * fully resolved operands. !*/ +/* Local prototypes */ + +static u8 +acpi_ex_do_match ( + u32 match_op, + union acpi_operand_object *package_obj, + union acpi_operand_object *match_obj); + /******************************************************************************* * @@ -92,7 +100,7 @@ * ******************************************************************************/ -u8 +static u8 acpi_ex_do_match ( u32 match_op, union acpi_operand_object *package_obj, @@ -216,11 +224,12 @@ acpi_ex_opcode_6A_0T_1R ( union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *return_desc = NULL; acpi_status status = AE_OK; - u32 index; + acpi_integer index; union acpi_operand_object *this_element; - ACPI_FUNCTION_TRACE_STR ("ex_opcode_6A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + ACPI_FUNCTION_TRACE_STR ("ex_opcode_6A_0T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); switch (walk_state->opcode) { @@ -241,9 +250,11 @@ acpi_ex_opcode_6A_0T_1R ( /* Get the package start_index, validate against the package length */ - index = (u32) operand[5]->integer.value; - if (index >= (u32) operand[0]->package.count) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index beyond package end\n")); + index = operand[5]->integer.value; + if (index >= operand[0]->package.count) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Index (%X%8.8X) beyond package end (%X)\n", + ACPI_FORMAT_UINT64 (index), operand[0]->package.count)); status = AE_AML_PACKAGE_LIMIT; goto cleanup; } @@ -314,13 +325,12 @@ acpi_ex_opcode_6A_0T_1R ( default: - ACPI_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n", + ACPI_REPORT_ERROR (("acpi_ex_opcode_6A_0T_1R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; } - walk_state->result_obj = return_desc; diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c index 264ef3bba31..c9e3c68b554 100644 --- a/drivers/acpi/executer/exprep.c +++ b/drivers/acpi/executer/exprep.c @@ -52,8 +52,23 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exprep") +/* Local prototypes */ + +static u32 +acpi_ex_decode_field_access ( + union acpi_operand_object *obj_desc, + u8 field_flags, + u32 *return_byte_alignment); + #ifdef ACPI_UNDER_DEVELOPMENT + +static u32 +acpi_ex_generate_access ( + u32 field_bit_offset, + u32 field_bit_length, + u32 region_length); + /******************************************************************************* * * FUNCTION: acpi_ex_generate_access @@ -99,12 +114,14 @@ acpi_ex_generate_access ( /* Round Field start offset and length to "minimal" byte boundaries */ field_byte_offset = ACPI_DIV_8 (ACPI_ROUND_DOWN (field_bit_offset, 8)); - field_byte_end_offset = ACPI_DIV_8 (ACPI_ROUND_UP (field_bit_length + field_bit_offset, 8)); + field_byte_end_offset = ACPI_DIV_8 (ACPI_ROUND_UP (field_bit_length + + field_bit_offset, 8)); field_byte_length = field_byte_end_offset - field_byte_offset; ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Bit length %d, Bit offset %d\n", field_bit_length, field_bit_offset)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Byte Length %d, Byte Offset %d, End Offset %d\n", field_byte_length, field_byte_offset, field_byte_end_offset)); @@ -117,20 +134,26 @@ acpi_ex_generate_access ( */ for (access_byte_width = 1; access_byte_width <= 8; access_byte_width <<= 1) { /* - * 1) Round end offset up to next access boundary and make sure that this - * does not go beyond the end of the parent region. - * 2) When the Access width is greater than the field_byte_length, we are done. - * (This does not optimize for the perfectly aligned case yet). + * 1) Round end offset up to next access boundary and make sure that + * this does not go beyond the end of the parent region. + * 2) When the Access width is greater than the field_byte_length, we + * are done. (This does not optimize for the perfectly aligned + * case yet). */ if (ACPI_ROUND_UP (field_byte_end_offset, access_byte_width) <= region_length) { - field_start_offset = ACPI_ROUND_DOWN (field_byte_offset, access_byte_width) / - access_byte_width; - field_end_offset = ACPI_ROUND_UP ((field_byte_length + field_byte_offset), - access_byte_width) / access_byte_width; - accesses = field_end_offset - field_start_offset; + field_start_offset = + ACPI_ROUND_DOWN (field_byte_offset, access_byte_width) / + access_byte_width; + + field_end_offset = + ACPI_ROUND_UP ((field_byte_length + field_byte_offset), + access_byte_width) / access_byte_width; + + accesses = field_end_offset - field_start_offset; ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "access_width %d end is within region\n", access_byte_width)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Field Start %d, Field End %d -- requires %d accesses\n", field_start_offset, field_end_offset, accesses)); @@ -139,8 +162,8 @@ acpi_ex_generate_access ( if (accesses <= 1) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Entire field can be accessed with one operation of size %d\n", - access_byte_width)); + "Entire field can be accessed with one operation of size %d\n", + access_byte_width)); return_VALUE (access_byte_width); } @@ -155,15 +178,20 @@ acpi_ex_generate_access ( } else { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "access_width %d end is NOT within region\n", access_byte_width)); + "access_width %d end is NOT within region\n", access_byte_width)); if (access_byte_width == 1) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Field goes beyond end-of-region!\n")); - return_VALUE (0); /* Field does not fit in the region at all */ - } - /* This width goes beyond the end-of-region, back off to previous access */ + /* Field does not fit in the region at all */ + return_VALUE (0); + } + + /* + * This width goes beyond the end-of-region, back off to + * previous access + */ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Backing off to previous optimal access width of %d\n", minimum_access_width)); @@ -171,8 +199,10 @@ acpi_ex_generate_access ( } } - /* Could not read/write field with one operation, just use max access width */ - + /* + * Could not read/write field with one operation, + * just use max access width + */ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Cannot access field in one operation, using width 8\n")); return_VALUE (8); @@ -184,8 +214,9 @@ acpi_ex_generate_access ( * * FUNCTION: acpi_ex_decode_field_access * - * PARAMETERS: Access - Encoded field access bits - * Length - Field length. + * PARAMETERS: obj_desc - Field object + * field_flags - Encoded fieldflags (contains access bits) + * return_byte_alignment - Where the byte alignment is returned * * RETURN: Field granularity (8, 16, 32 or 64) and * byte_alignment (1, 2, 3, or 4) @@ -214,9 +245,10 @@ acpi_ex_decode_field_access ( case AML_FIELD_ACCESS_ANY: #ifdef ACPI_UNDER_DEVELOPMENT - byte_alignment = acpi_ex_generate_access (obj_desc->common_field.start_field_bit_offset, - obj_desc->common_field.bit_length, - 0xFFFFFFFF /* Temp until we pass region_length as param */); + byte_alignment = + acpi_ex_generate_access (obj_desc->common_field.start_field_bit_offset, + obj_desc->common_field.bit_length, + 0xFFFFFFFF /* Temp until we pass region_length as parameter */); bit_length = byte_alignment * 8; #endif @@ -276,6 +308,7 @@ acpi_ex_decode_field_access ( * field_flags - Access, lock_rule, and update_rule. * The format of a field_flag is described * in the ACPI specification + * field_attribute - Special attributes (not used) * field_bit_position - Field start position * field_bit_length - Field length in number of bits * @@ -337,7 +370,7 @@ acpi_ex_prep_common_field_object ( /* Setup width (access granularity) fields */ obj_desc->common_field.access_byte_width = (u8) - ACPI_DIV_8 (access_bit_width); /* 1, 2, 4, 8 */ + ACPI_DIV_8 (access_bit_width); /* 1, 2, 4, 8 */ obj_desc->common_field.access_bit_width = (u8) access_bit_width; @@ -380,11 +413,7 @@ acpi_ex_prep_common_field_object ( * * FUNCTION: acpi_ex_prep_field_value * - * PARAMETERS: Node - Owning Node - * region_node - Region in which field is being defined - * field_flags - Access, lock_rule, and update_rule. - * field_bit_position - Field start position - * field_bit_length - Field length in number of bits + * PARAMETERS: Info - Contains all field creation info * * RETURN: Status * @@ -445,7 +474,7 @@ acpi_ex_prep_field_value ( switch (info->field_type) { case ACPI_TYPE_LOCAL_REGION_FIELD: - obj_desc->field.region_obj = acpi_ns_get_attached_object (info->region_node); + obj_desc->field.region_obj = acpi_ns_get_attached_object (info->region_node); /* An additional reference for the container */ @@ -461,8 +490,10 @@ acpi_ex_prep_field_value ( case ACPI_TYPE_LOCAL_BANK_FIELD: obj_desc->bank_field.value = info->bank_value; - obj_desc->bank_field.region_obj = acpi_ns_get_attached_object (info->region_node); - obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object (info->register_node); + obj_desc->bank_field.region_obj = acpi_ns_get_attached_object ( + info->region_node); + obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object ( + info->register_node); /* An additional reference for the attached objects */ @@ -481,10 +512,13 @@ acpi_ex_prep_field_value ( case ACPI_TYPE_LOCAL_INDEX_FIELD: - obj_desc->index_field.index_obj = acpi_ns_get_attached_object (info->register_node); - obj_desc->index_field.data_obj = acpi_ns_get_attached_object (info->data_register_node); + obj_desc->index_field.index_obj = acpi_ns_get_attached_object ( + info->register_node); + obj_desc->index_field.data_obj = acpi_ns_get_attached_object ( + info->data_register_node); obj_desc->index_field.value = (u32) - (info->field_bit_position / ACPI_MUL_8 (obj_desc->field.access_byte_width)); + (info->field_bit_position / ACPI_MUL_8 ( + obj_desc->field.access_byte_width)); if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) { ACPI_REPORT_ERROR (("Null Index Object during field prep\n")); diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c index 7cfd0684c70..723aaef4bb4 100644 --- a/drivers/acpi/executer/exregion.c +++ b/drivers/acpi/executer/exregion.c @@ -115,7 +115,6 @@ acpi_ex_system_memory_space_handler ( return_ACPI_STATUS (AE_AML_OPERAND_VALUE); } - #ifndef ACPI_MISALIGNED_TRANSFERS /* * Hardware does not support non-aligned data transfers, we must verify @@ -134,7 +133,8 @@ acpi_ex_system_memory_space_handler ( */ if ((address < mem_info->mapped_physical_address) || (((acpi_integer) address + length) > - ((acpi_integer) mem_info->mapped_physical_address + mem_info->mapped_length))) { + ((acpi_integer) + mem_info->mapped_physical_address + mem_info->mapped_length))) { /* * The request cannot be resolved by the current memory mapping; * Delete the existing mapping and create a new one. @@ -150,7 +150,9 @@ acpi_ex_system_memory_space_handler ( * Don't attempt to map memory beyond the end of the region, and * constrain the maximum mapping size to something reasonable. */ - window_size = (acpi_size) ((mem_info->address + mem_info->length) - address); + window_size = (acpi_size) + ((mem_info->address + mem_info->length) - address); + if (window_size > ACPI_SYSMEM_REGION_WINDOW_SIZE) { window_size = ACPI_SYSMEM_REGION_WINDOW_SIZE; } @@ -160,8 +162,9 @@ acpi_ex_system_memory_space_handler ( status = acpi_os_map_memory (address, window_size, (void **) &mem_info->mapped_logical_address); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X%8.8X, size %X\n", - ACPI_FORMAT_UINT64 (address), (u32) window_size)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not map memory at %8.8X%8.8X, size %X\n", + ACPI_FORMAT_UINT64 (address), (u32) window_size)); mem_info->mapped_length = 0; return_ACPI_STATUS (status); } @@ -177,10 +180,12 @@ acpi_ex_system_memory_space_handler ( * access */ logical_addr_ptr = mem_info->mapped_logical_address + - ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address); + ((acpi_integer) address - + (acpi_integer) mem_info->mapped_physical_address); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, - "system_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, + "system_memory %d (%d width) Address=%8.8X%8.8X\n", + function, bit_width, ACPI_FORMAT_UINT64 (address))); /* @@ -298,13 +303,15 @@ acpi_ex_system_io_space_handler ( switch (function) { case ACPI_READ: - status = acpi_os_read_port ((acpi_io_address) address, &value32, bit_width); + status = acpi_os_read_port ((acpi_io_address) address, + &value32, bit_width); *value = value32; break; case ACPI_WRITE: - status = acpi_os_write_port ((acpi_io_address) address, (u32) *value, bit_width); + status = acpi_os_write_port ((acpi_io_address) address, + (u32) *value, bit_width); break; default: @@ -375,12 +382,14 @@ acpi_ex_pci_config_space_handler ( case ACPI_READ: *value = 0; - status = acpi_os_read_pci_configuration (pci_id, pci_register, value, bit_width); + status = acpi_os_read_pci_configuration (pci_id, pci_register, + value, bit_width); break; case ACPI_WRITE: - status = acpi_os_write_pci_configuration (pci_id, pci_register, *value, bit_width); + status = acpi_os_write_pci_configuration (pci_id, pci_register, + *value, bit_width); break; default: @@ -505,8 +514,7 @@ acpi_ex_data_table_space_handler ( logical_addr_ptr = ACPI_PHYSADDR_TO_PTR (address); - - /* Perform the memory read or write */ + /* Perform the memory read or write */ switch (function) { case ACPI_READ: diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c index 7936329a0e3..21d5c74fa30 100644 --- a/drivers/acpi/executer/exresnte.c +++ b/drivers/acpi/executer/exresnte.c @@ -210,15 +210,15 @@ acpi_ex_resolve_node_to_value ( case ACPI_TYPE_LOCAL_BANK_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "field_read Node=%p source_desc=%p Type=%X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "field_read Node=%p source_desc=%p Type=%X\n", node, source_desc, entry_type)); status = acpi_ex_read_data_from_field (walk_state, source_desc, &obj_desc); break; - /* - * For these objects, just return the object attached to the Node - */ + /* For these objects, just return the object attached to the Node */ + case ACPI_TYPE_MUTEX: case ACPI_TYPE_METHOD: case ACPI_TYPE_POWER: @@ -233,12 +233,12 @@ acpi_ex_resolve_node_to_value ( acpi_ut_add_reference (obj_desc); break; - /* TYPE_ANY is untyped, and thus there is no object associated with it */ case ACPI_TYPE_ANY: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Untyped entry %p, no attached object!\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Untyped entry %p, no attached object!\n", node)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); /* Cannot be AE_TYPE */ @@ -259,7 +259,8 @@ acpi_ex_resolve_node_to_value ( default: /* No named references are allowed here */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported Reference opcode %X (%s)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unsupported Reference opcode %X (%s)\n", source_desc->reference.opcode, acpi_ps_get_opcode_name (source_desc->reference.opcode))); @@ -268,11 +269,12 @@ acpi_ex_resolve_node_to_value ( break; - /* Default case is for unknown types */ - default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Node %p - Unknown object type %X\n", + /* Default case is for unknown types */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Node %p - Unknown object type %X\n", node, entry_type)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); @@ -280,7 +282,7 @@ acpi_ex_resolve_node_to_value ( } /* switch (entry_type) */ - /* Put the object descriptor on the stack */ + /* Return the object descriptor */ *object_ptr = (void *) obj_desc; return_ACPI_STATUS (status); diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c index 7be60491115..3de45672379 100644 --- a/drivers/acpi/executer/exresolv.c +++ b/drivers/acpi/executer/exresolv.c @@ -54,6 +54,13 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exresolv") +/* Local prototypes */ + +static acpi_status +acpi_ex_resolve_object_to_value ( + union acpi_operand_object **stack_ptr, + struct acpi_walk_state *walk_state); + /******************************************************************************* * @@ -96,6 +103,11 @@ acpi_ex_resolve_to_value ( if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } + + if (!*stack_ptr) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null pointer\n")); + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } } /* @@ -120,18 +132,17 @@ acpi_ex_resolve_to_value ( * * FUNCTION: acpi_ex_resolve_object_to_value * - * PARAMETERS: stack_ptr - Pointer to a stack location that contains a - * ptr to an internal object. + * PARAMETERS: stack_ptr - Pointer to an internal object * walk_state - Current method state * * RETURN: Status * - * DESCRIPTION: Retrieve the value from an internal object. The Reference type + * DESCRIPTION: Retrieve the value from an internal object. The Reference type * uses the associated AML opcode to determine the value. * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_resolve_object_to_value ( union acpi_operand_object **stack_ptr, struct acpi_walk_state *walk_state) @@ -159,7 +170,7 @@ acpi_ex_resolve_object_to_value ( case AML_NAME_OP: /* - * Convert indirect name ptr to a direct name ptr. + * Convert name reference to a namespace node * Then, acpi_ex_resolve_node_to_value can be used to get the value */ temp_node = stack_desc->reference.object; @@ -168,7 +179,7 @@ acpi_ex_resolve_object_to_value ( acpi_ut_remove_reference (stack_desc); - /* Put direct name pointer onto stack and exit */ + /* Return the namespace node */ (*stack_ptr) = temp_node; break; @@ -255,10 +266,19 @@ acpi_ex_resolve_object_to_value ( break; + case AML_INT_NAMEPATH_OP: /* Reference to a named object */ + + /* Get the object pointed to by the namespace node */ + + *stack_ptr = (stack_desc->reference.node)->object; + acpi_ut_add_reference (*stack_ptr); + acpi_ut_remove_reference (stack_desc); + break; default: - ACPI_REPORT_ERROR (("During resolve, Unknown Reference opcode %X (%s) in %p\n", + ACPI_REPORT_ERROR (( + "During resolve, Unknown Reference opcode %X (%s) in %p\n", opcode, acpi_ps_get_opcode_name (opcode), stack_desc)); status = AE_AML_INTERNAL; break; @@ -278,9 +298,8 @@ acpi_ex_resolve_object_to_value ( break; - /* - * These cases may never happen here, but just in case.. - */ + /* These cases may never happen here, but just in case.. */ + case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: @@ -333,9 +352,8 @@ acpi_ex_resolve_multiple ( ACPI_FUNCTION_TRACE ("acpi_ex_resolve_multiple"); - /* - * Operand can be either a namespace node or an operand descriptor - */ + /* Operand can be either a namespace node or an operand descriptor */ + switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { case ACPI_DESC_TYPE_OPERAND: type = obj_desc->common.type; @@ -357,10 +375,8 @@ acpi_ex_resolve_multiple ( return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } + /* If type is anything other than a reference, we are done */ - /* - * If type is anything other than a reference, we are done - */ if (type != ACPI_TYPE_LOCAL_REFERENCE) { goto exit; } @@ -382,8 +398,9 @@ acpi_ex_resolve_multiple ( /* All "References" point to a NS node */ if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { - ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", - node, acpi_ut_get_descriptor_name (node))); + ACPI_REPORT_ERROR (( + "acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", + node, acpi_ut_get_descriptor_name (node))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -440,8 +457,9 @@ acpi_ex_resolve_multiple ( /* All "References" point to a NS node */ if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { - ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", - node, acpi_ut_get_descriptor_name (node))); + ACPI_REPORT_ERROR (( + "acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", + node, acpi_ut_get_descriptor_name (node))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -468,7 +486,7 @@ acpi_ex_resolve_multiple ( if (return_desc) { status = acpi_ds_method_data_get_value (obj_desc->reference.opcode, - obj_desc->reference.offset, walk_state, &obj_desc); + obj_desc->reference.offset, walk_state, &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -500,7 +518,8 @@ acpi_ex_resolve_multiple ( default: - ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Unknown Reference subtype %X\n", + ACPI_REPORT_ERROR (( + "acpi_ex_resolve_multiple: Unknown Reference subtype %X\n", obj_desc->reference.opcode)); return_ACPI_STATUS (AE_AML_INTERNAL); } diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c index c92890220c3..d8b470eefe7 100644 --- a/drivers/acpi/executer/exresop.c +++ b/drivers/acpi/executer/exresop.c @@ -52,6 +52,14 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exresop") +/* Local prototypes */ + +static acpi_status +acpi_ex_check_object_type ( + acpi_object_type type_needed, + acpi_object_type this_type, + void *object); + /******************************************************************************* * @@ -67,7 +75,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_check_object_type ( acpi_object_type type_needed, acpi_object_type this_type, @@ -142,6 +150,7 @@ acpi_ex_resolve_operands ( const struct acpi_opcode_info *op_info; u32 this_arg_type; acpi_object_type type_needed; + u16 target_op = 0; ACPI_FUNCTION_TRACE_U32 ("ex_resolve_operands", opcode); @@ -160,7 +169,8 @@ acpi_ex_resolve_operands ( return_ACPI_STATUS (AE_AML_INTERNAL); } - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X [%s] required_operand_types=%8.8X \n", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Opcode %X [%s] required_operand_types=%8.8X \n", opcode, op_info->name, arg_types)); /* @@ -187,7 +197,7 @@ acpi_ex_resolve_operands ( switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { case ACPI_DESC_TYPE_NAMED: - /* Node */ + /* Namespace Node */ object_type = ((struct acpi_namespace_node *) obj_desc)->type; break; @@ -202,16 +212,16 @@ acpi_ex_resolve_operands ( /* Check for bad acpi_object_type */ if (!acpi_ut_valid_object_type (object_type)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad operand object type [%X]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Bad operand object type [%X]\n", object_type)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) { - /* - * Decode the Reference - */ + /* Decode the Reference */ + op_info = acpi_ps_get_opcode_info (opcode); if (op_info->class == AML_CLASS_UNKNOWN) { return_ACPI_STATUS (AE_AML_BAD_OPCODE); @@ -219,12 +229,17 @@ acpi_ex_resolve_operands ( switch (obj_desc->reference.opcode) { case AML_DEBUG_OP: + target_op = AML_DEBUG_OP; + + /*lint -fallthrough */ + case AML_NAME_OP: case AML_INDEX_OP: case AML_REF_OF_OP: case AML_ARG_OP: case AML_LOCAL_OP: - case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */ + case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */ + case AML_INT_NAMEPATH_OP: /* Reference to a named object */ ACPI_DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Operand is a Reference, ref_opcode [%s]\n", @@ -254,10 +269,8 @@ acpi_ex_resolve_operands ( return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } + /* Get one argument type, point to the next */ - /* - * Get one argument type, point to the next - */ this_arg_type = GET_CURRENT_ARG_TYPE (arg_types); INCREMENT_ARG_LIST (arg_types); @@ -271,26 +284,31 @@ acpi_ex_resolve_operands ( if ((ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_OPERAND) && (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_STRING)) { /* - * String found - the string references a named object and must be - * resolved to a node + * String found - the string references a named object and + * must be resolved to a node */ goto next_operand; } - /* Else not a string - fall through to the normal Reference case below */ + /* + * Else not a string - fall through to the normal Reference + * case below + */ /*lint -fallthrough */ case ARGI_REFERENCE: /* References: */ case ARGI_INTEGER_REF: case ARGI_OBJECT_REF: case ARGI_DEVICE_REF: - case ARGI_TARGETREF: /* Allows implicit conversion rules before store */ - case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ - case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ - - /* Need an operand of type ACPI_TYPE_LOCAL_REFERENCE */ + case ARGI_TARGETREF: /* Allows implicit conversion rules before store */ + case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ + case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ - if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) /* Node (name) ptr OK as-is */ { + /* + * Need an operand of type ACPI_TYPE_LOCAL_REFERENCE + * A Namespace Node is OK as-is + */ + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) { goto next_operand; } @@ -300,11 +318,9 @@ acpi_ex_resolve_operands ( return_ACPI_STATUS (status); } - if (AML_NAME_OP == obj_desc->reference.opcode) { - /* - * Convert an indirect name ptr to direct name ptr and put - * it on the stack - */ + if (obj_desc->reference.opcode == AML_NAME_OP) { + /* Convert a named reference to the actual named object */ + temp_node = obj_desc->reference.object; acpi_ut_remove_reference (obj_desc); (*stack_ptr) = temp_node; @@ -332,7 +348,6 @@ acpi_ex_resolve_operands ( break; } - /* * Resolve this object to a value */ @@ -392,7 +407,7 @@ acpi_ex_resolve_operands ( /* * The more complex cases allow multiple resolved object types */ - case ARGI_INTEGER: /* Number */ + case ARGI_INTEGER: /* * Need an operand of type ACPI_TYPE_INTEGER, @@ -563,7 +578,7 @@ acpi_ex_resolve_operands ( case ARGI_REGION_OR_FIELD: - /* Need an operand of type ACPI_TYPE_REGION or a FIELD in a region */ + /* Need an operand of type REGION or a FIELD in a region */ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { case ACPI_TYPE_REGION: @@ -614,6 +629,12 @@ acpi_ex_resolve_operands ( break; } + if (target_op == AML_DEBUG_OP) { + /* Allow store of any object to the Debug object */ + + break; + } + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Integer/Buffer/String/Package/Ref/Ddb], found [%s] %p\n", acpi_ut_get_object_type_name (obj_desc), obj_desc)); @@ -652,8 +673,7 @@ next_operand: if (GET_CURRENT_ARG_TYPE (arg_types)) { stack_ptr--; } - - } /* while (*Types) */ + } return_ACPI_STATUS (status); } diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c index e0fc6aba125..2725db0901b 100644 --- a/drivers/acpi/executer/exstore.c +++ b/drivers/acpi/executer/exstore.c @@ -48,11 +48,171 @@ #include #include #include +#include #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exstore") +/* Local prototypes */ + +static void +acpi_ex_do_debug_object ( + union acpi_operand_object *source_desc, + u32 level, + u32 index); + +static acpi_status +acpi_ex_store_object_to_index ( + union acpi_operand_object *val_desc, + union acpi_operand_object *dest_desc, + struct acpi_walk_state *walk_state); + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_do_debug_object + * + * PARAMETERS: source_desc - Value to be stored + * Level - Indentation level (used for packages) + * Index - Current package element, zero if not pkg + * + * RETURN: None + * + * DESCRIPTION: Handles stores to the Debug Object. + * + ******************************************************************************/ + +static void +acpi_ex_do_debug_object ( + union acpi_operand_object *source_desc, + u32 level, + u32 index) +{ + u32 i; + + + ACPI_FUNCTION_TRACE_PTR ("ex_do_debug_object", source_desc); + + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s", + level, " ")); + + /* Display index for package output only */ + + if (index > 0) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, + "(%.2u) ", index -1)); + } + + if (!source_desc) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "\n")); + return_VOID; + } + + if (ACPI_GET_DESCRIPTOR_TYPE (source_desc) == ACPI_DESC_TYPE_OPERAND) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%s: ", + acpi_ut_get_object_type_name (source_desc))); + + if (!acpi_ut_valid_internal_object (source_desc)) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, + "%p, Invalid Internal Object!\n", source_desc)); + return_VOID; + } + } + else if (ACPI_GET_DESCRIPTOR_TYPE (source_desc) == ACPI_DESC_TYPE_NAMED) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%s: %p\n", + acpi_ut_get_type_name (((struct acpi_namespace_node *) source_desc)->type), + source_desc)); + return_VOID; + } + else { + return_VOID; + } + + switch (ACPI_GET_OBJECT_TYPE (source_desc)) { + case ACPI_TYPE_INTEGER: + + /* Output correct integer width */ + + if (acpi_gbl_integer_byte_width == 4) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X\n", + (u32) source_desc->integer.value)); + } + else { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (source_desc->integer.value))); + } + break; + + case ACPI_TYPE_BUFFER: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X]", + (u32) source_desc->buffer.length)); + ACPI_DUMP_BUFFER (source_desc->buffer.pointer, + (source_desc->buffer.length < 32) ? source_desc->buffer.length : 32); + break; + + case ACPI_TYPE_STRING: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] \"%s\"\n", + source_desc->string.length, source_desc->string.pointer)); + break; + + case ACPI_TYPE_PACKAGE: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X Elements]\n", + source_desc->package.count)); + + /* Output the entire contents of the package */ + + for (i = 0; i < source_desc->package.count; i++) { + acpi_ex_do_debug_object (source_desc->package.elements[i], + level+4, i+1); + } + break; + + case ACPI_TYPE_LOCAL_REFERENCE: + + if (source_desc->reference.opcode == AML_INDEX_OP) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[%s, 0x%X]\n", + acpi_ps_get_opcode_name (source_desc->reference.opcode), + source_desc->reference.offset)); + } + else { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[%s]\n", + acpi_ps_get_opcode_name (source_desc->reference.opcode))); + } + + + if (source_desc->reference.object) { + if (ACPI_GET_DESCRIPTOR_TYPE (source_desc->reference.object) == + ACPI_DESC_TYPE_NAMED) { + acpi_ex_do_debug_object (((struct acpi_namespace_node *) + source_desc->reference.object)->object, + level+4, 0); + } + else { + acpi_ex_do_debug_object (source_desc->reference.object, level+4, 0); + } + } + else if (source_desc->reference.node) { + acpi_ex_do_debug_object ((source_desc->reference.node)->object, + level+4, 0); + } + break; + + default: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p %s\n", + source_desc, acpi_ut_get_object_type_name (source_desc))); + break; + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n")); + return_VOID; +} + /******************************************************************************* * @@ -154,8 +314,9 @@ acpi_ex_store ( /* Storing an object into a Name "container" */ - status = acpi_ex_store_object_to_node (source_desc, ref_desc->reference.object, - walk_state, ACPI_IMPLICIT_CONVERSION); + status = acpi_ex_store_object_to_node (source_desc, + ref_desc->reference.object, + walk_state, ACPI_IMPLICIT_CONVERSION); break; @@ -173,7 +334,7 @@ acpi_ex_store ( /* Store to a method local/arg */ status = acpi_ds_store_object_to_local (ref_desc->reference.opcode, - ref_desc->reference.offset, source_desc, walk_state); + ref_desc->reference.offset, source_desc, walk_state); break; @@ -187,60 +348,7 @@ acpi_ex_store ( "**** Write to Debug Object: Object %p %s ****:\n\n", source_desc, acpi_ut_get_object_type_name (source_desc))); - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %s: ", - acpi_ut_get_object_type_name (source_desc))); - - if (!acpi_ut_valid_internal_object (source_desc)) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, - "%p, Invalid Internal Object!\n", source_desc)); - break; - } - - switch (ACPI_GET_OBJECT_TYPE (source_desc)) { - case ACPI_TYPE_INTEGER: - - if (acpi_gbl_integer_byte_width == 4) { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X\n", - (u32) source_desc->integer.value)); - } - else { - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (source_desc->integer.value))); - } - break; - - - case ACPI_TYPE_BUFFER: - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X]", - (u32) source_desc->buffer.length)); - ACPI_DUMP_BUFFER (source_desc->buffer.pointer, - (source_desc->buffer.length < 32) ? source_desc->buffer.length : 32); - break; - - - case ACPI_TYPE_STRING: - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] \"%s\"\n", - source_desc->string.length, source_desc->string.pointer)); - break; - - - case ACPI_TYPE_PACKAGE: - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] Elements Ptr - %p\n", - source_desc->package.count, source_desc->package.elements)); - break; - - - default: - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p\n", - source_desc)); - break; - } - - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n")); + acpi_ex_do_debug_object (source_desc, 0, 0); break; @@ -272,7 +380,7 @@ acpi_ex_store ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ex_store_object_to_index ( union acpi_operand_object *source_desc, union acpi_operand_object *index_desc, @@ -313,16 +421,22 @@ acpi_ex_store_object_to_index ( if (obj_desc) { /* Decrement reference count by the ref count of the parent package */ - for (i = 0; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) { + for (i = 0; + i < ((union acpi_operand_object *) + index_desc->reference.object)->common.reference_count; + i++) { acpi_ut_remove_reference (obj_desc); } } *(index_desc->reference.where) = new_desc; - /* Increment reference count by the ref count of the parent package -1 */ + /* Increment ref count by the ref count of the parent package-1 */ - for (i = 1; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) { + for (i = 1; + i < ((union acpi_operand_object *) + index_desc->reference.object)->common.reference_count; + i++) { acpi_ut_add_reference (new_desc); } @@ -440,9 +554,8 @@ acpi_ex_store_object_to_node ( ACPI_FUNCTION_TRACE_PTR ("ex_store_object_to_node", source_desc); - /* - * Get current type of the node, and object attached to Node - */ + /* Get current type of the node, and object attached to Node */ + target_type = acpi_ns_get_type (node); target_desc = acpi_ns_get_attached_object (node); @@ -467,19 +580,18 @@ acpi_ex_store_object_to_node ( target_type = ACPI_TYPE_ANY; } - /* - * Do the actual store operation - */ + /* Do the actual store operation */ + switch (target_type) { case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: - /* - * For fields, copy the source data to the target field. - */ - status = acpi_ex_write_data_to_field (source_desc, target_desc, &walk_state->result_obj); + /* For fields, copy the source data to the target field. */ + + status = acpi_ex_write_data_to_field (source_desc, target_desc, + &walk_state->result_obj); break; @@ -493,7 +605,8 @@ acpi_ex_store_object_to_node ( * * Copy and/or convert the source object to a new target object */ - status = acpi_ex_store_object_to_object (source_desc, target_desc, &new_desc, walk_state); + status = acpi_ex_store_object_to_object (source_desc, target_desc, + &new_desc, walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -526,7 +639,8 @@ acpi_ex_store_object_to_node ( /* No conversions for all other types. Just attach the source object */ - status = acpi_ns_attach_object (node, source_desc, ACPI_GET_OBJECT_TYPE (source_desc)); + status = acpi_ns_attach_object (node, source_desc, + ACPI_GET_OBJECT_TYPE (source_desc)); break; } diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c index d3677feb07f..120f30ed0bd 100644 --- a/drivers/acpi/executer/exstoren.c +++ b/drivers/acpi/executer/exstoren.c @@ -81,9 +81,8 @@ acpi_ex_resolve_object ( ACPI_FUNCTION_TRACE ("ex_resolve_object"); - /* - * Ensure we have a Target that can be stored to - */ + /* Ensure we have a Target that can be stored to */ + switch (target_type) { case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: @@ -118,16 +117,14 @@ acpi_ex_resolve_object ( break; } - /* - * Must have a Integer, Buffer, or String - */ + /* Must have a Integer, Buffer, or String */ + if ((ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_INTEGER) && (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) && (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_STRING) && !((ACPI_GET_OBJECT_TYPE (source_desc) == ACPI_TYPE_LOCAL_REFERENCE) && (source_desc->reference.opcode == AML_LOAD_OP))) { - /* - * Conversion successful but still not a valid type - */ + /* Conversion successful but still not a valid type */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Cannot assign type %s to %s (must be type Int/Str/Buf)\n", acpi_ut_get_object_type_name (source_desc), @@ -140,9 +137,8 @@ acpi_ex_resolve_object ( case ACPI_TYPE_LOCAL_ALIAS: case ACPI_TYPE_LOCAL_METHOD_ALIAS: - /* - * Aliases are resolved by acpi_ex_prep_operands - */ + /* Aliases are resolved by acpi_ex_prep_operands */ + ACPI_REPORT_ERROR (("Store into Alias - should never happen\n")); status = AE_AML_INTERNAL; break; diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c index 05e1ecae8d9..12d1527669c 100644 --- a/drivers/acpi/executer/exstorob.c +++ b/drivers/acpi/executer/exstorob.c @@ -128,7 +128,8 @@ acpi_ex_store_buffer_to_buffer ( else { /* Truncate the source, copy only what will fit */ - ACPI_MEMCPY (target_desc->buffer.pointer, buffer, target_desc->buffer.length); + ACPI_MEMCPY (target_desc->buffer.pointer, buffer, + target_desc->buffer.length); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Truncating source buffer from %X to %X\n", @@ -183,7 +184,8 @@ acpi_ex_store_string_to_string ( * String will fit in existing non-static buffer. * Clear old string and copy in the new one */ - ACPI_MEMSET (target_desc->string.pointer, 0, (acpi_size) target_desc->string.length + 1); + ACPI_MEMSET (target_desc->string.pointer, 0, + (acpi_size) target_desc->string.length + 1); ACPI_MEMCPY (target_desc->string.pointer, buffer, length); } else { @@ -198,7 +200,8 @@ acpi_ex_store_string_to_string ( ACPI_MEM_FREE (target_desc->string.pointer); } - target_desc->string.pointer = ACPI_MEM_CALLOCATE ((acpi_size) length + 1); + target_desc->string.pointer = ACPI_MEM_CALLOCATE ( + (acpi_size) length + 1); if (!target_desc->string.pointer) { return_ACPI_STATUS (AE_NO_MEMORY); } diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c index f92efc51289..cafa702108d 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/executer/exsystem.c @@ -55,8 +55,8 @@ * * FUNCTION: acpi_ex_system_wait_semaphore * - * PARAMETERS: Semaphore - OSD semaphore to wait on - * Timeout - Max time to wait + * PARAMETERS: Semaphore - Semaphore to wait on + * Timeout - Max time to wait * * RETURN: Status * @@ -90,7 +90,8 @@ acpi_ex_system_wait_semaphore ( status = acpi_os_wait_semaphore (semaphore, 1, timeout); - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*** Thread awake after blocking, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "*** Thread awake after blocking, %s\n", acpi_format_exception (status))); /* Reacquire the interpreter */ @@ -111,8 +112,8 @@ acpi_ex_system_wait_semaphore ( * * FUNCTION: acpi_ex_system_do_stall * - * PARAMETERS: how_long - The amount of time to stall, - * in microseconds + * PARAMETERS: how_long - The amount of time to stall, + * in microseconds * * RETURN: Status * @@ -141,7 +142,8 @@ acpi_ex_system_do_stall ( * (ACPI specifies 100 usec as max, but this gives some slack in * order to support existing BIOSs) */ - ACPI_REPORT_ERROR (("Stall: Time parameter is too large (%d)\n", how_long)); + ACPI_REPORT_ERROR (("Stall: Time parameter is too large (%d)\n", + how_long)); status = AE_AML_OPERAND_VALUE; } else { @@ -156,8 +158,8 @@ acpi_ex_system_do_stall ( * * FUNCTION: acpi_ex_system_do_suspend * - * PARAMETERS: how_long - The amount of time to suspend, - * in milliseconds + * PARAMETERS: how_long - The amount of time to suspend, + * in milliseconds * * RETURN: None * @@ -192,8 +194,8 @@ acpi_ex_system_do_suspend ( * * FUNCTION: acpi_ex_system_acquire_mutex * - * PARAMETERS: *time_desc - The 'time to delay' object descriptor - * *obj_desc - The object descriptor for this op + * PARAMETERS: time_desc - The 'time to delay' object descriptor + * obj_desc - The object descriptor for this op * * RETURN: Status * @@ -218,16 +220,15 @@ acpi_ex_system_acquire_mutex ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* - * Support for the _GL_ Mutex object -- go get the global lock - */ + /* Support for the _GL_ Mutex object -- go get the global lock */ + if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { status = acpi_ev_acquire_global_lock ((u16) time_desc->integer.value); return_ACPI_STATUS (status); } status = acpi_ex_system_wait_semaphore (obj_desc->mutex.semaphore, - (u16) time_desc->integer.value); + (u16) time_desc->integer.value); return_ACPI_STATUS (status); } @@ -236,7 +237,7 @@ acpi_ex_system_acquire_mutex ( * * FUNCTION: acpi_ex_system_release_mutex * - * PARAMETERS: *obj_desc - The object descriptor for this op + * PARAMETERS: obj_desc - The object descriptor for this op * * RETURN: Status * @@ -261,9 +262,8 @@ acpi_ex_system_release_mutex ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* - * Support for the _GL_ Mutex object -- release the global lock - */ + /* Support for the _GL_ Mutex object -- release the global lock */ + if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { status = acpi_ev_release_global_lock (); return_ACPI_STATUS (status); @@ -278,9 +278,9 @@ acpi_ex_system_release_mutex ( * * FUNCTION: acpi_ex_system_signal_event * - * PARAMETERS: *obj_desc - The object descriptor for this op + * PARAMETERS: obj_desc - The object descriptor for this op * - * RETURN: AE_OK + * RETURN: Status * * DESCRIPTION: Provides an access point to perform synchronization operations * within the AML. @@ -309,8 +309,8 @@ acpi_ex_system_signal_event ( * * FUNCTION: acpi_ex_system_wait_event * - * PARAMETERS: *time_desc - The 'time to delay' object descriptor - * *obj_desc - The object descriptor for this op + * PARAMETERS: time_desc - The 'time to delay' object descriptor + * obj_desc - The object descriptor for this op * * RETURN: Status * @@ -333,7 +333,7 @@ acpi_ex_system_wait_event ( if (obj_desc) { status = acpi_ex_system_wait_semaphore (obj_desc->event.semaphore, - (u16) time_desc->integer.value); + (u16) time_desc->integer.value); } return_ACPI_STATUS (status); @@ -344,7 +344,7 @@ acpi_ex_system_wait_event ( * * FUNCTION: acpi_ex_system_reset_event * - * PARAMETERS: *obj_desc - The object descriptor for this op + * PARAMETERS: obj_desc - The object descriptor for this op * * RETURN: Status * diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c index 40c6abb8b49..5c7ec0c0417 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/executer/exutils.c @@ -67,22 +67,31 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exutils") +/* Local prototypes */ -#ifndef ACPI_NO_METHOD_EXECUTION +static u32 +acpi_ex_digits_needed ( + acpi_integer value, + u32 base); + +#ifndef ACPI_NO_METHOD_EXECUTION /******************************************************************************* * * FUNCTION: acpi_ex_enter_interpreter * * PARAMETERS: None * + * RETURN: Status + * * DESCRIPTION: Enter the interpreter execution region. Failure to enter * the interpreter region is a fatal system error * ******************************************************************************/ acpi_status -acpi_ex_enter_interpreter (void) +acpi_ex_enter_interpreter ( + void) { acpi_status status; @@ -104,6 +113,8 @@ acpi_ex_enter_interpreter (void) * * PARAMETERS: None * + * RETURN: None + * * DESCRIPTION: Exit the interpreter execution region * * Cases where the interpreter is unlocked: @@ -119,7 +130,8 @@ acpi_ex_enter_interpreter (void) ******************************************************************************/ void -acpi_ex_exit_interpreter (void) +acpi_ex_exit_interpreter ( + void) { acpi_status status; @@ -212,7 +224,8 @@ acpi_ex_acquire_global_lock ( locked = TRUE; } else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not acquire Global Lock, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not acquire Global Lock, %s\n", acpi_format_exception (status))); } } @@ -228,7 +241,7 @@ acpi_ex_acquire_global_lock ( * PARAMETERS: locked_by_me - Return value from corresponding call to * acquire_global_lock. * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Release the global lock if it is locked. * @@ -269,11 +282,14 @@ acpi_ex_release_global_lock ( * PARAMETERS: Value - Value to be represented * Base - Base of representation * - * RETURN: the number of digits needed to represent Value in Base + * RETURN: The number of digits. + * + * DESCRIPTION: Calculate the number of digits needed to represent the Value + * in the given Base (Radix) * ******************************************************************************/ -u32 +static u32 acpi_ex_digits_needed ( acpi_integer value, u32 base) @@ -312,6 +328,8 @@ acpi_ex_digits_needed ( * PARAMETERS: numeric_id - EISA ID to be converted * out_string - Where to put the converted string (8 bytes) * + * RETURN: None + * * DESCRIPTION: Convert a numeric EISA ID to string representation * ******************************************************************************/ @@ -349,7 +367,10 @@ acpi_ex_eisa_id_to_string ( * PARAMETERS: Value - Value to be converted * out_string - Where to put the converted string (8 bytes) * - * RETURN: Convert a number to string representation + * RETURN: None, string + * + * DESCRIPTOIN: Convert a number to string representation. Assumes string + * buffer is large enough to hold the string. * ******************************************************************************/ diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c index 529e922bdc8..b51001e74ee 100644 --- a/drivers/acpi/hardware/hwacpi.c +++ b/drivers/acpi/hardware/hwacpi.c @@ -58,7 +58,8 @@ * * RETURN: Status * - * DESCRIPTION: Initialize and validate various ACPI registers + * DESCRIPTION: Initialize and validate the various ACPI registers defined in + * the FADT. * ******************************************************************************/ @@ -75,7 +76,7 @@ acpi_hw_initialize ( /* We must have the ACPI tables by the time we get here */ if (!acpi_gbl_FADT) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "A FADT is not loaded\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No FADT is present\n")); return_ACPI_STATUS (AE_NO_ACPI_TABLES); } @@ -131,7 +132,8 @@ acpi_hw_set_mode ( * transitions are not supported. */ if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) { - ACPI_REPORT_ERROR (("No ACPI mode transition supported in this system (enable/disable both zero)\n")); + ACPI_REPORT_ERROR (( + "No ACPI mode transition supported in this system (enable/disable both zero)\n")); return_ACPI_STATUS (AE_OK); } @@ -162,7 +164,8 @@ acpi_hw_set_mode ( } if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("Could not write mode change, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Could not write mode change, %s\n", + acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -173,7 +176,8 @@ acpi_hw_set_mode ( retry = 3000; while (retry) { if (acpi_hw_get_mode() == mode) { - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode)); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", + mode)); return_ACPI_STATUS (AE_OK); } acpi_os_stall(1000); @@ -185,7 +189,7 @@ acpi_hw_set_mode ( } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_hw_get_mode * @@ -199,7 +203,8 @@ acpi_hw_set_mode ( ******************************************************************************/ u32 -acpi_hw_get_mode (void) +acpi_hw_get_mode ( + void) { acpi_status status; u32 value; diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c index 9ac1d639bf5..8daeabb2fc7 100644 --- a/drivers/acpi/hardware/hwgpe.c +++ b/drivers/acpi/hardware/hwgpe.c @@ -48,6 +48,13 @@ #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME ("hwgpe") +/* Local prototypes */ + +static acpi_status +acpi_hw_enable_wakeup_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block); + /****************************************************************************** * @@ -135,6 +142,7 @@ acpi_hw_clear_gpe ( * DESCRIPTION: Return the status of a single GPE. * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_hw_get_gpe_status ( @@ -206,7 +214,7 @@ unlock_and_exit: * * RETURN: Status * - * DESCRIPTION: Disable all GPEs within a GPE block + * DESCRIPTION: Disable all GPEs within a single GPE block * ******************************************************************************/ @@ -244,7 +252,7 @@ acpi_hw_disable_gpe_block ( * * RETURN: Status * - * DESCRIPTION: Clear status bits for all GPEs within a GPE block + * DESCRIPTION: Clear status bits for all GPEs within a single GPE block * ******************************************************************************/ @@ -282,8 +290,8 @@ acpi_hw_clear_gpe_block ( * * RETURN: Status * - * DESCRIPTION: Enable all "runtime" GPEs within a GPE block. (Includes - * combination wake/run GPEs.) + * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes + * combination wake/run GPEs. * ******************************************************************************/ @@ -327,12 +335,12 @@ acpi_hw_enable_runtime_gpe_block ( * * RETURN: Status * - * DESCRIPTION: Enable all "wake" GPEs within a GPE block. (Includes - * combination wake/run GPEs.) + * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes + * combination wake/run GPEs. * ******************************************************************************/ -acpi_status +static acpi_status acpi_hw_enable_wakeup_gpe_block ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block) @@ -350,7 +358,8 @@ acpi_hw_enable_wakeup_gpe_block ( /* Enable all "wake" GPEs in this register */ - status = acpi_hw_low_level_write (8, gpe_block->register_info[i].enable_for_wake, + status = acpi_hw_low_level_write (8, + gpe_block->register_info[i].enable_for_wake, &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE (status)) { return (status); @@ -369,7 +378,7 @@ acpi_hw_enable_wakeup_gpe_block ( * * RETURN: Status * - * DESCRIPTION: Disable and clear all GPEs + * DESCRIPTION: Disable and clear all GPEs in all GPE blocks * ******************************************************************************/ @@ -397,7 +406,7 @@ acpi_hw_disable_all_gpes ( * * RETURN: Status * - * DESCRIPTION: Enable all GPEs of the given type + * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks * ******************************************************************************/ @@ -424,7 +433,7 @@ acpi_hw_enable_all_runtime_gpes ( * * RETURN: Status * - * DESCRIPTION: Enable all GPEs of the given type + * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks * ******************************************************************************/ diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index 91af0c2ddcf..6d9e4eb8483 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -87,8 +87,9 @@ acpi_hw_clear_acpi_status ( } } - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, - ACPI_BITMASK_ALL_FIXED_STATUS); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_STATUS, + ACPI_BITMASK_ALL_FIXED_STATUS); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } @@ -138,28 +139,30 @@ acpi_get_sleep_type_data ( { acpi_status status = AE_OK; struct acpi_parameter_info info; + char *sleep_state_name; ACPI_FUNCTION_TRACE ("acpi_get_sleep_type_data"); - /* - * Validate parameters - */ + /* Validate parameters */ + if ((sleep_state > ACPI_S_STATES_MAX) || !sleep_type_a || !sleep_type_b) { return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* - * Evaluate the namespace object containing the values for this state - */ + /* Evaluate the namespace object containing the values for this state */ + info.parameters = NULL; - status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_sleep_state_names[sleep_state], - &info); + info.return_object = NULL; + sleep_state_name = (char *) acpi_gbl_sleep_state_names[sleep_state]; + + status = acpi_ns_evaluate_by_name (sleep_state_name, &info); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s while evaluating sleep_state [%s]\n", - acpi_format_exception (status), acpi_gbl_sleep_state_names[sleep_state])); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "%s while evaluating sleep_state [%s]\n", + acpi_format_exception (status), sleep_state_name)); return_ACPI_STATUS (status); } @@ -167,45 +170,57 @@ acpi_get_sleep_type_data ( /* Must have a return object */ if (!info.return_object) { - ACPI_REPORT_ERROR (("Missing Sleep State object\n")); + ACPI_REPORT_ERROR (("No Sleep State object returned from [%s]\n", + sleep_state_name)); status = AE_NOT_EXIST; } /* It must be of type Package */ else if (ACPI_GET_OBJECT_TYPE (info.return_object) != ACPI_TYPE_PACKAGE) { - ACPI_REPORT_ERROR (("Sleep State object not a Package\n")); + ACPI_REPORT_ERROR (("Sleep State return object is not a Package\n")); status = AE_AML_OPERAND_TYPE; } - /* The package must have at least two elements */ - + /* + * The package must have at least two elements. NOTE (March 2005): This + * goes against the current ACPI spec which defines this object as a + * package with one encoded DWORD element. However, existing practice + * by BIOS vendors seems to be to have 2 or more elements, at least + * one per sleep type (A/B). + */ else if (info.return_object->package.count < 2) { - ACPI_REPORT_ERROR (("Sleep State package does not have at least two elements\n")); + ACPI_REPORT_ERROR (( + "Sleep State return package does not have at least two elements\n")); status = AE_AML_NO_OPERAND; } /* The first two elements must both be of type Integer */ - else if ((ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[0]) != ACPI_TYPE_INTEGER) || - (ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[1]) != ACPI_TYPE_INTEGER)) { - ACPI_REPORT_ERROR (("Sleep State package elements are not both Integers (%s, %s)\n", + else if ((ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[0]) + != ACPI_TYPE_INTEGER) || + (ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[1]) + != ACPI_TYPE_INTEGER)) { + ACPI_REPORT_ERROR (( + "Sleep State return package elements are not both Integers (%s, %s)\n", acpi_ut_get_object_type_name (info.return_object->package.elements[0]), acpi_ut_get_object_type_name (info.return_object->package.elements[1]))); status = AE_AML_OPERAND_TYPE; } else { - /* - * Valid _Sx_ package size, type, and value - */ - *sleep_type_a = (u8) (info.return_object->package.elements[0])->integer.value; - *sleep_type_b = (u8) (info.return_object->package.elements[1])->integer.value; + /* Valid _Sx_ package size, type, and value */ + + *sleep_type_a = (u8) + (info.return_object->package.elements[0])->integer.value; + *sleep_type_b = (u8) + (info.return_object->package.elements[1])->integer.value; } if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "While evaluating sleep_state [%s], bad Sleep object %p type %s\n", - acpi_gbl_sleep_state_names[sleep_state], info.return_object, + "%s While evaluating sleep_state [%s], bad Sleep object %p type %s\n", + acpi_format_exception (status), + sleep_state_name, info.return_object, acpi_ut_get_object_type_name (info.return_object))); } @@ -221,9 +236,9 @@ EXPORT_SYMBOL(acpi_get_sleep_type_data); * * PARAMETERS: register_id - Index of ACPI Register to access * - * RETURN: The bit mask to be used when accessing the register + * RETURN: The bitmask to be used when accessing the register * - * DESCRIPTION: Map register_id into a register bit mask. + * DESCRIPTION: Map register_id into a register bitmask. * ******************************************************************************/ @@ -359,7 +374,7 @@ acpi_set_register ( /* Always do a register read first so we can insert the new bits */ status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, - bit_reg_info->parent_register, ®ister_value); + bit_reg_info->parent_register, ®ister_value); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } @@ -396,7 +411,7 @@ acpi_set_register ( bit_reg_info->access_bit_mask, value); status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_ENABLE, (u16) register_value); + ACPI_REGISTER_PM1_ENABLE, (u16) register_value); break; @@ -413,7 +428,7 @@ acpi_set_register ( bit_reg_info->access_bit_mask, value); status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM1_CONTROL, (u16) register_value); + ACPI_REGISTER_PM1_CONTROL, (u16) register_value); break; @@ -427,17 +442,19 @@ acpi_set_register ( ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM2 control: Read %X from %8.8X%8.8X\n", register_value, - ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address))); + ACPI_FORMAT_UINT64 ( + acpi_gbl_FADT->xpm2_cnt_blk.address))); ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position, bit_reg_info->access_bit_mask, value); ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %4.4X to %8.8X%8.8X\n", register_value, - ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address))); + ACPI_FORMAT_UINT64 ( + acpi_gbl_FADT->xpm2_cnt_blk.address))); status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, - ACPI_REGISTER_PM2_CONTROL, (u8) (register_value)); + ACPI_REGISTER_PM2_CONTROL, (u8) (register_value)); break; @@ -454,7 +471,9 @@ unlock_and_exit: /* Normalize the value that was read */ - ACPI_DEBUG_EXEC (register_value = ((register_value & bit_reg_info->access_bit_mask) >> bit_reg_info->bit_position)); + ACPI_DEBUG_EXEC (register_value = + ((register_value & bit_reg_info->access_bit_mask) >> + bit_reg_info->bit_position)); ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Set bits: %8.8X actual %8.8X register %X\n", value, register_value, bit_reg_info->parent_register)); @@ -469,7 +488,7 @@ EXPORT_SYMBOL(acpi_set_register); * * PARAMETERS: use_lock - Mutex hw access * register_id - register_iD + Offset - * return_value - Value that was read from the register + * return_value - Where the register value is returned * * RETURN: Status and the value read. * @@ -557,7 +576,8 @@ acpi_hw_register_read ( break; default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Register ID: %X\n", register_id)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Register ID: %X\n", + register_id)); status = AE_BAD_PARAMETER; break; } @@ -763,10 +783,11 @@ acpi_hw_low_level_read ( return (AE_BAD_PARAMETER); } - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", - *value, width, - ACPI_FORMAT_UINT64 (address), - acpi_ut_get_region_name (reg->address_space_id))); + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", + *value, width, + ACPI_FORMAT_UINT64 (address), + acpi_ut_get_region_name (reg->address_space_id))); return (status); } @@ -841,10 +862,11 @@ acpi_hw_low_level_write ( return (AE_BAD_PARAMETER); } - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", - value, width, - ACPI_FORMAT_UINT64 (address), - acpi_ut_get_region_name (reg->address_space_id))); + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", + value, width, + ACPI_FORMAT_UINT64 (address), + acpi_ut_get_region_name (reg->address_space_id))); return (status); } diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 77b3e9a8550..415d342aeab 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -43,27 +43,13 @@ */ #include - #include #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME ("hwsleep") -#define METHOD_NAME__BFS "\\_BFS" -#define METHOD_NAME__GTS "\\_GTS" -#define METHOD_NAME__PTS "\\_PTS" -#define METHOD_NAME__SST "\\_SI._SST" -#define METHOD_NAME__WAK "\\_WAK" - -#define ACPI_SST_INDICATOR_OFF 0 -#define ACPI_SST_WORKING 1 -#define ACPI_SST_WAKING 2 -#define ACPI_SST_SLEEPING 3 -#define ACPI_SST_SLEEP_CONTEXT 4 - - -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_set_firmware_waking_vector * @@ -72,7 +58,7 @@ * * RETURN: Status * - * DESCRIPTION: access function for d_firmware_waking_vector field in FACS + * DESCRIPTION: Access function for the firmware_waking_vector field in FACS * ******************************************************************************/ @@ -99,19 +85,20 @@ acpi_set_firmware_waking_vector ( } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_get_firmware_waking_vector * - * PARAMETERS: *physical_address - Output buffer where contents of + * PARAMETERS: *physical_address - Where the contents of * the firmware_waking_vector field of - * the FACS will be stored. + * the FACS will be returned. * - * RETURN: Status + * RETURN: Status, vector * - * DESCRIPTION: Access function for firmware_waking_vector field in FACS + * DESCRIPTION: Access function for the firmware_waking_vector field in FACS * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_firmware_waking_vector ( @@ -141,7 +128,7 @@ acpi_get_firmware_waking_vector ( #endif -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_enter_sleep_state_prep * @@ -215,7 +202,7 @@ acpi_enter_sleep_state_prep ( break; default: - arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is indicator off */ + arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is off */ break; } @@ -223,14 +210,15 @@ acpi_enter_sleep_state_prep ( status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { - ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Method _SST failed, %s\n", + acpi_format_exception (status))); } return_ACPI_STATUS (AE_OK); } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_enter_sleep_state * @@ -299,15 +287,18 @@ acpi_enter_sleep_state ( /* Get current value of PM1A control */ - status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol); + status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Entering sleep state [S%d]\n", sleep_state)); + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "Entering sleep state [S%d]\n", sleep_state)); /* Clear SLP_EN and SLP_TYP fields */ - PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask | sleep_enable_reg_info->access_bit_mask); + PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask | + sleep_enable_reg_info->access_bit_mask); PM1Bcontrol = PM1Acontrol; /* Insert SLP_TYP bits */ @@ -322,12 +313,14 @@ acpi_enter_sleep_state ( /* Write #1: fill in SLP_TYP data */ - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -341,22 +334,25 @@ acpi_enter_sleep_state ( ACPI_FLUSH_CPU_CACHE (); - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } if (sleep_state > ACPI_STATE_S3) { /* - * We wanted to sleep > S3, but it didn't happen (by virtue of the fact that - * we are still executing!) + * We wanted to sleep > S3, but it didn't happen (by virtue of the + * fact that we are still executing!) * - * Wait ten seconds, then try again. This is to get S4/S5 to work on all machines. + * Wait ten seconds, then try again. This is to get S4/S5 to work on + * all machines. * * We wait so long to allow chipsets that poll this reg very slowly to * still read the right value. Ideally, this block would go @@ -364,7 +360,8 @@ acpi_enter_sleep_state ( */ acpi_os_stall (10000000); - status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_CONTROL, + status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_CONTROL, sleep_enable_reg_info->access_bit_mask); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -374,7 +371,8 @@ acpi_enter_sleep_state ( /* Wait until we enter sleep state */ do { - status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_DO_NOT_LOCK); + status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, + ACPI_MTX_DO_NOT_LOCK); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -388,7 +386,7 @@ acpi_enter_sleep_state ( EXPORT_SYMBOL(acpi_enter_sleep_state); -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_enter_sleep_state_s4bios * @@ -439,11 +437,13 @@ acpi_enter_sleep_state_s4bios ( ACPI_FLUSH_CPU_CACHE (); - status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, (u32) acpi_gbl_FADT->S4bios_req, 8); + status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, + (u32) acpi_gbl_FADT->S4bios_req, 8); do { acpi_os_stall(1000); - status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_DO_NOT_LOCK); + status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, + ACPI_MTX_DO_NOT_LOCK); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -454,7 +454,7 @@ acpi_enter_sleep_state_s4bios ( EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios); -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_leave_sleep_state * @@ -534,18 +534,21 @@ acpi_leave_sleep_state ( arg.integer.value = ACPI_SST_WAKING; status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { - ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Method _SST failed, %s\n", + acpi_format_exception (status))); } arg.integer.value = sleep_state; status = acpi_evaluate_object (NULL, METHOD_NAME__BFS, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { - ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", + acpi_format_exception (status))); } status = acpi_evaluate_object (NULL, METHOD_NAME__WAK, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { - ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", + acpi_format_exception (status))); } /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ @@ -567,15 +570,19 @@ acpi_leave_sleep_state ( /* Enable power button */ - (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, + (void) acpi_set_register( + acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, 1, ACPI_MTX_DO_NOT_LOCK); - (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, + + (void) acpi_set_register( + acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, 1, ACPI_MTX_DO_NOT_LOCK); arg.integer.value = ACPI_SST_WORKING; status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { - ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Method _SST failed, %s\n", + acpi_format_exception (status))); } return_ACPI_STATUS (status); diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c index 1906167d729..49d7b395322 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/hardware/hwtimer.c @@ -43,7 +43,6 @@ */ #include - #include #define _COMPONENT ACPI_HARDWARE @@ -90,7 +89,7 @@ acpi_get_timer_resolution ( * * PARAMETERS: Ticks - Where the timer value is returned * - * RETURN: Status and current ticks + * RETURN: Status and current timer value (ticks) * * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks). * @@ -199,5 +198,6 @@ acpi_get_timer_duration ( *time_elapsed = (u32) quotient; return_ACPI_STATUS (status); } + EXPORT_SYMBOL(acpi_get_timer_duration); diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index 1c0c12336c5..ece7a9dedd5 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -67,7 +67,8 @@ ******************************************************************************/ acpi_status -acpi_ns_root_initialize (void) +acpi_ns_root_initialize ( + void) { acpi_status status; const struct acpi_predefined_names *init_val = NULL; @@ -265,7 +266,7 @@ unlock_and_exit: * * FUNCTION: acpi_ns_lookup * - * PARAMETERS: prefix_node - Search scope if name is not fully qualified + * PARAMETERS: scope_info - Current scope info block * Pathname - Search pathname, in internal format * (as represented in the AML stream) * Type - Type associated with name diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index bfd922c5c7d..5653a19d717 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -49,14 +49,20 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsalloc") +/* Local prototypes */ + +static void +acpi_ns_remove_reference ( + struct acpi_namespace_node *node); + /******************************************************************************* * * FUNCTION: acpi_ns_create_node * - * PARAMETERS: acpi_name - Name of the new node + * PARAMETERS: Name - Name of the new node (4 char ACPI name) * - * RETURN: None + * RETURN: New namespace node (Null on failure) * * DESCRIPTION: Create a namespace node * @@ -145,7 +151,6 @@ acpi_ns_delete_node ( } } - ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++); /* @@ -157,57 +162,6 @@ acpi_ns_delete_node ( } -#ifdef ACPI_ALPHABETIC_NAMESPACE -/******************************************************************************* - * - * FUNCTION: acpi_ns_compare_names - * - * PARAMETERS: Name1 - First name to compare - * Name2 - Second name to compare - * - * RETURN: value from strncmp - * - * DESCRIPTION: Compare two ACPI names. Names that are prefixed with an - * underscore are forced to be alphabetically first. - * - ******************************************************************************/ - -int -acpi_ns_compare_names ( - char *name1, - char *name2) -{ - char reversed_name1[ACPI_NAME_SIZE]; - char reversed_name2[ACPI_NAME_SIZE]; - u32 i; - u32 j; - - - /* - * Replace all instances of "underscore" with a value that is smaller so - * that all names that are prefixed with underscore(s) are alphabetically - * first. - * - * Reverse the name bytewise so we can just do a 32-bit compare instead - * of a strncmp. - */ - for (i = 0, j= (ACPI_NAME_SIZE - 1); i < ACPI_NAME_SIZE; i++, j--) { - reversed_name1[j] = name1[i]; - if (name1[i] == '_') { - reversed_name1[j] = '*'; - } - - reversed_name2[j] = name2[i]; - if (name2[i] == '_') { - reversed_name2[j] = '*'; - } - } - - return (*(int *) reversed_name1 - *(int *) reversed_name2); -} -#endif - - /******************************************************************************* * * FUNCTION: acpi_ns_install_node @@ -271,7 +225,8 @@ acpi_ns_install_node ( * alphabetic placement. */ previous_child_node = NULL; - while (acpi_ns_compare_names (acpi_ut_get_node_name (child_node), acpi_ut_get_node_name (node)) < 0) { + while (acpi_ns_compare_names (acpi_ut_get_node_name (child_node), + acpi_ut_get_node_name (node)) < 0) { if (child_node->flags & ANOBJ_END_OF_PEER_LIST) { /* Last peer; Clear end-of-list flag */ @@ -429,7 +384,8 @@ acpi_ns_delete_children ( /* There should be only one reference remaining on this node */ if (child_node->reference_count != 1) { - ACPI_REPORT_WARNING (("Existing references (%d) on node being deleted (%p)\n", + ACPI_REPORT_WARNING (( + "Existing references (%d) on node being deleted (%p)\n", child_node->reference_count, child_node)); } @@ -548,7 +504,7 @@ acpi_ns_delete_namespace_subtree ( * ******************************************************************************/ -void +static void acpi_ns_remove_reference ( struct acpi_namespace_node *node) { @@ -683,3 +639,54 @@ acpi_ns_delete_namespace_by_owner ( } +#ifdef ACPI_ALPHABETIC_NAMESPACE +/******************************************************************************* + * + * FUNCTION: acpi_ns_compare_names + * + * PARAMETERS: Name1 - First name to compare + * Name2 - Second name to compare + * + * RETURN: value from strncmp + * + * DESCRIPTION: Compare two ACPI names. Names that are prefixed with an + * underscore are forced to be alphabetically first. + * + ******************************************************************************/ + +int +acpi_ns_compare_names ( + char *name1, + char *name2) +{ + char reversed_name1[ACPI_NAME_SIZE]; + char reversed_name2[ACPI_NAME_SIZE]; + u32 i; + u32 j; + + + /* + * Replace all instances of "underscore" with a value that is smaller so + * that all names that are prefixed with underscore(s) are alphabetically + * first. + * + * Reverse the name bytewise so we can just do a 32-bit compare instead + * of a strncmp. + */ + for (i = 0, j= (ACPI_NAME_SIZE - 1); i < ACPI_NAME_SIZE; i++, j--) { + reversed_name1[j] = name1[i]; + if (name1[i] == '_') { + reversed_name1[j] = '*'; + } + + reversed_name2[j] = name2[i]; + if (name2[i] == '_') { + reversed_name2[j] = '*'; + } + } + + return (*(int *) reversed_name1 - *(int *) reversed_name2); +} +#endif + + diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c index 1f6af3eb6c9..4550e6f9809 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/namespace/nsdump.c @@ -50,16 +50,32 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsdump") +/* Local prototypes */ -#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +#ifdef ACPI_OBSOLETE_FUNCTIONS +void +acpi_ns_dump_root_devices ( + void); +static acpi_status +acpi_ns_dump_one_device ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); +#endif + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) /******************************************************************************* * * FUNCTION: acpi_ns_print_pathname * - * PARAMETERS: num_segment - Number of ACPI name segments + * PARAMETERS: num_segments - Number of ACPI name segments * Pathname - The compressed (internal) path * + * RETURN: None + * * DESCRIPTION: Print an object's full namespace pathname * ******************************************************************************/ @@ -103,6 +119,8 @@ acpi_ns_print_pathname ( * Level - Desired debug level * Component - Caller's component ID * + * RETURN: None + * * DESCRIPTION: Print an object's full namespace pathname * Manages allocation/freeing of a pathname buffer * @@ -137,9 +155,12 @@ acpi_ns_dump_pathname ( * * FUNCTION: acpi_ns_dump_one_object * - * PARAMETERS: Handle - Node to be dumped + * PARAMETERS: obj_handle - Node to be dumped * Level - Nesting level of the handle * Context - Passed into walk_namespace + * return_value - Not used + * + * RETURN: Status * * DESCRIPTION: Dump a single Node * This procedure is a user_function called by acpi_ns_walk_namespace. @@ -394,8 +415,7 @@ acpi_ns_dump_one_object ( return (AE_OK); } - acpi_os_printf ("(R%d)", - obj_desc->common.reference_count); + acpi_os_printf ("(R%d)", obj_desc->common.reference_count); switch (type) { case ACPI_TYPE_METHOD: @@ -551,18 +571,20 @@ cleanup: #ifdef ACPI_FUTURE_USAGE - /******************************************************************************* * * FUNCTION: acpi_ns_dump_objects * * PARAMETERS: Type - Object type to be dumped + * display_type - 0 or ACPI_DISPLAY_SUMMARY * max_depth - Maximum depth of dump. Use ACPI_UINT32_MAX * for an effectively unlimited depth. * owner_id - Dump only objects owned by this ID. Use * ACPI_UINT32_MAX to match all owners. * start_handle - Where in namespace to start/end search * + * RETURN: None + * * DESCRIPTION: Dump typed objects within the loaded namespace. * Uses acpi_ns_walk_namespace in conjunction with acpi_ns_dump_one_object. * @@ -592,6 +614,39 @@ acpi_ns_dump_objects ( } +/******************************************************************************* + * + * FUNCTION: acpi_ns_dump_entry + * + * PARAMETERS: Handle - Node to be dumped + * debug_level - Output level + * + * RETURN: None + * + * DESCRIPTION: Dump a single Node + * + ******************************************************************************/ + +void +acpi_ns_dump_entry ( + acpi_handle handle, + u32 debug_level) +{ + struct acpi_walk_info info; + + + ACPI_FUNCTION_ENTRY (); + + + info.debug_level = debug_level; + info.owner_id = ACPI_UINT32_MAX; + info.display_type = ACPI_DISPLAY_SUMMARY; + + (void) acpi_ns_dump_one_object (handle, 1, &info, NULL); +} + + +#ifdef _ACPI_ASL_COMPILER /******************************************************************************* * * FUNCTION: acpi_ns_dump_tables @@ -601,6 +656,8 @@ acpi_ns_dump_objects ( * max_depth - Maximum depth of dump. Use INT_MAX * for an effectively unlimited depth. * + * RETURN: None + * * DESCRIPTION: Dump the name space, or a portion of it. * ******************************************************************************/ @@ -626,7 +683,7 @@ acpi_ns_dump_tables ( } if (ACPI_NS_ALL == search_base) { - /* entire namespace */ + /* Entire namespace */ search_handle = acpi_gbl_root_node; ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "\\\n")); @@ -636,38 +693,6 @@ acpi_ns_dump_tables ( ACPI_UINT32_MAX, search_handle); return_VOID; } - -#endif /* ACPI_FUTURE_USAGE */ - - -/******************************************************************************* - * - * FUNCTION: acpi_ns_dump_entry - * - * PARAMETERS: Handle - Node to be dumped - * debug_level - Output level - * - * DESCRIPTION: Dump a single Node - * - ******************************************************************************/ - -void -acpi_ns_dump_entry ( - acpi_handle handle, - u32 debug_level) -{ - struct acpi_walk_info info; - - - ACPI_FUNCTION_ENTRY (); - - - info.debug_level = debug_level; - info.owner_id = ACPI_UINT32_MAX; - info.display_type = ACPI_DISPLAY_SUMMARY; - - (void) acpi_ns_dump_one_object (handle, 1, &info, NULL); -} - -#endif - +#endif /* _ACPI_ASL_COMPILER */ +#endif /* ACPI_FUTURE_USAGE */ +#endif /* defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) */ diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c index d30a59e6b07..27c4f7cd2a4 100644 --- a/drivers/acpi/namespace/nsdumpdv.c +++ b/drivers/acpi/namespace/nsdumpdv.c @@ -43,15 +43,18 @@ #include -#include +/* TBD: This entire module is apparently obsolete and should be removed */ + #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsdumpdv") - +#ifdef ACPI_OBSOLETE_FUNCTIONS #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +#include + /******************************************************************************* * * FUNCTION: acpi_ns_dump_one_device @@ -59,13 +62,16 @@ * PARAMETERS: Handle - Node to be dumped * Level - Nesting level of the handle * Context - Passed into walk_namespace + * return_value - Not used + * + * RETURN: Status * * DESCRIPTION: Dump a single Node that represents a device * This procedure is a user_function called by acpi_ns_walk_namespace. * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_dump_one_device ( acpi_handle obj_handle, u32 level, @@ -108,12 +114,15 @@ acpi_ns_dump_one_device ( * * PARAMETERS: None * + * RETURN: None + * * DESCRIPTION: Dump all objects of type "device" * ******************************************************************************/ void -acpi_ns_dump_root_devices (void) +acpi_ns_dump_root_devices ( + void) { acpi_handle sys_bus_handle; acpi_status status; @@ -142,5 +151,6 @@ acpi_ns_dump_root_devices (void) } #endif +#endif diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index 0d008d53657..1ae89a1c882 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -52,19 +52,33 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nseval") +/* Local prototypes */ + +static acpi_status +acpi_ns_execute_control_method ( + struct acpi_parameter_info *info); + +static acpi_status +acpi_ns_get_object_value ( + struct acpi_parameter_info *info); + /******************************************************************************* * * FUNCTION: acpi_ns_evaluate_relative * - * PARAMETERS: Pathname - Name of method to execute, If NULL, the - * handle is the object to execute - * Info - Method info block + * PARAMETERS: Pathname - Name of method to execute, If NULL, the + * handle is the object to execute + * Info - Method info block, contains: + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * Params - List of parameters to pass to the method, + * terminated by NULL. Params itself may be + * NULL if no parameters are being passed. * * RETURN: Status * - * DESCRIPTION: Find and execute the requested method using the handle as a - * scope + * DESCRIPTION: Evaluate the object or find and execute the requested method * * MUTEX: Locks Namespace * @@ -157,8 +171,8 @@ cleanup1: * * FUNCTION: acpi_ns_evaluate_by_name * - * PARAMETERS: Pathname - Fully qualified pathname to the object - * Info - Contains: + * PARAMETERS: Pathname - Fully qualified pathname to the object + * Info - Method info block, contains: * return_object - Where to put method's return value (if * any). If NULL, no value is returned. * Params - List of parameters to pass to the method, @@ -167,8 +181,8 @@ cleanup1: * * RETURN: Status * - * DESCRIPTION: Find and execute the requested method passing the given - * parameters + * DESCRIPTION: Evaluate the object or rind and execute the requested method + * passing the given parameters * * MUTEX: Locks Namespace * @@ -241,17 +255,21 @@ cleanup: * * FUNCTION: acpi_ns_evaluate_by_handle * - * PARAMETERS: Handle - Method Node to execute - * Params - List of parameters to pass to the method, - * terminated by NULL. Params itself may be + * PARAMETERS: Info - Method info block, contains: + * Node - Method/Object Node to execute + * Parameters - List of parameters to pass to the method, + * terminated by NULL. Params itself may be * NULL if no parameters are being passed. - * param_type - Type of Parameter list - * return_object - Where to put method's return value (if - * any). If NULL, no value is returned. + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * parameter_type - Type of Parameter list + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. * * RETURN: Status * - * DESCRIPTION: Execute the requested method passing the given parameters + * DESCRIPTION: Evaluate object or execute the requested method passing the + * given parameters * * MUTEX: Locks Namespace * @@ -345,7 +363,16 @@ acpi_ns_evaluate_by_handle ( * * FUNCTION: acpi_ns_execute_control_method * - * PARAMETERS: Info - Method info block (w/params) + * PARAMETERS: Info - Method info block, contains: + * Node - Method Node to execute + * Parameters - List of parameters to pass to the method, + * terminated by NULL. Params itself may be + * NULL if no parameters are being passed. + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * parameter_type - Type of Parameter list + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. * * RETURN: Status * @@ -355,7 +382,7 @@ acpi_ns_evaluate_by_handle ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_execute_control_method ( struct acpi_parameter_info *info) { @@ -414,7 +441,10 @@ acpi_ns_execute_control_method ( * * FUNCTION: acpi_ns_get_object_value * - * PARAMETERS: Info - Method info block (w/params) + * PARAMETERS: Info - Method info block, contains: + * Node - Object's NS node + * return_object - Where to put object value (if + * any). If NULL, no value is returned. * * RETURN: Status * @@ -424,7 +454,7 @@ acpi_ns_execute_control_method ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_get_object_value ( struct acpi_parameter_info *info) { diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index 4a46b380605..362802ae29a 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -50,6 +50,22 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsinit") +/* Local prototypes */ + +static acpi_status +acpi_ns_init_one_object ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value); + +static acpi_status +acpi_ns_init_one_device ( + acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value); + /******************************************************************************* * @@ -191,7 +207,7 @@ acpi_ns_initialize_devices ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_init_one_object ( acpi_handle obj_handle, u32 level, @@ -331,7 +347,7 @@ acpi_ns_init_one_object ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_init_one_device ( acpi_handle obj_handle, u32 nesting_level, @@ -374,7 +390,8 @@ acpi_ns_init_one_device ( /* * Run _STA to determine if we can run _INI on the device. */ - ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_STA")); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, + pinfo.node, METHOD_NAME__STA)); status = acpi_ut_execute_STA (pinfo.node, &flags); if (ACPI_FAILURE (status)) { @@ -399,8 +416,9 @@ acpi_ns_init_one_device ( /* * The device is present. Run _INI. */ - ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_INI")); - status = acpi_ns_evaluate_relative ("_INI", &pinfo); + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, + pinfo.node, METHOD_NAME__INI)); + status = acpi_ns_evaluate_relative (METHOD_NAME__INI, &pinfo); if (ACPI_FAILURE (status)) { /* No _INI (AE_NOT_FOUND) means device requires no initialization */ diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c index 1d7aedf68a7..34e49701660 100644 --- a/drivers/acpi/namespace/nsload.c +++ b/drivers/acpi/namespace/nsload.c @@ -50,9 +50,24 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsload") +/* Local prototypes */ -#ifndef ACPI_NO_METHOD_EXECUTION +static acpi_status +acpi_ns_load_table_by_type ( + acpi_table_type table_type); + +#ifdef ACPI_FUTURE_IMPLEMENTATION +acpi_status +acpi_ns_unload_namespace ( + acpi_handle handle); + +static acpi_status +acpi_ns_delete_subtree ( + acpi_handle start_handle); +#endif + +#ifndef ACPI_NO_METHOD_EXECUTION /******************************************************************************* * * FUNCTION: acpi_ns_load_table @@ -159,7 +174,7 @@ acpi_ns_load_table ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_load_table_by_type ( acpi_table_type table_type) { @@ -321,8 +336,7 @@ acpi_ns_load_namespace ( } -#ifdef ACPI_FUTURE_USAGE - +#ifdef ACPI_FUTURE_IMPLEMENTATION /******************************************************************************* * * FUNCTION: acpi_ns_delete_subtree @@ -339,7 +353,7 @@ acpi_ns_load_namespace ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ns_delete_subtree ( acpi_handle start_handle) { @@ -453,8 +467,6 @@ acpi_ns_unload_namespace ( return_ACPI_STATUS (status); } - -#endif /* ACPI_FUTURE_USAGE */ - +#endif #endif diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c index b6f8f910eff..d8ce7e39795 100644 --- a/drivers/acpi/namespace/nsnames.c +++ b/drivers/acpi/namespace/nsnames.c @@ -50,6 +50,14 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsnames") +/* Local prototypes */ + +static void +acpi_ns_build_external_path ( + struct acpi_namespace_node *node, + acpi_size size, + char *name_buffer); + /******************************************************************************* * @@ -66,7 +74,7 @@ * ******************************************************************************/ -void +static void acpi_ns_build_external_path ( struct acpi_namespace_node *node, acpi_size size, @@ -126,7 +134,7 @@ acpi_ns_build_external_path ( * * FUNCTION: acpi_ns_get_external_pathname * - * PARAMETERS: Node - NS node whose pathname is needed + * PARAMETERS: Node - Namespace node whose pathname is needed * * RETURN: Pointer to storage containing the fully qualified name of * the node, In external format (name segments separated by path diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c index 4e41e66db61..27258c1ca4f 100644 --- a/drivers/acpi/namespace/nsobject.c +++ b/drivers/acpi/namespace/nsobject.c @@ -60,6 +60,8 @@ * Type - Type of object, or ACPI_TYPE_ANY if not * known * + * RETURN: Status + * * DESCRIPTION: Record the given object as the value associated with the * name whose acpi_handle is passed. If Object is NULL * and Type is ACPI_TYPE_ANY, set the name as having no value. @@ -97,7 +99,8 @@ acpi_ns_attach_object ( if (!object && (ACPI_TYPE_ANY != type)) { /* Null object */ - ACPI_REPORT_ERROR (("ns_attach_object: Null object, but type not ACPI_TYPE_ANY\n")); + ACPI_REPORT_ERROR (( + "ns_attach_object: Null object, but type not ACPI_TYPE_ANY\n")); return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -112,7 +115,8 @@ acpi_ns_attach_object ( /* Check if this object is already attached */ if (node->object == object) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj %p already installed in name_obj %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Obj %p already installed in name_obj %p\n", object, node)); return_ACPI_STATUS (AE_OK); @@ -192,7 +196,7 @@ acpi_ns_attach_object ( * * FUNCTION: acpi_ns_detach_object * - * PARAMETERS: Node - An node whose object will be detached + * PARAMETERS: Node - A Namespace node whose object will be detached * * RETURN: None. * @@ -248,7 +252,7 @@ acpi_ns_detach_object ( * * FUNCTION: acpi_ns_get_attached_object * - * PARAMETERS: Node - Parent Node to be examined + * PARAMETERS: Node - Namespace node * * RETURN: Current value of the object field from the Node whose * handle is passed @@ -284,7 +288,7 @@ acpi_ns_get_attached_object ( * * FUNCTION: acpi_ns_get_secondary_object * - * PARAMETERS: Node - Parent Node to be examined + * PARAMETERS: Node - Namespace node * * RETURN: Current value of the object field from the Node whose * handle is passed. diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index 0e6dea23603..af8aaa9cc4f 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -49,15 +49,24 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nssearch") +/* Local prototypes */ + +static acpi_status +acpi_ns_search_parent_tree ( + u32 target_name, + struct acpi_namespace_node *node, + acpi_object_type type, + struct acpi_namespace_node **return_node); + /******************************************************************************* * * FUNCTION: acpi_ns_search_node * - * PARAMETERS: *target_name - Ascii ACPI name to search for - * *Node - Starting node where search will begin - * Type - Object type to match - * **return_node - Where the matched Named obj is returned + * PARAMETERS: target_name - Ascii ACPI name to search for + * Node - Starting node where search will begin + * Type - Object type to match + * return_node - Where the matched Named obj is returned * * RETURN: Status * @@ -163,10 +172,10 @@ acpi_ns_search_node ( * * FUNCTION: acpi_ns_search_parent_tree * - * PARAMETERS: *target_name - Ascii ACPI name to search for - * *Node - Starting node where search will begin - * Type - Object type to match - * **return_node - Where the matched Node is returned + * PARAMETERS: target_name - Ascii ACPI name to search for + * Node - Starting node where search will begin + * Type - Object type to match + * return_node - Where the matched Node is returned * * RETURN: Status * @@ -257,12 +266,12 @@ acpi_ns_search_parent_tree ( * * PARAMETERS: target_name - Ascii ACPI name to search for (4 chars) * walk_state - Current state of the walk - * *Node - Starting node where search will begin + * Node - Starting node where search will begin * interpreter_mode - Add names only in ACPI_MODE_LOAD_PASS_x. * Otherwise,search only. * Type - Object type to match * Flags - Flags describing the search restrictions - * **return_node - Where the Node is returned + * return_node - Where the Node is returned * * RETURN: Status * diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index 75da76cc0b1..c53b82e94ce 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -51,6 +51,18 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsutils") +/* Local prototypes */ + +static u8 +acpi_ns_valid_path_separator ( + char sep); + +#ifdef ACPI_OBSOLETE_FUNCTIONS +acpi_name +acpi_ns_find_parent_name ( + struct acpi_namespace_node *node_to_search); +#endif + /******************************************************************************* * @@ -59,7 +71,8 @@ * PARAMETERS: module_name - Caller's module name (for error output) * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) - * Message - Error message to use on failure + * internal_name - Name or path of the namespace node + * lookup_status - Exception code from NS lookup * * RETURN: None * @@ -121,6 +134,9 @@ acpi_ns_report_error ( * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) * Message - Error message to use on failure + * prefix_node - Prefix relative to the path + * Path - Path to the node + * method_status - Execution status * * RETURN: None * @@ -161,8 +177,8 @@ acpi_ns_report_method_error ( * * FUNCTION: acpi_ns_print_node_pathname * - * PARAMETERS: Node - Object - * Msg - Prefix message + * PARAMETERS: Node - Object + * Message - Prefix message * * DESCRIPTION: Print an object's full namespace pathname * Manages allocation/freeing of a pathname buffer @@ -172,7 +188,7 @@ acpi_ns_report_method_error ( void acpi_ns_print_node_pathname ( struct acpi_namespace_node *node, - char *msg) + char *message) { struct acpi_buffer buffer; acpi_status status; @@ -189,8 +205,8 @@ acpi_ns_print_node_pathname ( status = acpi_ns_handle_to_pathname (node, &buffer); if (ACPI_SUCCESS (status)) { - if (msg) { - acpi_os_printf ("%s ", msg); + if (message) { + acpi_os_printf ("%s ", message); } acpi_os_printf ("[%s] (Node %p)", (char *) buffer.pointer, node); @@ -224,7 +240,7 @@ acpi_ns_valid_root_prefix ( * * FUNCTION: acpi_ns_valid_path_separator * - * PARAMETERS: Sep - Character to be checked + * PARAMETERS: Sep - Character to be checked * * RETURN: TRUE if a valid path separator * @@ -232,7 +248,7 @@ acpi_ns_valid_root_prefix ( * ******************************************************************************/ -u8 +static u8 acpi_ns_valid_path_separator ( char sep) { @@ -245,10 +261,12 @@ acpi_ns_valid_path_separator ( * * FUNCTION: acpi_ns_get_type * - * PARAMETERS: Handle - Parent Node to be examined + * PARAMETERS: Node - Parent Node to be examined * * RETURN: Type field from Node whose handle is passed * + * DESCRIPTION: Return the type of a Namespace node + * ******************************************************************************/ acpi_object_type @@ -271,11 +289,13 @@ acpi_ns_get_type ( * * FUNCTION: acpi_ns_local * - * PARAMETERS: Type - A namespace object type + * PARAMETERS: Type - A namespace object type * * RETURN: LOCAL if names must be found locally in objects of the * passed type, 0 if enclosing scopes should be searched * + * DESCRIPTION: Returns scope rule for the given object type. + * ******************************************************************************/ u32 @@ -303,7 +323,7 @@ acpi_ns_local ( * PARAMETERS: Info - Info struct initialized with the * external name pointer. * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Calculate the length of the internal (AML) namestring * corresponding to the external (ASL) namestring. @@ -551,14 +571,16 @@ acpi_ns_internalize_name ( * * FUNCTION: acpi_ns_externalize_name * - * PARAMETERS: *internal_name - Internal representation of name - * **converted_name - Where to return the resulting - * external representation of name + * PARAMETERS: internal_name_length - Lenth of the internal name below + * internal_name - Internal representation of name + * converted_name_length - Where the length is returned + * converted_name - Where the resulting external name + * is returned * * RETURN: Status * * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30) - * to its external form (e.g. "\_PR_.CPU0") + * to its external (printable) form (e.g. "\_PR_.CPU0") * ******************************************************************************/ @@ -717,8 +739,9 @@ acpi_ns_externalize_name ( * * DESCRIPTION: Convert a namespace handle to a real Node * - * Note: Real integer handles allow for more verification - * and keep all pointers within this subsystem. + * Note: Real integer handles would allow for more verification + * and keep all pointers within this subsystem - however this introduces + * more (and perhaps unnecessary) overhead. * ******************************************************************************/ @@ -775,7 +798,7 @@ acpi_ns_convert_entry_to_handle ( return ((acpi_handle) node); -/* --------------------------------------------------- +/* Example future implementation --------------------- if (!Node) { @@ -801,12 +824,13 @@ acpi_ns_convert_entry_to_handle ( * * RETURN: none * - * DESCRIPTION: free memory allocated for table storage. + * DESCRIPTION: free memory allocated for namespace and ACPI table storage. * ******************************************************************************/ void -acpi_ns_terminate (void) +acpi_ns_terminate ( + void) { union acpi_operand_object *obj_desc; @@ -940,7 +964,6 @@ acpi_ns_get_node_by_path ( (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); cleanup: - /* Cleanup */ if (internal_path) { ACPI_MEM_FREE (internal_path); } @@ -948,55 +971,6 @@ cleanup: } -/******************************************************************************* - * - * FUNCTION: acpi_ns_find_parent_name - * - * PARAMETERS: *child_node - Named Obj whose name is to be found - * - * RETURN: The ACPI name - * - * DESCRIPTION: Search for the given obj in its parent scope and return the - * name segment, or "????" if the parent name can't be found - * (which "should not happen"). - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE -acpi_name -acpi_ns_find_parent_name ( - struct acpi_namespace_node *child_node) -{ - struct acpi_namespace_node *parent_node; - - - ACPI_FUNCTION_TRACE ("ns_find_parent_name"); - - - if (child_node) { - /* Valid entry. Get the parent Node */ - - parent_node = acpi_ns_get_parent_node (child_node); - if (parent_node) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, - "Parent of %p [%4.4s] is %p [%4.4s]\n", - child_node, acpi_ut_get_node_name (child_node), - parent_node, acpi_ut_get_node_name (parent_node))); - - if (parent_node->name.integer) { - return_VALUE ((acpi_name) parent_node->name.integer); - } - } - - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, - "Unable to find parent of %p (%4.4s)\n", - child_node, acpi_ut_get_node_name (child_node))); - } - - return_VALUE (ACPI_UNKNOWN_NAME); -} -#endif - - /******************************************************************************* * * FUNCTION: acpi_ns_get_parent_node @@ -1009,7 +983,6 @@ acpi_ns_find_parent_name ( * ******************************************************************************/ - struct acpi_namespace_node * acpi_ns_get_parent_node ( struct acpi_namespace_node *node) @@ -1030,7 +1003,6 @@ acpi_ns_get_parent_node ( node = node->peer; } - return (node->peer); } @@ -1049,7 +1021,6 @@ acpi_ns_get_parent_node ( * ******************************************************************************/ - struct acpi_namespace_node * acpi_ns_get_next_valid_node ( struct acpi_namespace_node *node) @@ -1067,3 +1038,53 @@ acpi_ns_get_next_valid_node ( } +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: acpi_ns_find_parent_name + * + * PARAMETERS: *child_node - Named Obj whose name is to be found + * + * RETURN: The ACPI name + * + * DESCRIPTION: Search for the given obj in its parent scope and return the + * name segment, or "????" if the parent name can't be found + * (which "should not happen"). + * + ******************************************************************************/ + +acpi_name +acpi_ns_find_parent_name ( + struct acpi_namespace_node *child_node) +{ + struct acpi_namespace_node *parent_node; + + + ACPI_FUNCTION_TRACE ("ns_find_parent_name"); + + + if (child_node) { + /* Valid entry. Get the parent Node */ + + parent_node = acpi_ns_get_parent_node (child_node); + if (parent_node) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Parent of %p [%4.4s] is %p [%4.4s]\n", + child_node, acpi_ut_get_node_name (child_node), + parent_node, acpi_ut_get_node_name (parent_node))); + + if (parent_node->name.integer) { + return_VALUE ((acpi_name) parent_node->name.integer); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Unable to find parent of %p (%4.4s)\n", + child_node, acpi_ut_get_node_name (child_node))); + } + + return_VALUE (ACPI_UNKNOWN_NAME); +} +#endif + + diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c index 4de2444df30..f9a7277dca6 100644 --- a/drivers/acpi/namespace/nswalk.c +++ b/drivers/acpi/namespace/nswalk.c @@ -56,7 +56,7 @@ * * PARAMETERS: Type - Type of node to be searched for * parent_node - Parent node whose children we are - * getting + * getting * child_node - Previous child that was found. * The NEXT child will be returned * diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index 1dc995586cb..12ea202257f 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -58,11 +58,11 @@ * FUNCTION: acpi_evaluate_object_typed * * PARAMETERS: Handle - Object handle (optional) - * *Pathname - Object pathname (optional) - * **external_params - List of parameters to pass to method, + * Pathname - Object pathname (optional) + * external_params - List of parameters to pass to method, * terminated by NULL. May be NULL * if no parameters are being passed. - * *return_buffer - Where to put method's return value (if + * return_buffer - Where to put method's return value (if * any). If NULL, no value is returned. * return_type - Expected type of return object * @@ -73,6 +73,7 @@ * be valid (non-null) * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_evaluate_object_typed ( @@ -307,7 +308,8 @@ acpi_evaluate_object ( if (ACPI_SUCCESS (status)) { /* Validate/Allocate/Clear caller buffer */ - status = acpi_ut_initialize_buffer (return_buffer, buffer_space_needed); + status = acpi_ut_initialize_buffer (return_buffer, + buffer_space_needed); if (ACPI_FAILURE (status)) { /* * Caller's buffer is too small or a new one can't be allocated @@ -423,7 +425,8 @@ acpi_walk_namespace ( return_ACPI_STATUS (status); } - status = acpi_ns_walk_namespace (type, start_object, max_depth, ACPI_NS_WALK_UNLOCK, + status = acpi_ns_walk_namespace (type, start_object, max_depth, + ACPI_NS_WALK_UNLOCK, user_function, context, return_value); (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); @@ -525,7 +528,8 @@ acpi_ns_get_device_callback ( } } - status = info->user_function (obj_handle, nesting_level, info->context, return_value); + status = info->user_function (obj_handle, nesting_level, info->context, + return_value); return (status); } diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c index f2405efd1b9..8d097914c49 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/namespace/nsxfname.c @@ -57,9 +57,9 @@ * FUNCTION: acpi_get_handle * * PARAMETERS: Parent - Object to search under (search scope). - * path_name - Pointer to an asciiz string containing the - * name - * ret_handle - Where the return handle is placed + * Pathname - Pointer to an asciiz string containing the + * name + * ret_handle - Where the return handle is returned * * RETURN: Status * @@ -220,7 +220,7 @@ EXPORT_SYMBOL(acpi_get_name); * FUNCTION: acpi_get_object_info * * PARAMETERS: Handle - Object Handle - * Info - Where the info is returned + * Buffer - Where the info is returned * * RETURN: Status * diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c index 19acf32674b..363e1f6cfb1 100644 --- a/drivers/acpi/namespace/nsxfobj.c +++ b/drivers/acpi/namespace/nsxfobj.c @@ -56,7 +56,7 @@ * FUNCTION: acpi_get_type * * PARAMETERS: Handle - Handle of object whose type is desired - * *ret_type - Where the type will be placed + * ret_type - Where the type will be placed * * RETURN: Status * @@ -258,5 +258,5 @@ unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (status); } -EXPORT_SYMBOL(acpi_get_next_object); +EXPORT_SYMBOL(acpi_get_next_object); diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c index b5d98895f6a..b7ac68cc9e1 100644 --- a/drivers/acpi/parser/psargs.c +++ b/drivers/acpi/parser/psargs.c @@ -50,6 +50,16 @@ #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME ("psargs") +/* Local prototypes */ + +static u32 +acpi_ps_get_next_package_length ( + struct acpi_parse_state *parser_state); + +static union acpi_parse_object * +acpi_ps_get_next_field ( + struct acpi_parse_state *parser_state); + /******************************************************************************* * @@ -64,7 +74,7 @@ * ******************************************************************************/ -u32 +static u32 acpi_ps_get_next_package_length ( struct acpi_parse_state *parser_state) { @@ -78,7 +88,6 @@ acpi_ps_get_next_package_length ( encoded_length = (u32) ACPI_GET8 (parser_state->aml); parser_state->aml++; - switch (encoded_length >> 6) /* bits 6-7 contain encoding scheme */ { case 0: /* 1-byte encoding (bits 0-5) */ @@ -287,13 +296,14 @@ acpi_ps_get_next_namepath ( * parent tree, but don't open a new scope -- we just want to lookup the * object (MUST BE mode EXECUTE to perform upsearch) */ - status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, - ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, &node); + status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + NULL, &node); if (ACPI_SUCCESS (status) && method_call) { if (node->type == ACPI_TYPE_METHOD) { - /* - * This name is actually a control method invocation - */ + /* This name is actually a control method invocation */ + method_desc = acpi_ns_get_attached_object (node); ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p Desc %p Path=%p\n", @@ -360,7 +370,7 @@ acpi_ps_get_next_namepath ( /* * We got a NOT_FOUND during table load or we encountered * a cond_ref_of(x) where the target does not exist. - * -- either case is ok + * Either case is ok */ status = AE_OK; } @@ -486,12 +496,13 @@ acpi_ps_get_next_simple_arg ( * ******************************************************************************/ -union acpi_parse_object * +static union acpi_parse_object * acpi_ps_get_next_field ( struct acpi_parse_state *parser_state) { - u32 aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml, - parser_state->aml_start); + u32 aml_offset = (u32) + ACPI_PTR_DIFF (parser_state->aml, + parser_state->aml_start); union acpi_parse_object *field; u16 opcode; u32 name; @@ -500,7 +511,7 @@ acpi_ps_get_next_field ( ACPI_FUNCTION_TRACE ("ps_get_next_field"); - /* determine field type */ + /* Determine field type */ switch (ACPI_GET8 (parser_state->aml)) { default: @@ -521,7 +532,6 @@ acpi_ps_get_next_field ( break; } - /* Allocate a new field op */ field = acpi_ps_alloc_op (opcode); @@ -582,10 +592,10 @@ acpi_ps_get_next_field ( * * FUNCTION: acpi_ps_get_next_arg * - * PARAMETERS: parser_state - Current parser state object + * PARAMETERS: walk_state - Current state + * parser_state - Current parser state object * arg_type - The argument type (AML_*_ARG) - * arg_count - If the argument points to a control method - * the method's argument is returned here. + * return_arg - Where the next arg is returned * * RETURN: Status, and an op object containing the next argument. * @@ -619,7 +629,7 @@ acpi_ps_get_next_arg ( case ARGP_NAME: case ARGP_NAMESTRING: - /* constants, strings, and namestrings are all the same size */ + /* Constants, strings, and namestrings are all the same size */ arg = acpi_ps_alloc_op (AML_BYTE_OP); if (!arg) { @@ -654,7 +664,6 @@ acpi_ps_get_next_arg ( else { arg = field; } - prev = field; } @@ -677,8 +686,8 @@ acpi_ps_get_next_arg ( /* Fill in bytelist data */ - arg->common.value.size = (u32) ACPI_PTR_DIFF (parser_state->pkg_end, - parser_state->aml); + arg->common.value.size = (u32) + ACPI_PTR_DIFF (parser_state->pkg_end, parser_state->aml); arg->named.data = parser_state->aml; /* Skip to End of byte data */ @@ -706,7 +715,7 @@ acpi_ps_get_next_arg ( status = acpi_ps_get_next_namepath (walk_state, parser_state, arg, 0); } else { - /* single complex argument, nothing returned */ + /* Single complex argument, nothing returned */ walk_state->arg_count = 1; } @@ -716,7 +725,7 @@ acpi_ps_get_next_arg ( case ARGP_DATAOBJ: case ARGP_TERMARG: - /* single complex argument, nothing returned */ + /* Single complex argument, nothing returned */ walk_state->arg_count = 1; break; @@ -727,7 +736,7 @@ acpi_ps_get_next_arg ( case ARGP_OBJLIST: if (parser_state->aml < parser_state->pkg_end) { - /* non-empty list of variable arguments, nothing returned */ + /* Non-empty list of variable arguments, nothing returned */ walk_state->arg_count = ACPI_VAR_ARGS; } diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c index 03e33fedc11..5744673568c 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/parser/psopcode.c @@ -44,6 +44,7 @@ #include #include +#include #include @@ -51,23 +52,6 @@ ACPI_MODULE_NAME ("psopcode") -#define _UNK 0x6B -/* - * Reserved ASCII characters. Do not use any of these for - * internal opcodes, since they are used to differentiate - * name strings from AML opcodes - */ -#define _ASC 0x6C -#define _NAM 0x6C -#define _PFX 0x6D -#define _UNKNOWN_OPCODE 0x02 /* An example unknown opcode */ - -#define MAX_EXTENDED_OPCODE 0x88 -#define NUM_EXTENDED_OPCODE (MAX_EXTENDED_OPCODE + 1) -#define MAX_INTERNAL_OPCODE -#define NUM_INTERNAL_OPCODE (MAX_INTERNAL_OPCODE + 1) - - /******************************************************************************* * * NAME: acpi_gbl_aml_op_info @@ -79,274 +63,9 @@ * ******************************************************************************/ - -/* - * All AML opcodes and the parse-time arguments for each. Used by the AML parser Each list is compressed - * into a 32-bit number and stored in the master opcode table at the end of this file. - */ - - -#define ARGP_ACCESSFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_ACQUIRE_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_WORDDATA) -#define ARGP_ADD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_ALIAS_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_NAME) -#define ARGP_ARG0 ARG_NONE -#define ARGP_ARG1 ARG_NONE -#define ARGP_ARG2 ARG_NONE -#define ARGP_ARG3 ARG_NONE -#define ARGP_ARG4 ARG_NONE -#define ARGP_ARG5 ARG_NONE -#define ARGP_ARG6 ARG_NONE -#define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST) -#define ARGP_BIT_AND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BIT_NAND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BIT_NOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BIT_NOT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BIT_OR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BIT_XOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_BREAK_OP ARG_NONE -#define ARGP_BREAK_POINT_OP ARG_NONE -#define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST) -#define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA) -#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME) -#define ARGP_CONTINUE_OP ARG_NONE -#define ARGP_COPY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SIMPLENAME) -#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_CREATE_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_CREATE_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) -#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_DEBUG_OP ARG_NONE -#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG) -#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) -#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET) -#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA) -#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST) -#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME) -#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG) -#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST) -#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_FROM_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) -#define ARGP_INCREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST) -#define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG) -#define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME) -#define ARGP_LOAD_TABLE_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_LOCAL0 ARG_NONE -#define ARGP_LOCAL1 ARG_NONE -#define ARGP_LOCAL2 ARG_NONE -#define ARGP_LOCAL3 ARG_NONE -#define ARGP_LOCAL4 ARG_NONE -#define ARGP_LOCAL5 ARG_NONE -#define ARGP_LOCAL6 ARG_NONE -#define ARGP_LOCAL7 ARG_NONE -#define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST) -#define ARGP_METHODCALL_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_MID_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_MOD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_MULTIPLY_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_MUTEX_OP ARGP_LIST2 (ARGP_NAME, ARGP_BYTEDATA) -#define ARGP_NAME_OP ARGP_LIST2 (ARGP_NAME, ARGP_DATAOBJ) -#define ARGP_NAMEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_NOOP_OP ARG_NONE -#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) -#define ARGP_ONE_OP ARG_NONE -#define ARGP_ONES_OP ARG_NONE -#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) -#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST) -#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST) -#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA) -#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) -#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG) -#define ARGP_REVISION_OP ARG_NONE -#define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST) -#define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG) -#define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG) -#define ARGP_STATICSTRING_OP ARGP_LIST1 (ARGP_NAMESTRING) -#define ARGP_STORE_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SUPERNAME) -#define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST) -#define ARGP_SUBTRACT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) -#define ARGP_TIMER_OP ARG_NONE -#define ARGP_TO_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TO_BUFFER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TO_DEC_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST) -#define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) -#define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) -#define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA) -#define ARGP_ZERO_OP ARG_NONE - - -/* - * All AML opcodes and the runtime arguments for each. Used by the AML interpreter Each list is compressed - * into a 32-bit number and stored in the master opcode table at the end of this file. - * - * (Used by prep_operands procedure and the ASL Compiler) - */ - - -#define ARGI_ACCESSFIELD_OP ARGI_INVALID_OPCODE -#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_INTEGER) -#define ARGI_ADD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_ALIAS_OP ARGI_INVALID_OPCODE -#define ARGI_ARG0 ARG_NONE -#define ARGI_ARG1 ARG_NONE -#define ARGI_ARG2 ARG_NONE -#define ARGI_ARG3 ARG_NONE -#define ARGI_ARG4 ARG_NONE -#define ARGI_ARG5 ARG_NONE -#define ARGI_ARG6 ARG_NONE -#define ARGI_BANK_FIELD_OP ARGI_INVALID_OPCODE -#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_BREAK_OP ARG_NONE -#define ARGI_BREAK_POINT_OP ARG_NONE -#define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_BYTE_OP ARGI_INVALID_OPCODE -#define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE -#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF) -#define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF) -#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF) -#define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE -#define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET) -#define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_CREATE_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_CREATE_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) -#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) -#define ARGI_DEBUG_OP ARG_NONE -#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF) -#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING) -#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE -#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF) -#define ARGI_DWORD_OP ARGI_INVALID_OPCODE -#define ARGI_ELSE_OP ARGI_INVALID_OPCODE -#define ARGI_EVENT_OP ARGI_INVALID_OPCODE -#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_FIELD_OP ARGI_INVALID_OPCODE -#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_IF_OP ARGI_INVALID_OPCODE -#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF) -#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE -#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) -#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) -#define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE -#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) -#define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE -#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE -#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_FIELD,ARGI_TARGETREF) -#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE) -#define ARGI_LOCAL0 ARG_NONE -#define ARGI_LOCAL1 ARG_NONE -#define ARGI_LOCAL2 ARG_NONE -#define ARGI_LOCAL3 ARG_NONE -#define ARGI_LOCAL4 ARG_NONE -#define ARGI_LOCAL5 ARG_NONE -#define ARGI_LOCAL6 ARG_NONE -#define ARGI_LOCAL7 ARG_NONE -#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_COMPUTEDATA, ARGI_INTEGER,ARGI_COMPUTEDATA,ARGI_INTEGER) -#define ARGI_METHOD_OP ARGI_INVALID_OPCODE -#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE -#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_MOD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_MUTEX_OP ARGI_INVALID_OPCODE -#define ARGI_NAME_OP ARGI_INVALID_OPCODE -#define ARGI_NAMEDFIELD_OP ARGI_INVALID_OPCODE -#define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE -#define ARGI_NOOP_OP ARG_NONE -#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER) -#define ARGI_ONE_OP ARG_NONE -#define ARGI_ONES_OP ARG_NONE -#define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE -#define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE -#define ARGI_QWORD_OP ARGI_INVALID_OPCODE -#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_OBJECT_REF) -#define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) -#define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX) -#define ARGI_RESERVEDFIELD_OP ARGI_INVALID_OPCODE -#define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT) -#define ARGI_RETURN_OP ARGI_INVALID_OPCODE -#define ARGI_REVISION_OP ARG_NONE -#define ARGI_SCOPE_OP ARGI_INVALID_OPCODE -#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT) -#define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT) -#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_STALL_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_STATICSTRING_OP ARGI_INVALID_OPCODE -#define ARGI_STORE_OP ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_TARGETREF) -#define ARGI_STRING_OP ARGI_INVALID_OPCODE -#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE -#define ARGI_TIMER_OP ARG_NONE -#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) -#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET) -#define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE) -#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) -#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) -#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER) -#define ARGI_WHILE_OP ARGI_INVALID_OPCODE -#define ARGI_WORD_OP ARGI_INVALID_OPCODE -#define ARGI_ZERO_OP ARG_NONE - - /* * Summary of opcode types/flags - */ - -/****************************************************************************** + * Opcodes that have associated namespace objects (AML_NSOBJECT flag) @@ -460,14 +179,13 @@ AML_CREATE_DWORD_FIELD_OP AML_CREATE_QWORD_FIELD_OP -******************************************************************************/ + ******************************************************************************/ /* - * Master Opcode information table. A summary of everything we know about each opcode, all in one place. + * Master Opcode information table. A summary of everything we know about each + * opcode, all in one place. */ - - const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /*! [Begin] no source code translation */ @@ -693,8 +411,7 @@ static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = * * PARAMETERS: Opcode - The AML opcode * - * RETURN: A pointer to the info about the opcode. NULL if the opcode was - * not found in the table. + * RETURN: A pointer to the info about the opcode. * * DESCRIPTION: Find AML opcode description based on the opcode. * NOTE: This procedure must ALWAYS return a valid pointer! @@ -731,7 +448,8 @@ acpi_ps_get_opcode_info ( default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown AML opcode [%4.4X]\n", opcode)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown AML opcode [%4.4X]\n", opcode)); break; } diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c index e79edb53cb3..bbfdc1a58c2 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/parser/psparse.c @@ -64,6 +64,23 @@ static u32 acpi_gbl_depth = 0; +/* Local prototypes */ + +static void +acpi_ps_complete_this_op ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +static acpi_status +acpi_ps_next_parse_state ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + acpi_status callback_status); + +static acpi_status +acpi_ps_parse_loop ( + struct acpi_walk_state *walk_state); + /******************************************************************************* * @@ -100,7 +117,7 @@ acpi_ps_get_opcode_size ( * * PARAMETERS: parser_state - A parser state object * - * RETURN: Status + * RETURN: Next AML opcode * * DESCRIPTION: Get next AML opcode (without incrementing AML pointer) * @@ -117,7 +134,6 @@ acpi_ps_peek_opcode ( aml = parser_state->aml; opcode = (u16) ACPI_GET8 (aml); - if (opcode == AML_EXTOP) { /* Extended opcode */ @@ -142,7 +158,7 @@ acpi_ps_peek_opcode ( * ******************************************************************************/ -void +static void acpi_ps_complete_this_op ( struct acpi_walk_state *walk_state, union acpi_parse_object *op) @@ -272,7 +288,6 @@ acpi_ps_complete_this_op ( next = NULL; } } - prev = next; } } @@ -280,7 +295,7 @@ acpi_ps_complete_this_op ( cleanup: - /* Now we can actually delete the subtree rooted at op */ + /* Now we can actually delete the subtree rooted at Op */ acpi_ps_delete_parse_tree (op); return_VOID; @@ -291,7 +306,9 @@ cleanup: * * FUNCTION: acpi_ps_next_parse_state * - * PARAMETERS: parser_state - Current parser state object + * PARAMETERS: walk_state - Current state + * Op - Current parse op + * callback_status - Status from previous operation * * RETURN: Status * @@ -300,7 +317,7 @@ cleanup: * ******************************************************************************/ -acpi_status +static acpi_status acpi_ps_next_parse_state ( struct acpi_walk_state *walk_state, union acpi_parse_object *op, @@ -382,9 +399,8 @@ acpi_ps_next_parse_state ( case AE_CTRL_TRANSFER: - /* - * A method call (invocation) -- transfer control - */ + /* A method call (invocation) -- transfer control */ + status = AE_CTRL_TRANSFER; walk_state->prev_op = op; walk_state->method_call_op = op; @@ -397,6 +413,7 @@ acpi_ps_next_parse_state ( default: + status = callback_status; if ((callback_status & AE_CODE_MASK) == AE_CODE_CONTROL) { status = AE_OK; @@ -412,7 +429,7 @@ acpi_ps_next_parse_state ( * * FUNCTION: acpi_ps_parse_loop * - * PARAMETERS: parser_state - Current parser state object + * PARAMETERS: walk_state - Current state * * RETURN: Status * @@ -421,7 +438,7 @@ acpi_ps_next_parse_state ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ps_parse_loop ( struct acpi_walk_state *walk_state) { @@ -443,6 +460,7 @@ acpi_ps_parse_loop ( walk_state->arg_types = 0; #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) + if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { /* We are restarting a preempted control method */ @@ -471,7 +489,8 @@ acpi_ps_parse_loop ( acpi_format_exception (status))); } - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "get_predicate Failed, %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "get_predicate Failed, %s\n", acpi_format_exception (status))); return_ACPI_STATUS (status); } @@ -492,16 +511,15 @@ acpi_ps_parse_loop ( } #endif - /* - * Iterative parsing loop, while there is more aml to process: - */ + /* Iterative parsing loop, while there is more AML to process: */ + while ((parser_state->aml < parser_state->aml_end) || (op)) { aml_op_start = parser_state->aml; if (!op) { /* Get the next opcode from the AML stream */ walk_state->aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml, - parser_state->aml_start); + parser_state->aml_start); walk_state->opcode = acpi_ps_peek_opcode (parser_state); /* @@ -578,8 +596,10 @@ acpi_ps_parse_loop ( INCREMENT_ARG_LIST (walk_state->arg_types); } - /* Make sure that we found a NAME and didn't run out of arguments */ - + /* + * Make sure that we found a NAME and didn't run out of + * arguments + */ if (!GET_CURRENT_ARG_TYPE (walk_state->arg_types)) { status = AE_AML_NO_OPERAND; goto close_this_op; @@ -597,12 +617,13 @@ acpi_ps_parse_loop ( status = walk_state->descending_callback (walk_state, &op); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "During name lookup/catalog, %s\n", - acpi_format_exception (status))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "During name lookup/catalog, %s\n", + acpi_format_exception (status))); goto close_this_op; } - if (op == NULL) { + if (!op) { continue; } @@ -659,7 +680,7 @@ acpi_ps_parse_loop ( if ((walk_state->descending_callback != NULL)) { /* - * Find the object. This will either insert the object into + * Find the object. This will either insert the object into * the namespace or simply look it up */ walk_state->op = op; @@ -688,11 +709,15 @@ acpi_ps_parse_loop ( } - /* Start arg_count at zero because we don't know if there are any args yet */ - + /* + * Start arg_count at zero because we don't know if there are + * any args yet + */ walk_state->arg_count = 0; - if (walk_state->arg_types) /* Are there any arguments that must be processed? */ { + /* Are there any arguments that must be processed? */ + + if (walk_state->arg_types) { /* Get arguments */ switch (op->common.aml_opcode) { @@ -720,14 +745,18 @@ acpi_ps_parse_loop ( default: - /* Op is not a constant or string, append each argument to the Op */ - + /* + * Op is not a constant or string, append each argument + * to the Op + */ while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) && !walk_state->arg_count) { - walk_state->aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml, - parser_state->aml_start); + walk_state->aml_offset = (u32) + ACPI_PTR_DIFF (parser_state->aml, parser_state->aml_start); + status = acpi_ps_get_next_arg (walk_state, parser_state, - GET_CURRENT_ARG_TYPE (walk_state->arg_types), &arg); + GET_CURRENT_ARG_TYPE (walk_state->arg_types), + &arg); if (ACPI_FAILURE (status)) { goto close_this_op; } @@ -752,7 +781,8 @@ acpi_ps_parse_loop ( * Save the length and address of the body */ op->named.data = parser_state->aml; - op->named.length = (u32) (parser_state->pkg_end - parser_state->aml); + op->named.length = (u32) (parser_state->pkg_end - + parser_state->aml); /* Skip body of method */ @@ -773,7 +803,8 @@ acpi_ps_parse_loop ( * to parse them correctly. */ op->named.data = aml_op_start; - op->named.length = (u32) (parser_state->pkg_end - aml_op_start); + op->named.length = (u32) (parser_state->pkg_end - + aml_op_start); /* Skip body */ @@ -785,7 +816,8 @@ acpi_ps_parse_loop ( case AML_WHILE_OP: if (walk_state->control_state) { - walk_state->control_state->control.package_end = parser_state->pkg_end; + walk_state->control_state->control.package_end = + parser_state->pkg_end; } break; @@ -801,8 +833,10 @@ acpi_ps_parse_loop ( /* Check for arguments that need to be processed */ if (walk_state->arg_count) { - /* There are arguments (complex ones), push Op and prepare for argument */ - + /* + * There are arguments (complex ones), push Op and + * prepare for argument + */ status = acpi_ps_push_scope (parser_state, op, walk_state->arg_types, walk_state->arg_count); if (ACPI_FAILURE (status)) { @@ -812,8 +846,10 @@ acpi_ps_parse_loop ( continue; } - /* All arguments have been processed -- Op is complete, prepare for next */ - + /* + * All arguments have been processed -- Op is complete, + * prepare for next + */ walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); if (walk_state->op_info->flags & AML_NAMED) { if (acpi_gbl_depth) { @@ -880,9 +916,8 @@ close_this_op: case AE_CTRL_TRANSFER: - /* - * We are about to transfer to a called method. - */ + /* We are about to transfer to a called method. */ + walk_state->prev_op = op; walk_state->prev_arg_types = walk_state->arg_types; return_ACPI_STATUS (status); @@ -1051,10 +1086,7 @@ close_this_op: * * FUNCTION: acpi_ps_parse_aml * - * PARAMETERS: start_scope - The starting point of the parse. Becomes the - * root of the parsed op tree. - * Aml - Pointer to the raw AML code to parse - * aml_size - Length of the AML to parse + * PARAMETERS: walk_state - Current state * * * RETURN: Status @@ -1076,8 +1108,10 @@ acpi_ps_parse_aml ( ACPI_FUNCTION_TRACE ("ps_parse_aml"); - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Entered with walk_state=%p Aml=%p size=%X\n", - walk_state, walk_state->parser_state.aml, walk_state->parser_state.aml_size)); + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Entered with walk_state=%p Aml=%p size=%X\n", + walk_state, walk_state->parser_state.aml, + walk_state->parser_state.aml_size)); /* Create and initialize a new thread state */ @@ -1142,9 +1176,10 @@ acpi_ps_parse_aml ( if ((status == AE_ALREADY_EXISTS) && (!walk_state->method_desc->method.semaphore)) { /* - * This method is marked not_serialized, but it tried to create a named - * object, causing the second thread entrance to fail. We will workaround - * this by marking the method permanently as Serialized. + * This method is marked not_serialized, but it tried to create + * a named object, causing the second thread entrance to fail. + * We will workaround this by marking the method permanently + * as Serialized. */ walk_state->method_desc->method.method_flags |= AML_METHOD_SERIALIZED; walk_state->method_desc->method.concurrency = 1; @@ -1187,7 +1222,8 @@ acpi_ps_parse_aml ( previous_walk_state = walk_state; - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "return_value=%p, implicit_value=%p State=%p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "return_value=%p, implicit_value=%p State=%p\n", walk_state->return_desc, walk_state->implicit_return_obj, walk_state)); /* Check if we have restarted a preempted walk */ @@ -1231,12 +1267,14 @@ acpi_ps_parse_aml ( */ else if (previous_walk_state->caller_return_desc) { if (previous_walk_state->implicit_return_obj) { - *(previous_walk_state->caller_return_desc) = previous_walk_state->implicit_return_obj; + *(previous_walk_state->caller_return_desc) = + previous_walk_state->implicit_return_obj; } else { /* NULL if no return value */ - *(previous_walk_state->caller_return_desc) = previous_walk_state->return_desc; + *(previous_walk_state->caller_return_desc) = + previous_walk_state->return_desc; } } else { diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c index dcbed49608b..8dcd1b1e713 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/parser/psscope.c @@ -65,6 +65,7 @@ union acpi_parse_object * acpi_ps_get_parent_scope ( struct acpi_parse_state *parser_state) { + return (parser_state->scope->parse_scope.op); } @@ -87,8 +88,10 @@ u8 acpi_ps_has_completed_scope ( struct acpi_parse_state *parser_state) { - return ((u8) ((parser_state->aml >= parser_state->scope->parse_scope.arg_end || - !parser_state->scope->parse_scope.arg_count))); + + return ((u8) + ((parser_state->aml >= parser_state->scope->parse_scope.arg_end || + !parser_state->scope->parse_scope.arg_count))); } @@ -167,23 +170,23 @@ acpi_ps_push_scope ( return_ACPI_STATUS (AE_NO_MEMORY); } - scope->common.data_type = ACPI_DESC_TYPE_STATE_PSCOPE; - scope->parse_scope.op = op; - scope->parse_scope.arg_list = remaining_args; - scope->parse_scope.arg_count = arg_count; - scope->parse_scope.pkg_end = parser_state->pkg_end; + scope->common.data_type = ACPI_DESC_TYPE_STATE_PSCOPE; + scope->parse_scope.op = op; + scope->parse_scope.arg_list = remaining_args; + scope->parse_scope.arg_count = arg_count; + scope->parse_scope.pkg_end = parser_state->pkg_end; /* Push onto scope stack */ acpi_ut_push_generic_state (&parser_state->scope, scope); if (arg_count == ACPI_VAR_ARGS) { - /* multiple arguments */ + /* Multiple arguments */ scope->parse_scope.arg_end = parser_state->pkg_end; } else { - /* single argument */ + /* Single argument */ scope->parse_scope.arg_end = ACPI_TO_POINTER (ACPI_MAX_PTR); } @@ -221,18 +224,17 @@ acpi_ps_pop_scope ( ACPI_FUNCTION_TRACE ("ps_pop_scope"); - /* - * Only pop the scope if there is in fact a next scope - */ + /* Only pop the scope if there is in fact a next scope */ + if (scope->common.next) { scope = acpi_ut_pop_generic_state (&parser_state->scope); /* return to parsing previous op */ - *op = scope->parse_scope.op; - *arg_list = scope->parse_scope.arg_list; - *arg_count = scope->parse_scope.arg_count; - parser_state->pkg_end = scope->parse_scope.pkg_end; + *op = scope->parse_scope.op; + *arg_list = scope->parse_scope.arg_list; + *arg_count = scope->parse_scope.arg_count; + parser_state->pkg_end = scope->parse_scope.pkg_end; /* All done with this scope state structure */ @@ -241,12 +243,13 @@ acpi_ps_pop_scope ( else { /* empty parse stack, prepare to fetch next opcode */ - *op = NULL; - *arg_list = 0; - *arg_count = 0; + *op = NULL; + *arg_list = 0; + *arg_count = 0; } - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped Op %p Args %X\n", *op, *arg_count)); + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Popped Op %p Args %X\n", *op, *arg_count)); return_VOID; } @@ -257,7 +260,7 @@ acpi_ps_pop_scope ( * * PARAMETERS: parser_state - Current parser state object * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Destroy available list, remaining stack levels, and return * root scope diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c index 2140bd1ac10..d5aafe73fca 100644 --- a/drivers/acpi/parser/pstree.c +++ b/drivers/acpi/parser/pstree.c @@ -49,6 +49,14 @@ #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME ("pstree") +/* Local prototypes */ + +#ifdef ACPI_OBSOLETE_FUNCTIONS +union acpi_parse_object * +acpi_ps_get_child ( + union acpi_parse_object *op); +#endif + /******************************************************************************* * @@ -57,7 +65,7 @@ * PARAMETERS: Op - Get an argument for this op * Argn - Nth argument to get * - * RETURN: The argument (as an Op object). NULL if argument does not exist + * RETURN: The argument (as an Op object). NULL if argument does not exist * * DESCRIPTION: Get the specified op's argument. * @@ -152,7 +160,6 @@ acpi_ps_append_arg ( return; } - /* Append the argument to the linked argument list */ if (op->common.value.arg) { @@ -164,14 +171,12 @@ acpi_ps_append_arg ( } prev_arg->common.next = arg; } - else { /* No argument list, this will be the first argument */ op->common.value.arg = arg; } - /* Set the parent in this arg and any args linked after it */ while (arg) { @@ -182,73 +187,6 @@ acpi_ps_append_arg ( #ifdef ACPI_FUTURE_USAGE - -/******************************************************************************* - * - * FUNCTION: acpi_ps_get_child - * - * PARAMETERS: Op - Get the child of this Op - * - * RETURN: Child Op, Null if none is found. - * - * DESCRIPTION: Get op's children or NULL if none - * - ******************************************************************************/ -union acpi_parse_object * -acpi_ps_get_child ( - union acpi_parse_object *op) -{ - union acpi_parse_object *child = NULL; - - - ACPI_FUNCTION_ENTRY (); - - - switch (op->common.aml_opcode) { - case AML_SCOPE_OP: - case AML_ELSE_OP: - case AML_DEVICE_OP: - case AML_THERMAL_ZONE_OP: - case AML_INT_METHODCALL_OP: - - child = acpi_ps_get_arg (op, 0); - break; - - - case AML_BUFFER_OP: - case AML_PACKAGE_OP: - case AML_METHOD_OP: - case AML_IF_OP: - case AML_WHILE_OP: - case AML_FIELD_OP: - - child = acpi_ps_get_arg (op, 1); - break; - - - case AML_POWER_RES_OP: - case AML_INDEX_FIELD_OP: - - child = acpi_ps_get_arg (op, 2); - break; - - - case AML_PROCESSOR_OP: - case AML_BANK_FIELD_OP: - - child = acpi_ps_get_arg (op, 3); - break; - - - default: - /* All others have no children */ - break; - } - - return (child); -} - - /******************************************************************************* * * FUNCTION: acpi_ps_get_depth_next @@ -280,21 +218,21 @@ acpi_ps_get_depth_next ( return (NULL); } - /* look for an argument or child */ + /* Look for an argument or child */ next = acpi_ps_get_arg (op, 0); if (next) { return (next); } - /* look for a sibling */ + /* Look for a sibling */ next = op->common.next; if (next) { return (next); } - /* look for a sibling of parent */ + /* Look for a sibling of parent */ parent = op->common.parent; @@ -305,13 +243,13 @@ acpi_ps_get_depth_next ( } if (arg == origin) { - /* reached parent of origin, end search */ + /* Reached parent of origin, end search */ return (NULL); } if (parent->common.next) { - /* found sibling of parent */ + /* Found sibling of parent */ return (parent->common.next); } @@ -323,5 +261,74 @@ acpi_ps_get_depth_next ( return (next); } + +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: acpi_ps_get_child + * + * PARAMETERS: Op - Get the child of this Op + * + * RETURN: Child Op, Null if none is found. + * + * DESCRIPTION: Get op's children or NULL if none + * + ******************************************************************************/ + +union acpi_parse_object * +acpi_ps_get_child ( + union acpi_parse_object *op) +{ + union acpi_parse_object *child = NULL; + + + ACPI_FUNCTION_ENTRY (); + + + switch (op->common.aml_opcode) { + case AML_SCOPE_OP: + case AML_ELSE_OP: + case AML_DEVICE_OP: + case AML_THERMAL_ZONE_OP: + case AML_INT_METHODCALL_OP: + + child = acpi_ps_get_arg (op, 0); + break; + + + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_METHOD_OP: + case AML_IF_OP: + case AML_WHILE_OP: + case AML_FIELD_OP: + + child = acpi_ps_get_arg (op, 1); + break; + + + case AML_POWER_RES_OP: + case AML_INDEX_FIELD_OP: + + child = acpi_ps_get_arg (op, 2); + break; + + + case AML_PROCESSOR_OP: + case AML_BANK_FIELD_OP: + + child = acpi_ps_get_arg (op, 3); + break; + + + default: + /* All others have no children */ + break; + } + + return (child); +} +#endif + #endif /* ACPI_FUTURE_USAGE */ diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c index b3597cb19f8..a10f88715d4 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/parser/psutils.c @@ -45,7 +45,6 @@ #include #include #include -#include #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME ("psutils") @@ -57,7 +56,7 @@ * * PARAMETERS: None * - * RETURN: scope_op + * RETURN: A new Scope object, null on failure * * DESCRIPTION: Create a Scope and associated namepath op with the root name * @@ -75,7 +74,6 @@ acpi_ps_create_scope_op ( return (NULL); } - scope_op->named.name = ACPI_ROOT_NAME; return (scope_op); } @@ -88,10 +86,9 @@ acpi_ps_create_scope_op ( * PARAMETERS: Op - A newly allocated Op object * Opcode - Opcode to store in the Op * - * RETURN: Status + * RETURN: None * - * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on - * opcode + * DESCRIPTION: Initialize a parse (Op) object * ******************************************************************************/ @@ -107,7 +104,8 @@ acpi_ps_init_op ( op->common.aml_opcode = opcode; ACPI_DISASM_ONLY_MEMBERS (ACPI_STRNCPY (op->common.aml_op_name, - (acpi_ps_get_opcode_info (opcode))->name, sizeof (op->common.aml_op_name))); + (acpi_ps_get_opcode_info (opcode))->name, + sizeof (op->common.aml_op_name))); } @@ -117,7 +115,7 @@ acpi_ps_init_op ( * * PARAMETERS: Opcode - Opcode that will be stored in the new Op * - * RETURN: Pointer to the new Op. + * RETURN: Pointer to the new Op, null on failure * * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on * opcode. A cache of opcodes is available for the pure @@ -275,7 +273,6 @@ acpi_ps_get_name ( union acpi_parse_object *op) { - /* The "generic" object has no name associated with it */ if (op->common.flags & ACPI_PARSEOP_GENERIC) { diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c index 110d2ce917b..9d20cb2ceb5 100644 --- a/drivers/acpi/parser/pswalk.c +++ b/drivers/acpi/parser/pswalk.c @@ -90,17 +90,15 @@ acpi_ps_delete_parse_tree ( } } - /* - * No more children, this Op is complete. - */ + /* No more children, this Op is complete. */ + next = op->common.next; parent = op->common.parent; acpi_ps_free_op (op); - /* - * If we are back to the starting point, the walk is complete. - */ + /* If we are back to the starting point, the walk is complete. */ + if (op == subtree_root) { return_VOID; } @@ -111,5 +109,6 @@ acpi_ps_delete_parse_tree ( op = parent; } } + return_VOID; } diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c index b318ad24726..dba893648e8 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/parser/psxface.c @@ -57,13 +57,16 @@ * * FUNCTION: acpi_psx_execute * - * PARAMETERS: Info->Node - A method object containing both the AML - * address and length. - * **Params - List of parameters to pass to method, + * PARAMETERS: Info - Method info block, contains: + * Node - Method Node to execute + * Parameters - List of parameters to pass to the method, * terminated by NULL. Params itself may be * NULL if no parameters are being passed. - * **return_obj_desc - Return object from execution of the - * method. + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * parameter_type - Type of Parameter list + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. * * RETURN: Status * @@ -196,9 +199,8 @@ acpi_psx_execute ( goto cleanup3; } - /* - * The walk of the parse tree is where we actually execute the method - */ + /* The walk of the parse tree is where we actually execute the method */ + status = acpi_ps_parse_aml (walk_state); goto cleanup2; /* Walk state already deleted */ @@ -217,7 +219,8 @@ cleanup1: for (i = 0; info->parameters[i]; i++) { /* Ignore errors, just do them all */ - (void) acpi_ut_update_object_reference (info->parameters[i], REF_DECREMENT); + (void) acpi_ut_update_object_reference ( + info->parameters[i], REF_DECREMENT); } } diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c index 4788c079735..55d264771c4 100644 --- a/drivers/acpi/resources/rsaddr.c +++ b/drivers/acpi/resources/rsaddr.c @@ -77,21 +77,21 @@ acpi_rs_address16_resource ( u8 **output_buffer, acpi_size *structure_size) { - u8 *buffer = byte_stream_buffer; - struct acpi_resource *output_struct = (void *) *output_buffer; - u8 *temp_ptr; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address16); u32 index; u16 temp16; u8 temp8; + u8 *temp_ptr; + u8 *buffer = byte_stream_buffer; + struct acpi_resource *output_struct = (void *) *output_buffer; + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_address16); ACPI_FUNCTION_TRACE ("rs_address16_resource"); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -104,9 +104,8 @@ acpi_rs_address16_resource ( *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_ADDRESS16; - /* - * Get the Resource Type (Byte3) - */ + /* Get the Resource Type (Byte3) */ + buffer += 2; temp8 = *buffer; @@ -118,9 +117,8 @@ acpi_rs_address16_resource ( output_struct->data.address16.resource_type = temp8; - /* - * Get the General Flags (Byte4) - */ + /* Get the General Flags (Byte4) */ + buffer += 1; temp8 = *buffer; @@ -140,9 +138,8 @@ acpi_rs_address16_resource ( output_struct->data.address16.max_address_fixed = (temp8 >> 3) & 0x01; - /* - * Get the Type Specific Flags (Byte5) - */ + /* Get the Type Specific Flags (Byte5) */ + buffer += 1; temp8 = *buffer; @@ -165,39 +162,34 @@ acpi_rs_address16_resource ( } } - /* - * Get Granularity (Bytes 6-7) - */ + /* Get Granularity (Bytes 6-7) */ + buffer += 1; ACPI_MOVE_16_TO_32 (&output_struct->data.address16.granularity, buffer); - /* - * Get min_address_range (Bytes 8-9) - */ + /* Get min_address_range (Bytes 8-9) */ + buffer += 2; ACPI_MOVE_16_TO_32 (&output_struct->data.address16.min_address_range, buffer); - /* - * Get max_address_range (Bytes 10-11) - */ + /* Get max_address_range (Bytes 10-11) */ + buffer += 2; ACPI_MOVE_16_TO_32 (&output_struct->data.address16.max_address_range, buffer); - /* - * Get address_translation_offset (Bytes 12-13) - */ + /* Get address_translation_offset (Bytes 12-13) */ + buffer += 2; - ACPI_MOVE_16_TO_32 (&output_struct->data.address16.address_translation_offset, buffer); + ACPI_MOVE_16_TO_32 (&output_struct->data.address16.address_translation_offset, + buffer); + + /* Get address_length (Bytes 14-15) */ - /* - * Get address_length (Bytes 14-15) - */ buffer += 2; ACPI_MOVE_16_TO_32 (&output_struct->data.address16.address_length, buffer); - /* - * Resource Source Index (if present) - */ + /* Resource Source Index (if present) */ + buffer += 2; /* @@ -225,7 +217,8 @@ acpi_rs_address16_resource ( output_struct->data.address16.resource_source.string_ptr = (char *)((u8 * )output_struct + struct_size); - temp_ptr = (u8 *) output_struct->data.address16.resource_source.string_ptr; + temp_ptr = (u8 *) + output_struct->data.address16.resource_source.string_ptr; /* Copy the string into the buffer */ @@ -239,9 +232,8 @@ acpi_rs_address16_resource ( index += 1; } - /* - * Add the terminating null - */ + /* Add the terminating null */ + *temp_ptr = 0x00; output_struct->data.address16.resource_source.string_length = index + 1; @@ -260,14 +252,12 @@ acpi_rs_address16_resource ( output_struct->data.address16.resource_source.string_ptr = NULL; } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -305,28 +295,24 @@ acpi_rs_address16_stream ( ACPI_FUNCTION_TRACE ("rs_address16_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x88; buffer += 1; - /* - * Save a pointer to the Length field - to be filled in later - */ + /* Save a pointer to the Length field - to be filled in later */ + length_field = buffer; buffer += 2; - /* - * Set the Resource Type (Memory, Io, bus_number) - */ + /* Set the Resource Type (Memory, Io, bus_number) */ + temp8 = (u8) (linked_list->data.address16.resource_type & 0x03); *buffer = temp8; buffer += 1; - /* - * Set the general flags - */ + /* Set the general flags */ + temp8 = (u8) (linked_list->data.address16.producer_consumer & 0x01); temp8 |= (linked_list->data.address16.decode & 0x01) << 1; @@ -336,9 +322,8 @@ acpi_rs_address16_stream ( *buffer = temp8; buffer += 1; - /* - * Set the type specific flags - */ + /* Set the type specific flags */ + temp8 = 0; if (ACPI_MEMORY_RANGE == linked_list->data.address16.resource_type) { @@ -362,39 +347,34 @@ acpi_rs_address16_stream ( *buffer = temp8; buffer += 1; - /* - * Set the address space granularity - */ + /* Set the address space granularity */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.granularity); buffer += 2; - /* - * Set the address range minimum - */ + /* Set the address range minimum */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.min_address_range); buffer += 2; - /* - * Set the address range maximum - */ + /* Set the address range maximum */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.max_address_range); buffer += 2; - /* - * Set the address translation offset - */ - ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.address_translation_offset); + /* Set the address translation offset */ + + ACPI_MOVE_32_TO_16 (buffer, + &linked_list->data.address16.address_translation_offset); buffer += 2; - /* - * Set the address length - */ + /* Set the address length */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.address_length); buffer += 2; - /* - * Resource Source Index and Resource Source are optional - */ + /* Resource Source Index and Resource Source are optional */ + if (0 != linked_list->data.address16.resource_source.string_length) { temp8 = (u8) linked_list->data.address16.resource_source.index; @@ -403,9 +383,8 @@ acpi_rs_address16_stream ( temp_pointer = (char *) buffer; - /* - * Copy the string - */ + /* Copy the string */ + ACPI_STRCPY (temp_pointer, linked_list->data.address16.resource_source.string_ptr); @@ -413,12 +392,12 @@ acpi_rs_address16_stream ( * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address16.resource_source.string_ptr) + 1); + buffer += (acpi_size)(ACPI_STRLEN ( + linked_list->data.address16.resource_source.string_ptr) + 1); } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + actual_bytes = ACPI_PTR_DIFF (buffer, *output_buffer); *bytes_consumed = actual_bytes; @@ -475,9 +454,8 @@ acpi_rs_address32_resource ( buffer = byte_stream_buffer; struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address32); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -490,9 +468,8 @@ acpi_rs_address32_resource ( *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_ADDRESS32; - /* - * Get the Resource Type (Byte3) - */ + /* Get the Resource Type (Byte3) */ + buffer += 2; temp8 = *buffer; @@ -504,35 +481,29 @@ acpi_rs_address32_resource ( output_struct->data.address32.resource_type = temp8; - /* - * Get the General Flags (Byte4) - */ + /* Get the General Flags (Byte4) */ + buffer += 1; temp8 = *buffer; - /* - * Producer / Consumer - */ + /* Producer / Consumer */ + output_struct->data.address32.producer_consumer = temp8 & 0x01; - /* - * Decode - */ + /* Decode */ + output_struct->data.address32.decode = (temp8 >> 1) & 0x01; - /* - * Min Address Fixed - */ + /* Min Address Fixed */ + output_struct->data.address32.min_address_fixed = (temp8 >> 2) & 0x01; - /* - * Max Address Fixed - */ + /* Max Address Fixed */ + output_struct->data.address32.max_address_fixed = (temp8 >> 3) & 0x01; - /* - * Get the Type Specific Flags (Byte5) - */ + /* Get the Type Specific Flags (Byte5) */ + buffer += 1; temp8 = *buffer; @@ -556,39 +527,34 @@ acpi_rs_address32_resource ( } } - /* - * Get Granularity (Bytes 6-9) - */ + /* Get Granularity (Bytes 6-9) */ + buffer += 1; ACPI_MOVE_32_TO_32 (&output_struct->data.address32.granularity, buffer); - /* - * Get min_address_range (Bytes 10-13) - */ + /* Get min_address_range (Bytes 10-13) */ + buffer += 4; ACPI_MOVE_32_TO_32 (&output_struct->data.address32.min_address_range, buffer); - /* - * Get max_address_range (Bytes 14-17) - */ + /* Get max_address_range (Bytes 14-17) */ + buffer += 4; ACPI_MOVE_32_TO_32 (&output_struct->data.address32.max_address_range, buffer); - /* - * Get address_translation_offset (Bytes 18-21) - */ + /* Get address_translation_offset (Bytes 18-21) */ + buffer += 4; - ACPI_MOVE_32_TO_32 (&output_struct->data.address32.address_translation_offset, buffer); + ACPI_MOVE_32_TO_32 (&output_struct->data.address32.address_translation_offset, + buffer); + + /* Get address_length (Bytes 22-25) */ - /* - * Get address_length (Bytes 22-25) - */ buffer += 4; ACPI_MOVE_32_TO_32 (&output_struct->data.address32.address_length, buffer); - /* - * Resource Source Index (if present) - */ + /* Resource Source Index (if present) */ + buffer += 4; /* @@ -615,7 +581,8 @@ acpi_rs_address32_resource ( output_struct->data.address32.resource_source.string_ptr = (char *)((u8 *)output_struct + struct_size); - temp_ptr = (u8 *) output_struct->data.address32.resource_source.string_ptr; + temp_ptr = (u8 *) + output_struct->data.address32.resource_source.string_ptr; /* Copy the string into the buffer */ @@ -628,9 +595,8 @@ acpi_rs_address32_resource ( index += 1; } - /* - * Add the terminating null - */ + /* Add the terminating null */ + *temp_ptr = 0x00; output_struct->data.address32.resource_source.string_length = index + 1; @@ -648,14 +614,12 @@ acpi_rs_address32_resource ( output_struct->data.address32.resource_source.string_ptr = NULL; } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -694,29 +658,25 @@ acpi_rs_address32_stream ( buffer = *output_buffer; - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x87; buffer += 1; - /* - * Set a pointer to the Length field - to be filled in later - */ + /* Set a pointer to the Length field - to be filled in later */ + length_field = ACPI_CAST_PTR (u16, buffer); buffer += 2; - /* - * Set the Resource Type (Memory, Io, bus_number) - */ + /* Set the Resource Type (Memory, Io, bus_number) */ + temp8 = (u8) (linked_list->data.address32.resource_type & 0x03); *buffer = temp8; buffer += 1; - /* - * Set the general flags - */ + /* Set the general flags */ + temp8 = (u8) (linked_list->data.address32.producer_consumer & 0x01); temp8 |= (linked_list->data.address32.decode & 0x01) << 1; temp8 |= (linked_list->data.address32.min_address_fixed & 0x01) << 2; @@ -725,9 +685,8 @@ acpi_rs_address32_stream ( *buffer = temp8; buffer += 1; - /* - * Set the type specific flags - */ + /* Set the type specific flags */ + temp8 = 0; if (ACPI_MEMORY_RANGE == linked_list->data.address32.resource_type) { @@ -751,39 +710,34 @@ acpi_rs_address32_stream ( *buffer = temp8; buffer += 1; - /* - * Set the address space granularity - */ + /* Set the address space granularity */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.granularity); buffer += 4; - /* - * Set the address range minimum - */ + /* Set the address range minimum */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.min_address_range); buffer += 4; - /* - * Set the address range maximum - */ + /* Set the address range maximum */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.max_address_range); buffer += 4; - /* - * Set the address translation offset - */ - ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.address_translation_offset); + /* Set the address translation offset */ + + ACPI_MOVE_32_TO_32 (buffer, + &linked_list->data.address32.address_translation_offset); buffer += 4; - /* - * Set the address length - */ + /* Set the address length */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.address_length); buffer += 4; - /* - * Resource Source Index and Resource Source are optional - */ + /* Resource Source Index and Resource Source are optional */ + if (0 != linked_list->data.address32.resource_source.string_length) { temp8 = (u8) linked_list->data.address32.resource_source.index; @@ -792,9 +746,8 @@ acpi_rs_address32_stream ( temp_pointer = (char *) buffer; - /* - * Copy the string - */ + /* Copy the string */ + ACPI_STRCPY (temp_pointer, linked_list->data.address32.resource_source.string_ptr); @@ -802,12 +755,12 @@ acpi_rs_address32_stream ( * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address32.resource_source.string_ptr) + 1); + buffer += (acpi_size)(ACPI_STRLEN ( + linked_list->data.address32.resource_source.string_ptr) + 1); } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); /* @@ -864,9 +817,8 @@ acpi_rs_address64_resource ( struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64); resource_type = *buffer; - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -879,9 +831,8 @@ acpi_rs_address64_resource ( *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_ADDRESS64; - /* - * Get the Resource Type (Byte3) - */ + /* Get the Resource Type (Byte3) */ + buffer += 2; temp8 = *buffer; @@ -893,35 +844,29 @@ acpi_rs_address64_resource ( output_struct->data.address64.resource_type = temp8; - /* - * Get the General Flags (Byte4) - */ + /* Get the General Flags (Byte4) */ + buffer += 1; temp8 = *buffer; - /* - * Producer / Consumer - */ + /* Producer / Consumer */ + output_struct->data.address64.producer_consumer = temp8 & 0x01; - /* - * Decode - */ + /* Decode */ + output_struct->data.address64.decode = (temp8 >> 1) & 0x01; - /* - * Min Address Fixed - */ + /* Min Address Fixed */ + output_struct->data.address64.min_address_fixed = (temp8 >> 2) & 0x01; - /* - * Max Address Fixed - */ + /* Max Address Fixed */ + output_struct->data.address64.max_address_fixed = (temp8 >> 3) & 0x01; - /* - * Get the Type Specific Flags (Byte5) - */ + /* Get the Type Specific Flags (Byte5) */ + buffer += 1; temp8 = *buffer; @@ -951,33 +896,29 @@ acpi_rs_address64_resource ( buffer += 2; } - /* - * Get Granularity (Bytes 6-13) or (Bytes 8-15) - */ + /* Get Granularity (Bytes 6-13) or (Bytes 8-15) */ + buffer += 1; ACPI_MOVE_64_TO_64 (&output_struct->data.address64.granularity, buffer); - /* - * Get min_address_range (Bytes 14-21) or (Bytes 16-23) - */ + /* Get min_address_range (Bytes 14-21) or (Bytes 16-23) */ + buffer += 8; ACPI_MOVE_64_TO_64 (&output_struct->data.address64.min_address_range, buffer); - /* - * Get max_address_range (Bytes 22-29) or (Bytes 24-31) - */ + /* Get max_address_range (Bytes 22-29) or (Bytes 24-31) */ + buffer += 8; ACPI_MOVE_64_TO_64 (&output_struct->data.address64.max_address_range, buffer); - /* - * Get address_translation_offset (Bytes 30-37) or (Bytes 32-39) - */ + /* Get address_translation_offset (Bytes 30-37) or (Bytes 32-39) */ + buffer += 8; - ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_translation_offset, buffer); + ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_translation_offset, + buffer); + + /* Get address_length (Bytes 38-45) or (Bytes 40-47) */ - /* - * Get address_length (Bytes 38-45) or (Bytes 40-47) - */ buffer += 8; ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_length, buffer); @@ -989,14 +930,15 @@ acpi_rs_address64_resource ( /* Get type_specific_attribute (Bytes 48-55) */ buffer += 8; - ACPI_MOVE_64_TO_64 (&output_struct->data.address64.type_specific_attributes, buffer); + ACPI_MOVE_64_TO_64 ( + &output_struct->data.address64.type_specific_attributes, + buffer); } else { output_struct->data.address64.type_specific_attributes = 0; - /* - * Resource Source Index (if present) - */ + /* Resource Source Index (if present) */ + buffer += 8; /* @@ -1025,7 +967,8 @@ acpi_rs_address64_resource ( output_struct->data.address64.resource_source.string_ptr = (char *)((u8 *)output_struct + struct_size); - temp_ptr = (u8 *) output_struct->data.address64.resource_source.string_ptr; + temp_ptr = (u8 *) + output_struct->data.address64.resource_source.string_ptr; /* Copy the string into the buffer */ @@ -1042,7 +985,8 @@ acpi_rs_address64_resource ( * Add the terminating null */ *temp_ptr = 0x00; - output_struct->data.address64.resource_source.string_length = index + 1; + output_struct->data.address64.resource_source.string_length = + index + 1; /* * In order for the struct_size to fall on a 32-bit boundary, @@ -1054,14 +998,12 @@ acpi_rs_address64_resource ( } } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -1100,29 +1042,25 @@ acpi_rs_address64_stream ( buffer = *output_buffer; - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x8A; buffer += 1; - /* - * Set a pointer to the Length field - to be filled in later - */ + /* Set a pointer to the Length field - to be filled in later */ + length_field = ACPI_CAST_PTR (u16, buffer); buffer += 2; - /* - * Set the Resource Type (Memory, Io, bus_number) - */ + /* Set the Resource Type (Memory, Io, bus_number) */ + temp8 = (u8) (linked_list->data.address64.resource_type & 0x03); *buffer = temp8; buffer += 1; - /* - * Set the general flags - */ + /* Set the general flags */ + temp8 = (u8) (linked_list->data.address64.producer_consumer & 0x01); temp8 |= (linked_list->data.address64.decode & 0x01) << 1; temp8 |= (linked_list->data.address64.min_address_fixed & 0x01) << 2; @@ -1131,9 +1069,8 @@ acpi_rs_address64_stream ( *buffer = temp8; buffer += 1; - /* - * Set the type specific flags - */ + /* Set the type specific flags */ + temp8 = 0; if (ACPI_MEMORY_RANGE == linked_list->data.address64.resource_type) { @@ -1157,39 +1094,34 @@ acpi_rs_address64_stream ( *buffer = temp8; buffer += 1; - /* - * Set the address space granularity - */ + /* Set the address space granularity */ + ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.granularity); buffer += 8; - /* - * Set the address range minimum - */ + /* Set the address range minimum */ + ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.min_address_range); buffer += 8; - /* - * Set the address range maximum - */ + /* Set the address range maximum */ + ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.max_address_range); buffer += 8; - /* - * Set the address translation offset - */ - ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.address_translation_offset); + /* Set the address translation offset */ + + ACPI_MOVE_64_TO_64 (buffer, + &linked_list->data.address64.address_translation_offset); buffer += 8; - /* - * Set the address length - */ + /* Set the address length */ + ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.address_length); buffer += 8; - /* - * Resource Source Index and Resource Source are optional - */ + /* Resource Source Index and Resource Source are optional */ + if (0 != linked_list->data.address64.resource_source.string_length) { temp8 = (u8) linked_list->data.address64.resource_source.index; @@ -1198,21 +1130,21 @@ acpi_rs_address64_stream ( temp_pointer = (char *) buffer; - /* - * Copy the string - */ - ACPI_STRCPY (temp_pointer, linked_list->data.address64.resource_source.string_ptr); + /* Copy the string */ + + ACPI_STRCPY (temp_pointer, + linked_list->data.address64.resource_source.string_ptr); /* * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address64.resource_source.string_ptr) + 1); + buffer += (acpi_size)(ACPI_STRLEN ( + linked_list->data.address64.resource_source.string_ptr) + 1); } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); /* diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index 8a5f0a52371..98176f2fcb5 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -81,9 +81,8 @@ acpi_rs_get_byte_stream_length ( while (!done) { - /* - * Init the variable that will hold the size to add to the total. - */ + /* Init the variable that will hold the size to add to the total. */ + segment_size = 0; switch (linked_list->id) { @@ -196,7 +195,8 @@ acpi_rs_get_byte_stream_length ( segment_size = 16; if (linked_list->data.address16.resource_source.string_ptr) { - segment_size += linked_list->data.address16.resource_source.string_length; + segment_size += + linked_list->data.address16.resource_source.string_length; segment_size++; } break; @@ -212,7 +212,8 @@ acpi_rs_get_byte_stream_length ( segment_size = 26; if (linked_list->data.address32.resource_source.string_ptr) { - segment_size += linked_list->data.address32.resource_source.string_length; + segment_size += + linked_list->data.address32.resource_source.string_length; segment_size++; } break; @@ -227,7 +228,8 @@ acpi_rs_get_byte_stream_length ( segment_size = 46; if (linked_list->data.address64.resource_source.string_ptr) { - segment_size += linked_list->data.address64.resource_source.string_length; + segment_size += + linked_list->data.address64.resource_source.string_length; segment_size++; } break; @@ -241,38 +243,36 @@ acpi_rs_get_byte_stream_length ( * Index + the length of the null terminated string * Resource Source + 1 for the null. */ - segment_size = 9 + - (((acpi_size) linked_list->data.extended_irq.number_of_interrupts - 1) * 4); + segment_size = 9 + (((acpi_size) + linked_list->data.extended_irq.number_of_interrupts - 1) * 4); if (linked_list->data.extended_irq.resource_source.string_ptr) { - segment_size += linked_list->data.extended_irq.resource_source.string_length; + segment_size += + linked_list->data.extended_irq.resource_source.string_length; segment_size++; } break; default: - /* - * If we get here, everything is out of sync, exit with error - */ + + /* If we get here, everything is out of sync, exit with error */ + return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); } /* switch (linked_list->Id) */ - /* - * Update the total - */ + /* Update the total */ + byte_stream_size_needed += segment_size; - /* - * Point to the next object - */ + /* Point to the next object */ + linked_list = ACPI_PTR_ADD (struct acpi_resource, linked_list, linked_list->length); } - /* - * This is the data the caller needs - */ + /* This is the data the caller needs */ + *size_needed = byte_stream_size_needed; return_ACPI_STATUS (AE_OK); } @@ -320,9 +320,8 @@ acpi_rs_get_list_length ( while (bytes_parsed < byte_stream_buffer_length) { - /* - * The next byte in the stream is the resource type - */ + /* The next byte in the stream is the resource type */ + resource_type = acpi_rs_get_resource_type (*byte_stream_buffer); switch (resource_type) { @@ -346,9 +345,8 @@ acpi_rs_get_list_length ( ACPI_MOVE_16_TO_16 (&temp16, buffer); bytes_consumed = temp16 + 3; - /* - * Ensure a 32-bit boundary for the structure - */ + /* Ensure a 32-bit boundary for the structure */ + temp16 = (u16) ACPI_ROUND_UP_to_32_bITS (temp16); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor) + @@ -416,9 +414,8 @@ acpi_rs_get_list_length ( temp8 = 0; } - /* - * Ensure a 64-bit boundary for the structure - */ + /* Ensure a 64-bit boundary for the structure */ + temp8 = (u8) ACPI_ROUND_UP_to_64_bITS (temp8); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64) + @@ -452,9 +449,8 @@ acpi_rs_get_list_length ( temp8 = 0; } - /* - * Ensure a 32-bit boundary for the structure - */ + /* Ensure a 32-bit boundary for the structure */ + temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address32) + @@ -488,9 +484,8 @@ acpi_rs_get_list_length ( temp8 = 0; } - /* - * Ensure a 32-bit boundary for the structure - */ + /* Ensure a 32-bit boundary for the structure */ + temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address16) + @@ -537,9 +532,8 @@ acpi_rs_get_list_length ( temp8 = 0; } - /* - * Ensure a 32-bit boundary for the structure - */ + /* Ensure a 32-bit boundary for the structure */ + temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_ext_irq) + @@ -567,9 +561,8 @@ acpi_rs_get_list_length ( ++buffer; - /* - * Look at the number of bits set - */ + /* Look at the number of bits set */ + ACPI_MOVE_16_TO_16 (&temp16, buffer); for (index = 0; index < 16; index++) { @@ -596,9 +589,8 @@ acpi_rs_get_list_length ( ++buffer; - /* - * Look at the number of bits set - */ + /* Look at the number of bits set */ + temp8 = *buffer; for(index = 0; index < 8; index++) { @@ -670,9 +662,8 @@ acpi_rs_get_list_length ( temp8 = (u8) (temp8 & 0x7); bytes_consumed = temp8 + 1; - /* - * Ensure a 32-bit boundary for the structure - */ + /* Ensure a 32-bit boundary for the structure */ + temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8); structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor) + (temp8 * sizeof (u8)); @@ -697,21 +688,18 @@ acpi_rs_get_list_length ( return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); } - /* - * Update the return value and counter - */ + /* Update the return value and counter */ + buffer_size += (u32) ACPI_ALIGN_RESOURCE_SIZE (structure_size); bytes_parsed += bytes_consumed; - /* - * Set the byte stream to point to the next resource - */ + /* Set the byte stream to point to the next resource */ + byte_stream_buffer += bytes_consumed; } - /* - * This is the data the caller needs - */ + /* This is the data the caller needs */ + *size_needed = buffer_size; return_ACPI_STATUS (AE_OK); } @@ -767,9 +755,8 @@ acpi_rs_get_pci_routing_table_length ( top_object_list = package_object->package.elements; for (index = 0; index < number_of_elements; index++) { - /* - * Dereference the sub-package - */ + /* Dereference the sub-package */ + package_element = *top_object_list; /* @@ -778,37 +765,40 @@ acpi_rs_get_pci_routing_table_length ( */ sub_object_list = package_element->package.elements; - /* - * Scan the irq_table_elements for the Source Name String - */ + /* Scan the irq_table_elements for the Source Name String */ + name_found = FALSE; for (table_index = 0; table_index < 4 && !name_found; table_index++) { - if ((ACPI_TYPE_STRING == ACPI_GET_OBJECT_TYPE (*sub_object_list)) || - ((ACPI_TYPE_LOCAL_REFERENCE == ACPI_GET_OBJECT_TYPE (*sub_object_list)) && - ((*sub_object_list)->reference.opcode == AML_INT_NAMEPATH_OP))) { + if ((ACPI_TYPE_STRING == + ACPI_GET_OBJECT_TYPE (*sub_object_list)) || + + ((ACPI_TYPE_LOCAL_REFERENCE == + ACPI_GET_OBJECT_TYPE (*sub_object_list)) && + + ((*sub_object_list)->reference.opcode == + AML_INT_NAMEPATH_OP))) { name_found = TRUE; } else { - /* - * Look at the next element - */ + /* Look at the next element */ + sub_object_list++; } } temp_size_needed += (sizeof (struct acpi_pci_routing_table) - 4); - /* - * Was a String type found? - */ + /* Was a String type found? */ + if (name_found) { if (ACPI_GET_OBJECT_TYPE (*sub_object_list) == ACPI_TYPE_STRING) { /* * The length String.Length field does not include the * terminating NULL, add 1 */ - temp_size_needed += ((acpi_size) (*sub_object_list)->string.length + 1); + temp_size_needed += ((acpi_size) + (*sub_object_list)->string.length + 1); } else { temp_size_needed += acpi_ns_get_pathname_length ( @@ -827,14 +817,14 @@ acpi_rs_get_pci_routing_table_length ( temp_size_needed = ACPI_ROUND_UP_to_64_bITS (temp_size_needed); - /* - * Point to the next union acpi_operand_object - */ + /* Point to the next union acpi_operand_object */ + top_object_list++; } /* - * Adding an extra element to the end of the list, essentially a NULL terminator + * Adding an extra element to the end of the list, essentially a + * NULL terminator */ *buffer_size_needed = temp_size_needed + sizeof (struct acpi_pci_routing_table); return_ACPI_STATUS (AE_OK); diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c index a3a0cbfda68..8e0eae0d50b 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/resources/rscreate.c @@ -87,9 +87,8 @@ acpi_rs_create_resource_list ( ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "byte_stream_buffer = %p\n", byte_stream_buffer)); - /* - * Params already validated, so we don't re-validate here - */ + /* Params already validated, so we don't re-validate here */ + byte_stream_buffer_length = byte_stream_buffer->buffer.length; byte_stream_start = byte_stream_buffer->buffer.pointer; @@ -171,9 +170,8 @@ acpi_rs_create_pci_routing_table ( /* Params already validated, so we don't re-validate here */ - /* - * Get the required buffer length - */ + /* Get the required buffer length */ + status = acpi_rs_get_pci_routing_table_length (package_object, &buffer_size_needed); if (ACPI_FAILURE (status)) { @@ -217,9 +215,8 @@ acpi_rs_create_pci_routing_table ( */ user_prt->length = (sizeof (struct acpi_pci_routing_table) - 4); - /* - * Each element of the top-level package must also be a package - */ + /* Each element of the top-level package must also be a package */ + if (ACPI_GET_OBJECT_TYPE (*top_object_list) != ACPI_TYPE_PACKAGE) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(PRT[%X]) Need sub-package, found %s\n", @@ -243,9 +240,8 @@ acpi_rs_create_pci_routing_table ( */ sub_object_list = (*top_object_list)->package.elements; - /* - * 1) First subobject: Dereference the PRT.Address - */ + /* 1) First subobject: Dereference the PRT.Address */ + obj_desc = sub_object_list[0]; if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { user_prt->address = obj_desc->integer.value; @@ -257,9 +253,8 @@ acpi_rs_create_pci_routing_table ( return_ACPI_STATUS (AE_BAD_DATA); } - /* - * 2) Second subobject: Dereference the PRT.Pin - */ + /* 2) Second subobject: Dereference the PRT.Pin */ + obj_desc = sub_object_list[1]; if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { user_prt->pin = (u32) obj_desc->integer.value; @@ -271,9 +266,8 @@ acpi_rs_create_pci_routing_table ( return_ACPI_STATUS (AE_BAD_DATA); } - /* - * 3) Third subobject: Dereference the PRT.source_name - */ + /* 3) Third subobject: Dereference the PRT.source_name */ + obj_desc = sub_object_list[2]; switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { case ACPI_TYPE_LOCAL_REFERENCE: @@ -296,7 +290,9 @@ acpi_rs_create_pci_routing_table ( status = acpi_ns_handle_to_pathname ((acpi_handle) node, &path_buffer); - user_prt->length += (u32) ACPI_STRLEN (user_prt->source) + 1; /* include null terminator */ + /* +1 to include null terminator */ + + user_prt->length += (u32) ACPI_STRLEN (user_prt->source) + 1; break; @@ -304,8 +300,10 @@ acpi_rs_create_pci_routing_table ( ACPI_STRCPY (user_prt->source, obj_desc->string.pointer); - /* Add to the Length field the length of the string (add 1 for terminator) */ - + /* + * Add to the Length field the length of the string + * (add 1 for terminator) + */ user_prt->length += obj_desc->string.length + 1; break; @@ -333,9 +331,8 @@ acpi_rs_create_pci_routing_table ( user_prt->length = (u32) ACPI_ROUND_UP_to_64_bITS (user_prt->length); - /* - * 4) Fourth subobject: Dereference the PRT.source_index - */ + /* 4) Fourth subobject: Dereference the PRT.source_index */ + obj_desc = sub_object_list[3]; if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { user_prt->source_index = (u32) obj_desc->integer.value; diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c index eef1b1f2c68..1935dab2ab5 100644 --- a/drivers/acpi/resources/rsdump.c +++ b/drivers/acpi/resources/rsdump.c @@ -48,9 +48,62 @@ #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME ("rsdump") +/* Local prototypes */ -#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +static void +acpi_rs_dump_irq ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_address16 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_address32 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_address64 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_dma ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_io ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_extended_irq ( + union acpi_resource_data *data); +static void +acpi_rs_dump_fixed_io ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_fixed_memory32 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_memory24 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_memory32 ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_start_depend_fns ( + union acpi_resource_data *data); + +static void +acpi_rs_dump_vendor_specific ( + union acpi_resource_data *data); + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) /******************************************************************************* * * FUNCTION: acpi_rs_dump_irq @@ -63,7 +116,7 @@ * ******************************************************************************/ -void +static void acpi_rs_dump_irq ( union acpi_resource_data *data) { @@ -77,13 +130,13 @@ acpi_rs_dump_irq ( acpi_os_printf ("IRQ Resource\n"); acpi_os_printf (" %s Triggered\n", - ACPI_LEVEL_SENSITIVE == irq_data->edge_level ? "Level" : "Edge"); + ACPI_LEVEL_SENSITIVE == irq_data->edge_level ? "Level" : "Edge"); acpi_os_printf (" Active %s\n", - ACPI_ACTIVE_LOW == irq_data->active_high_low ? "Low" : "High"); + ACPI_ACTIVE_LOW == irq_data->active_high_low ? "Low" : "High"); acpi_os_printf (" %s\n", - ACPI_SHARED == irq_data->shared_exclusive ? "Shared" : "Exclusive"); + ACPI_SHARED == irq_data->shared_exclusive ? "Shared" : "Exclusive"); acpi_os_printf (" %X Interrupts ( ", irq_data->number_of_interrupts); @@ -108,7 +161,7 @@ acpi_rs_dump_irq ( * ******************************************************************************/ -void +static void acpi_rs_dump_dma ( union acpi_resource_data *data) { @@ -144,7 +197,7 @@ acpi_rs_dump_dma ( } acpi_os_printf (" %sBus Master\n", - ACPI_BUS_MASTER == dma_data->bus_master ? "" : "Not a "); + ACPI_BUS_MASTER == dma_data->bus_master ? "" : "Not a "); switch (dma_data->transfer) { @@ -165,7 +218,8 @@ acpi_rs_dump_dma ( break; } - acpi_os_printf (" Number of Channels: %X ( ", dma_data->number_of_channels); + acpi_os_printf (" Number of Channels: %X ( ", + dma_data->number_of_channels); for (index = 0; index < dma_data->number_of_channels; index++) { acpi_os_printf ("%X ", dma_data->channels[index]); @@ -188,7 +242,7 @@ acpi_rs_dump_dma ( * ******************************************************************************/ -void +static void acpi_rs_dump_start_depend_fns ( union acpi_resource_data *data) { @@ -232,8 +286,7 @@ acpi_rs_dump_start_depend_fns ( break; default: - acpi_os_printf (" Invalid performance " - "robustness preference\n"); + acpi_os_printf (" Invalid performance robustness preference\n"); break; } @@ -253,7 +306,7 @@ acpi_rs_dump_start_depend_fns ( * ******************************************************************************/ -void +static void acpi_rs_dump_io ( union acpi_resource_data *data) { @@ -266,19 +319,15 @@ acpi_rs_dump_io ( acpi_os_printf ("Io Resource\n"); acpi_os_printf (" %d bit decode\n", - ACPI_DECODE_16 == io_data->io_decode ? 16 : 10); + ACPI_DECODE_16 == io_data->io_decode ? 16 : 10); - acpi_os_printf (" Range minimum base: %08X\n", - io_data->min_base_address); + acpi_os_printf (" Range minimum base: %08X\n", io_data->min_base_address); - acpi_os_printf (" Range maximum base: %08X\n", - io_data->max_base_address); + acpi_os_printf (" Range maximum base: %08X\n", io_data->max_base_address); - acpi_os_printf (" Alignment: %08X\n", - io_data->alignment); + acpi_os_printf (" Alignment: %08X\n", io_data->alignment); - acpi_os_printf (" Range Length: %08X\n", - io_data->range_length); + acpi_os_printf (" Range Length: %08X\n", io_data->range_length); return; } @@ -296,7 +345,7 @@ acpi_rs_dump_io ( * ******************************************************************************/ -void +static void acpi_rs_dump_fixed_io ( union acpi_resource_data *data) { @@ -307,11 +356,9 @@ acpi_rs_dump_fixed_io ( acpi_os_printf ("Fixed Io Resource\n"); - acpi_os_printf (" Range base address: %08X", - fixed_io_data->base_address); + acpi_os_printf (" Range base address: %08X", fixed_io_data->base_address); - acpi_os_printf (" Range length: %08X", - fixed_io_data->range_length); + acpi_os_printf (" Range length: %08X", fixed_io_data->range_length); return; } @@ -329,7 +376,7 @@ acpi_rs_dump_fixed_io ( * ******************************************************************************/ -void +static void acpi_rs_dump_vendor_specific ( union acpi_resource_data *data) { @@ -346,7 +393,7 @@ acpi_rs_dump_vendor_specific ( for (index = 0; index < vendor_data->length; index++) { acpi_os_printf (" Byte %X: %08X\n", - index, vendor_data->reserved[index]); + index, vendor_data->reserved[index]); } return; @@ -365,7 +412,7 @@ acpi_rs_dump_vendor_specific ( * ******************************************************************************/ -void +static void acpi_rs_dump_memory24 ( union acpi_resource_data *data) { @@ -378,21 +425,19 @@ acpi_rs_dump_memory24 ( acpi_os_printf ("24-Bit Memory Range Resource\n"); acpi_os_printf (" Read%s\n", - ACPI_READ_WRITE_MEMORY == - memory24_data->read_write_attribute ? - "/Write" : " only"); + ACPI_READ_WRITE_MEMORY == + memory24_data->read_write_attribute ? + "/Write" : " only"); acpi_os_printf (" Range minimum base: %08X\n", - memory24_data->min_base_address); + memory24_data->min_base_address); acpi_os_printf (" Range maximum base: %08X\n", - memory24_data->max_base_address); + memory24_data->max_base_address); - acpi_os_printf (" Alignment: %08X\n", - memory24_data->alignment); + acpi_os_printf (" Alignment: %08X\n", memory24_data->alignment); - acpi_os_printf (" Range length: %08X\n", - memory24_data->range_length); + acpi_os_printf (" Range length: %08X\n", memory24_data->range_length); return; } @@ -410,7 +455,7 @@ acpi_rs_dump_memory24 ( * ******************************************************************************/ -void +static void acpi_rs_dump_memory32 ( union acpi_resource_data *data) { @@ -423,21 +468,19 @@ acpi_rs_dump_memory32 ( acpi_os_printf ("32-Bit Memory Range Resource\n"); acpi_os_printf (" Read%s\n", - ACPI_READ_WRITE_MEMORY == - memory32_data->read_write_attribute ? - "/Write" : " only"); + ACPI_READ_WRITE_MEMORY == + memory32_data->read_write_attribute ? + "/Write" : " only"); acpi_os_printf (" Range minimum base: %08X\n", - memory32_data->min_base_address); + memory32_data->min_base_address); acpi_os_printf (" Range maximum base: %08X\n", - memory32_data->max_base_address); + memory32_data->max_base_address); - acpi_os_printf (" Alignment: %08X\n", - memory32_data->alignment); + acpi_os_printf (" Alignment: %08X\n", memory32_data->alignment); - acpi_os_printf (" Range length: %08X\n", - memory32_data->range_length); + acpi_os_printf (" Range length: %08X\n", memory32_data->range_length); return; } @@ -455,11 +498,12 @@ acpi_rs_dump_memory32 ( * ******************************************************************************/ -void +static void acpi_rs_dump_fixed_memory32 ( union acpi_resource_data *data) { - struct acpi_resource_fixed_mem32 *fixed_memory32_data = (struct acpi_resource_fixed_mem32 *) data; + struct acpi_resource_fixed_mem32 *fixed_memory32_data = + (struct acpi_resource_fixed_mem32 *) data; ACPI_FUNCTION_ENTRY (); @@ -468,15 +512,14 @@ acpi_rs_dump_fixed_memory32 ( acpi_os_printf ("32-Bit Fixed Location Memory Range Resource\n"); acpi_os_printf (" Read%s\n", - ACPI_READ_WRITE_MEMORY == - fixed_memory32_data->read_write_attribute ? - "/Write" : " Only"); + ACPI_READ_WRITE_MEMORY == + fixed_memory32_data->read_write_attribute ? "/Write" : " Only"); acpi_os_printf (" Range base address: %08X\n", - fixed_memory32_data->range_base_address); + fixed_memory32_data->range_base_address); acpi_os_printf (" Range length: %08X\n", - fixed_memory32_data->range_length); + fixed_memory32_data->range_length); return; } @@ -494,7 +537,7 @@ acpi_rs_dump_fixed_memory32 ( * ******************************************************************************/ -void +static void acpi_rs_dump_address16 ( union acpi_resource_data *data) { @@ -514,35 +557,30 @@ acpi_rs_dump_address16 ( switch (address16_data->attribute.memory.cache_attribute) { case ACPI_NON_CACHEABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Noncacheable memory\n"); + acpi_os_printf (" Type Specific: Noncacheable memory\n"); break; case ACPI_CACHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Cacheable memory\n"); + acpi_os_printf (" Type Specific: Cacheable memory\n"); break; case ACPI_WRITE_COMBINING_MEMORY: - acpi_os_printf (" Type Specific: " - "Write-combining memory\n"); + acpi_os_printf (" Type Specific: Write-combining memory\n"); break; case ACPI_PREFETCHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Prefetchable memory\n"); + acpi_os_printf (" Type Specific: Prefetchable memory\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid cache attribute\n"); + acpi_os_printf (" Type Specific: Invalid cache attribute\n"); break; } acpi_os_printf (" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == - address16_data->attribute.memory.read_write_attribute ? - "/Write" : " Only"); + address16_data->attribute.memory.read_write_attribute ? + "/Write" : " Only"); break; case ACPI_IO_RANGE: @@ -551,30 +589,26 @@ acpi_rs_dump_address16 ( switch (address16_data->attribute.io.range_attribute) { case ACPI_NON_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "Non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: Non-ISA Io Addresses\n"); break; case ACPI_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA Io Addresses\n"); break; case ACPI_ENTIRE_RANGE: - acpi_os_printf (" Type Specific: " - "ISA and non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA and non-ISA Io Addresses\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid range attribute\n"); + acpi_os_printf (" Type Specific: Invalid range attribute\n"); break; } acpi_os_printf (" Type Specific: %s Translation\n", ACPI_SPARSE_TRANSLATION == - address16_data->attribute.io.translation_attribute ? - "Sparse" : "Dense"); + address16_data->attribute.io.translation_attribute ? + "Sparse" : "Dense"); break; case ACPI_BUS_NUMBER_RANGE: @@ -589,41 +623,42 @@ acpi_rs_dump_address16 ( } acpi_os_printf (" Resource %s\n", - ACPI_CONSUMER == address16_data->producer_consumer ? + ACPI_CONSUMER == address16_data->producer_consumer ? "Consumer" : "Producer"); acpi_os_printf (" %s decode\n", - ACPI_SUB_DECODE == address16_data->decode ? - "Subtractive" : "Positive"); + ACPI_SUB_DECODE == address16_data->decode ? + "Subtractive" : "Positive"); acpi_os_printf (" Min address is %s fixed\n", - ACPI_ADDRESS_FIXED == address16_data->min_address_fixed ? - "" : "not"); + ACPI_ADDRESS_FIXED == address16_data->min_address_fixed ? + "" : "not"); acpi_os_printf (" Max address is %s fixed\n", - ACPI_ADDRESS_FIXED == address16_data->max_address_fixed ? - "" : "not"); + ACPI_ADDRESS_FIXED == address16_data->max_address_fixed ? + "" : "not"); acpi_os_printf (" Granularity: %08X\n", - address16_data->granularity); + address16_data->granularity); acpi_os_printf (" Address range min: %08X\n", - address16_data->min_address_range); + address16_data->min_address_range); acpi_os_printf (" Address range max: %08X\n", - address16_data->max_address_range); + address16_data->max_address_range); acpi_os_printf (" Address translation offset: %08X\n", - address16_data->address_translation_offset); + address16_data->address_translation_offset); acpi_os_printf (" Address Length: %08X\n", - address16_data->address_length); + address16_data->address_length); if (0xFF != address16_data->resource_source.index) { acpi_os_printf (" Resource Source Index: %X\n", - address16_data->resource_source.index); + address16_data->resource_source.index); + acpi_os_printf (" Resource Source: %s\n", - address16_data->resource_source.string_ptr); + address16_data->resource_source.string_ptr); } return; @@ -642,7 +677,7 @@ acpi_rs_dump_address16 ( * ******************************************************************************/ -void +static void acpi_rs_dump_address32 ( union acpi_resource_data *data) { @@ -661,35 +696,30 @@ acpi_rs_dump_address32 ( switch (address32_data->attribute.memory.cache_attribute) { case ACPI_NON_CACHEABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Noncacheable memory\n"); + acpi_os_printf (" Type Specific: Noncacheable memory\n"); break; case ACPI_CACHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Cacheable memory\n"); + acpi_os_printf (" Type Specific: Cacheable memory\n"); break; case ACPI_WRITE_COMBINING_MEMORY: - acpi_os_printf (" Type Specific: " - "Write-combining memory\n"); + acpi_os_printf (" Type Specific: Write-combining memory\n"); break; case ACPI_PREFETCHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Prefetchable memory\n"); + acpi_os_printf (" Type Specific: Prefetchable memory\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid cache attribute\n"); + acpi_os_printf (" Type Specific: Invalid cache attribute\n"); break; } acpi_os_printf (" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == - address32_data->attribute.memory.read_write_attribute ? - "/Write" : " Only"); + address32_data->attribute.memory.read_write_attribute ? + "/Write" : " Only"); break; case ACPI_IO_RANGE: @@ -698,30 +728,26 @@ acpi_rs_dump_address32 ( switch (address32_data->attribute.io.range_attribute) { case ACPI_NON_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "Non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: Non-ISA Io Addresses\n"); break; case ACPI_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA Io Addresses\n"); break; case ACPI_ENTIRE_RANGE: - acpi_os_printf (" Type Specific: " - "ISA and non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA and non-ISA Io Addresses\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid Range attribute"); + acpi_os_printf (" Type Specific: Invalid Range attribute"); break; } acpi_os_printf (" Type Specific: %s Translation\n", ACPI_SPARSE_TRANSLATION == - address32_data->attribute.io.translation_attribute ? - "Sparse" : "Dense"); + address32_data->attribute.io.translation_attribute ? + "Sparse" : "Dense"); break; case ACPI_BUS_NUMBER_RANGE: @@ -731,46 +757,48 @@ acpi_rs_dump_address32 ( default: - acpi_os_printf (" Resource Type: 0x%2.2X\n", address32_data->resource_type); + acpi_os_printf (" Resource Type: 0x%2.2X\n", + address32_data->resource_type); break; } acpi_os_printf (" Resource %s\n", - ACPI_CONSUMER == address32_data->producer_consumer ? - "Consumer" : "Producer"); + ACPI_CONSUMER == address32_data->producer_consumer ? + "Consumer" : "Producer"); acpi_os_printf (" %s decode\n", - ACPI_SUB_DECODE == address32_data->decode ? - "Subtractive" : "Positive"); + ACPI_SUB_DECODE == address32_data->decode ? + "Subtractive" : "Positive"); acpi_os_printf (" Min address is %s fixed\n", - ACPI_ADDRESS_FIXED == address32_data->min_address_fixed ? - "" : "not "); + ACPI_ADDRESS_FIXED == address32_data->min_address_fixed ? + "" : "not "); acpi_os_printf (" Max address is %s fixed\n", - ACPI_ADDRESS_FIXED == address32_data->max_address_fixed ? - "" : "not "); + ACPI_ADDRESS_FIXED == address32_data->max_address_fixed ? + "" : "not "); acpi_os_printf (" Granularity: %08X\n", - address32_data->granularity); + address32_data->granularity); acpi_os_printf (" Address range min: %08X\n", - address32_data->min_address_range); + address32_data->min_address_range); acpi_os_printf (" Address range max: %08X\n", - address32_data->max_address_range); + address32_data->max_address_range); acpi_os_printf (" Address translation offset: %08X\n", - address32_data->address_translation_offset); + address32_data->address_translation_offset); acpi_os_printf (" Address Length: %08X\n", - address32_data->address_length); + address32_data->address_length); if(0xFF != address32_data->resource_source.index) { acpi_os_printf (" Resource Source Index: %X\n", - address32_data->resource_source.index); + address32_data->resource_source.index); + acpi_os_printf (" Resource Source: %s\n", - address32_data->resource_source.string_ptr); + address32_data->resource_source.string_ptr); } return; @@ -789,7 +817,7 @@ acpi_rs_dump_address32 ( * ******************************************************************************/ -void +static void acpi_rs_dump_address64 ( union acpi_resource_data *data) { @@ -808,35 +836,30 @@ acpi_rs_dump_address64 ( switch (address64_data->attribute.memory.cache_attribute) { case ACPI_NON_CACHEABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Noncacheable memory\n"); + acpi_os_printf (" Type Specific: Noncacheable memory\n"); break; case ACPI_CACHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Cacheable memory\n"); + acpi_os_printf (" Type Specific: Cacheable memory\n"); break; case ACPI_WRITE_COMBINING_MEMORY: - acpi_os_printf (" Type Specific: " - "Write-combining memory\n"); + acpi_os_printf (" Type Specific: Write-combining memory\n"); break; case ACPI_PREFETCHABLE_MEMORY: - acpi_os_printf (" Type Specific: " - "Prefetchable memory\n"); + acpi_os_printf (" Type Specific: Prefetchable memory\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid cache attribute\n"); + acpi_os_printf (" Type Specific: Invalid cache attribute\n"); break; } acpi_os_printf (" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == - address64_data->attribute.memory.read_write_attribute ? - "/Write" : " Only"); + address64_data->attribute.memory.read_write_attribute ? + "/Write" : " Only"); break; case ACPI_IO_RANGE: @@ -845,30 +868,26 @@ acpi_rs_dump_address64 ( switch (address64_data->attribute.io.range_attribute) { case ACPI_NON_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "Non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: Non-ISA Io Addresses\n"); break; case ACPI_ISA_ONLY_RANGES: - acpi_os_printf (" Type Specific: " - "ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA Io Addresses\n"); break; case ACPI_ENTIRE_RANGE: - acpi_os_printf (" Type Specific: " - "ISA and non-ISA Io Addresses\n"); + acpi_os_printf (" Type Specific: ISA and non-ISA Io Addresses\n"); break; default: - acpi_os_printf (" Type Specific: " - "Invalid Range attribute"); + acpi_os_printf (" Type Specific: Invalid Range attribute"); break; } acpi_os_printf (" Type Specific: %s Translation\n", ACPI_SPARSE_TRANSLATION == - address64_data->attribute.io.translation_attribute ? - "Sparse" : "Dense"); + address64_data->attribute.io.translation_attribute ? + "Sparse" : "Dense"); break; case ACPI_BUS_NUMBER_RANGE: @@ -878,49 +897,51 @@ acpi_rs_dump_address64 ( default: - acpi_os_printf (" Resource Type: 0x%2.2X\n", address64_data->resource_type); + acpi_os_printf (" Resource Type: 0x%2.2X\n", + address64_data->resource_type); break; } acpi_os_printf (" Resource %s\n", - ACPI_CONSUMER == address64_data->producer_consumer ? - "Consumer" : "Producer"); + ACPI_CONSUMER == address64_data->producer_consumer ? + "Consumer" : "Producer"); acpi_os_printf (" %s decode\n", - ACPI_SUB_DECODE == address64_data->decode ? - "Subtractive" : "Positive"); + ACPI_SUB_DECODE == address64_data->decode ? + "Subtractive" : "Positive"); acpi_os_printf (" Min address is %s fixed\n", - ACPI_ADDRESS_FIXED == address64_data->min_address_fixed ? - "" : "not "); + ACPI_ADDRESS_FIXED == address64_data->min_address_fixed ? + "" : "not "); acpi_os_printf (" Max address is %s fixed\n", - ACPI_ADDRESS_FIXED == address64_data->max_address_fixed ? - "" : "not "); + ACPI_ADDRESS_FIXED == address64_data->max_address_fixed ? + "" : "not "); acpi_os_printf (" Granularity: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->granularity)); + ACPI_FORMAT_UINT64 (address64_data->granularity)); acpi_os_printf (" Address range min: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->min_address_range)); + ACPI_FORMAT_UINT64 (address64_data->min_address_range)); acpi_os_printf (" Address range max: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->max_address_range)); + ACPI_FORMAT_UINT64 (address64_data->max_address_range)); acpi_os_printf (" Address translation offset: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->address_translation_offset)); + ACPI_FORMAT_UINT64 (address64_data->address_translation_offset)); acpi_os_printf (" Address Length: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->address_length)); + ACPI_FORMAT_UINT64 (address64_data->address_length)); acpi_os_printf (" Type Specific Attributes: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (address64_data->type_specific_attributes)); + ACPI_FORMAT_UINT64 (address64_data->type_specific_attributes)); if (0xFF != address64_data->resource_source.index) { acpi_os_printf (" Resource Source Index: %X\n", - address64_data->resource_source.index); + address64_data->resource_source.index); + acpi_os_printf (" Resource Source: %s\n", - address64_data->resource_source.string_ptr); + address64_data->resource_source.string_ptr); } return; @@ -939,7 +960,7 @@ acpi_rs_dump_address64 ( * ******************************************************************************/ -void +static void acpi_rs_dump_extended_irq ( union acpi_resource_data *data) { @@ -953,23 +974,22 @@ acpi_rs_dump_extended_irq ( acpi_os_printf ("Extended IRQ Resource\n"); acpi_os_printf (" Resource %s\n", - ACPI_CONSUMER == ext_irq_data->producer_consumer ? - "Consumer" : "Producer"); + ACPI_CONSUMER == ext_irq_data->producer_consumer ? + "Consumer" : "Producer"); acpi_os_printf (" %s\n", - ACPI_LEVEL_SENSITIVE == ext_irq_data->edge_level ? - "Level" : "Edge"); + ACPI_LEVEL_SENSITIVE == ext_irq_data->edge_level ? + "Level" : "Edge"); acpi_os_printf (" Active %s\n", - ACPI_ACTIVE_LOW == ext_irq_data->active_high_low ? - "low" : "high"); + ACPI_ACTIVE_LOW == ext_irq_data->active_high_low ? + "low" : "high"); acpi_os_printf (" %s\n", - ACPI_SHARED == ext_irq_data->shared_exclusive ? - "Shared" : "Exclusive"); + ACPI_SHARED == ext_irq_data->shared_exclusive ? + "Shared" : "Exclusive"); - acpi_os_printf (" Interrupts : %X ( ", - ext_irq_data->number_of_interrupts); + acpi_os_printf (" Interrupts : %X ( ", ext_irq_data->number_of_interrupts); for (index = 0; index < ext_irq_data->number_of_interrupts; index++) { acpi_os_printf ("%X ", ext_irq_data->interrupts[index]); @@ -979,9 +999,10 @@ acpi_rs_dump_extended_irq ( if(0xFF != ext_irq_data->resource_source.index) { acpi_os_printf (" Resource Source Index: %X", - ext_irq_data->resource_source.index); + ext_irq_data->resource_source.index); + acpi_os_printf (" Resource Source: %s", - ext_irq_data->resource_source.string_ptr); + ext_irq_data->resource_source.string_ptr); } return; @@ -992,7 +1013,7 @@ acpi_rs_dump_extended_irq ( * * FUNCTION: acpi_rs_dump_resource_list * - * PARAMETERS: Data - pointer to the resource structure to dump. + * PARAMETERS: Resource - pointer to the resource structure to dump. * * RETURN: None * @@ -1096,7 +1117,7 @@ acpi_rs_dump_resource_list ( * * FUNCTION: acpi_rs_dump_irq_list * - * PARAMETERS: Data - pointer to the routing table to dump. + * PARAMETERS: route_table - pointer to the routing table to dump. * * RETURN: None * @@ -1124,20 +1145,17 @@ acpi_rs_dump_irq_list ( acpi_os_printf ("PCI IRQ Routing Table structure %X.\n", count++); acpi_os_printf (" Address: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64 (prt_element->address)); + ACPI_FORMAT_UINT64 (prt_element->address)); acpi_os_printf (" Pin: %X\n", prt_element->pin); acpi_os_printf (" Source: %s\n", prt_element->source); - acpi_os_printf (" source_index: %X\n", - prt_element->source_index); + acpi_os_printf (" source_index: %X\n", prt_element->source_index); buffer += prt_element->length; - prt_element = ACPI_CAST_PTR (struct acpi_pci_routing_table, buffer); - - if(0 == prt_element->length) { + if (0 == prt_element->length) { done = TRUE; } } diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c index 972c746d37e..23a4d149fac 100644 --- a/drivers/acpi/resources/rsio.c +++ b/drivers/acpi/resources/rsio.c @@ -81,67 +81,60 @@ acpi_rs_io_resource ( struct acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_io); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_io); ACPI_FUNCTION_TRACE ("rs_io_resource"); - /* - * The number of bytes consumed are Constant - */ + /* The number of bytes consumed are Constant */ + *bytes_consumed = 8; output_struct->id = ACPI_RSTYPE_IO; - /* - * Check Decode - */ + /* Check Decode */ + buffer += 1; temp8 = *buffer; output_struct->data.io.io_decode = temp8 & 0x01; - /* - * Check min_base Address - */ + /* Check min_base Address */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); output_struct->data.io.min_base_address = temp16; - /* - * Check max_base Address - */ + /* Check max_base Address */ + buffer += 2; ACPI_MOVE_16_TO_16 (&temp16, buffer); output_struct->data.io.max_base_address = temp16; - /* - * Check Base alignment - */ + /* Check Base alignment */ + buffer += 2; temp8 = *buffer; output_struct->data.io.alignment = temp8; - /* - * Check range_length - */ + /* Check range_length */ + buffer += 1; temp8 = *buffer; output_struct->data.io.range_length = temp8; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -179,43 +172,39 @@ acpi_rs_fixed_io_resource ( struct acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_io); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_fixed_io); ACPI_FUNCTION_TRACE ("rs_fixed_io_resource"); - /* - * The number of bytes consumed are Constant - */ + /* The number of bytes consumed are Constant */ + *bytes_consumed = 4; output_struct->id = ACPI_RSTYPE_FIXED_IO; - /* - * Check Range Base Address - */ + /* Check Range Base Address */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); output_struct->data.fixed_io.base_address = temp16; - /* - * Check range_length - */ + /* Check range_length */ + buffer += 2; temp8 = *buffer; output_struct->data.fixed_io.range_length = temp8; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -251,55 +240,48 @@ acpi_rs_io_stream ( ACPI_FUNCTION_TRACE ("rs_io_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x47; buffer += 1; - /* - * Io Information Byte - */ + /* Io Information Byte */ + temp8 = (u8) (linked_list->data.io.io_decode & 0x01); *buffer = temp8; buffer += 1; - /* - * Set the Range minimum base address - */ + /* Set the Range minimum base address */ + temp16 = (u16) linked_list->data.io.min_base_address; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the Range maximum base address - */ + /* Set the Range maximum base address */ + temp16 = (u16) linked_list->data.io.max_base_address; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the base alignment - */ + /* Set the base alignment */ + temp8 = (u8) linked_list->data.io.alignment; *buffer = temp8; buffer += 1; - /* - * Set the range length - */ + /* Set the range length */ + temp8 = (u8) linked_list->data.io.range_length; *buffer = temp8; buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -335,32 +317,28 @@ acpi_rs_fixed_io_stream ( ACPI_FUNCTION_TRACE ("rs_fixed_io_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x4B; buffer += 1; - /* - * Set the Range base address - */ + /* Set the Range base address */ + temp16 = (u16) linked_list->data.fixed_io.base_address; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the range length - */ + /* Set the range length */ + temp8 = (u8) linked_list->data.fixed_io.range_length; *buffer = temp8; buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -399,21 +377,20 @@ acpi_rs_dma_resource ( u8 temp8 = 0; u8 index; u8 i; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_dma); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_dma); ACPI_FUNCTION_TRACE ("rs_dma_resource"); - /* - * The number of bytes consumed are Constant - */ + /* The number of bytes consumed are Constant */ + *bytes_consumed = 3; output_struct->id = ACPI_RSTYPE_DMA; - /* - * Point to the 8-bits of Byte 1 - */ + /* Point to the 8-bits of Byte 1 */ + buffer += 1; temp8 = *buffer; @@ -430,46 +407,40 @@ acpi_rs_dma_resource ( output_struct->data.dma.number_of_channels = i; if (i > 0) { - /* - * Calculate the structure size based upon the number of interrupts - */ + /* Calculate the structure size based upon the number of interrupts */ + struct_size += ((acpi_size) i - 1) * 4; } - /* - * Point to Byte 2 - */ + /* Point to Byte 2 */ + buffer += 1; temp8 = *buffer; - /* - * Check for transfer preference (Bits[1:0]) - */ + /* Check for transfer preference (Bits[1:0]) */ + output_struct->data.dma.transfer = temp8 & 0x03; if (0x03 == output_struct->data.dma.transfer) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid DMA.Transfer preference (3)\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Invalid DMA.Transfer preference (3)\n")); return_ACPI_STATUS (AE_BAD_DATA); } - /* - * Get bus master preference (Bit[2]) - */ + /* Get bus master preference (Bit[2]) */ + output_struct->data.dma.bus_master = (temp8 >> 2) & 0x01; - /* - * Get channel speed support (Bits[6:5]) - */ + /* Get channel speed support (Bits[6:5]) */ + output_struct->data.dma.type = (temp8 >> 5) & 0x03; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -506,16 +477,14 @@ acpi_rs_dma_stream ( ACPI_FUNCTION_TRACE ("rs_dma_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x2A; buffer += 1; temp8 = 0; - /* - * Loop through all of the Channels and set the mask bits - */ + /* Loop through all of the Channels and set the mask bits */ + for (index = 0; index < linked_list->data.dma.number_of_channels; index++) { @@ -526,9 +495,8 @@ acpi_rs_dma_stream ( *buffer = temp8; buffer += 1; - /* - * Set the DMA Info - */ + /* Set the DMA Info */ + temp8 = (u8) ((linked_list->data.dma.type & 0x03) << 5); temp8 |= ((linked_list->data.dma.bus_master & 0x01) << 2); temp8 |= (linked_list->data.dma.transfer & 0x03); @@ -536,9 +504,8 @@ acpi_rs_dma_stream ( *buffer = temp8; buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c index fd07a8702fb..8a2b630be45 100644 --- a/drivers/acpi/resources/rsirq.c +++ b/drivers/acpi/resources/rsirq.c @@ -83,7 +83,8 @@ acpi_rs_irq_resource ( u8 temp8 = 0; u8 index; u8 i; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_irq); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_irq); ACPI_FUNCTION_TRACE ("rs_irq_resource"); @@ -91,15 +92,14 @@ acpi_rs_irq_resource ( /* * The number of bytes consumed are contained in the descriptor - * (Bits:0-1) + * (Bits:0-1) */ temp8 = *buffer; *bytes_consumed = (temp8 & 0x03) + 1; output_struct->id = ACPI_RSTYPE_IRQ; - /* - * Point to the 16-bits of Bytes 1 and 2 - */ + /* Point to the 16-bits of Bytes 1 and 2 */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -118,22 +118,19 @@ acpi_rs_irq_resource ( output_struct->data.irq.number_of_interrupts = i; if (i > 0) { - /* - * Calculate the structure size based upon the number of interrupts - */ + /* Calculate the structure size based upon the number of interrupts */ + struct_size += ((acpi_size) i - 1) * 4; } - /* - * Point to Byte 3 if it is used - */ + /* Point to Byte 3 if it is used */ + if (4 == *bytes_consumed) { buffer += 2; temp8 = *buffer; - /* - * Check for HE, LL interrupts - */ + /* Check for HE, LL interrupts */ + switch (temp8 & 0x09) { case 0x01: /* HE */ output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE; @@ -152,13 +149,13 @@ acpi_rs_irq_resource ( * so 0x00 and 0x09 are illegal. */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Invalid interrupt polarity/trigger in resource list, %X\n", temp8)); + "Invalid interrupt polarity/trigger in resource list, %X\n", + temp8)); return_ACPI_STATUS (AE_BAD_DATA); } - /* - * Check for sharable - */ + /* Check for sharable */ + output_struct->data.irq.shared_exclusive = (temp8 >> 3) & 0x01; } else { @@ -171,14 +168,12 @@ acpi_rs_irq_resource ( output_struct->data.irq.shared_exclusive = ACPI_EXCLUSIVE; } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -234,9 +229,8 @@ acpi_rs_irq_stream ( buffer += 1; temp16 = 0; - /* - * Loop through all of the interrupts and set the mask bits - */ + /* Loop through all of the interrupts and set the mask bits */ + for(index = 0; index < linked_list->data.irq.number_of_interrupts; index++) { @@ -247,9 +241,8 @@ acpi_rs_irq_stream ( ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the IRQ Info byte if needed. - */ + /* Set the IRQ Info byte if needed. */ + if (IRqinfo_byte_needed) { temp8 = 0; temp8 = (u8) ((linked_list->data.irq.shared_exclusive & @@ -267,9 +260,8 @@ acpi_rs_irq_stream ( buffer += 1; } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -309,15 +301,15 @@ acpi_rs_extended_irq_resource ( u8 temp8 = 0; u8 *temp_ptr; u8 index; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_ext_irq); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_ext_irq); ACPI_FUNCTION_TRACE ("rs_extended_irq_resource"); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -330,9 +322,8 @@ acpi_rs_extended_irq_resource ( *bytes_consumed = temp16 + 3; output_struct->id = ACPI_RSTYPE_EXT_IRQ; - /* - * Point to the Byte3 - */ + /* Point to the Byte3 */ + buffer += 2; temp8 = *buffer; @@ -347,21 +338,18 @@ acpi_rs_extended_irq_resource ( * - Edge/Level are defined opposite in the table vs the headers */ output_struct->data.extended_irq.edge_level = - (temp8 & 0x2) ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; + (temp8 & 0x2) ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; + + /* Check Interrupt Polarity */ - /* - * Check Interrupt Polarity - */ output_struct->data.extended_irq.active_high_low = (temp8 >> 2) & 0x1; - /* - * Check for sharable - */ + /* Check for sharable */ + output_struct->data.extended_irq.shared_exclusive = (temp8 >> 3) & 0x01; - /* - * Point to Byte4 (IRQ Table length) - */ + /* Point to Byte4 (IRQ Table length) */ + buffer += 1; temp8 = *buffer; @@ -379,14 +367,12 @@ acpi_rs_extended_irq_resource ( */ struct_size += (temp8 - 1) * 4; - /* - * Point to Byte5 (First IRQ Number) - */ + /* Point to Byte5 (First IRQ Number) */ + buffer += 1; - /* - * Cycle through every IRQ in the table - */ + /* Cycle through every IRQ in the table */ + for (index = 0; index < temp8; index++) { ACPI_MOVE_32_TO_32 ( &output_struct->data.extended_irq.interrupts[index], buffer); @@ -407,7 +393,8 @@ acpi_rs_extended_irq_resource ( * we add 1 to the length. */ if (*bytes_consumed > - ((acpi_size) output_struct->data.extended_irq.number_of_interrupts * 4) + (5 + 1)) { + ((acpi_size) output_struct->data.extended_irq.number_of_interrupts * 4) + + (5 + 1)) { /* Dereference the Index */ temp8 = *buffer; @@ -417,13 +404,13 @@ acpi_rs_extended_irq_resource ( buffer += 1; - /* - * Point the String pointer to the end of this structure. - */ + /* Point the String pointer to the end of this structure. */ + output_struct->data.extended_irq.resource_source.string_ptr = (char *)((char *) output_struct + struct_size); - temp_ptr = (u8 *) output_struct->data.extended_irq.resource_source.string_ptr; + temp_ptr = (u8 *) + output_struct->data.extended_irq.resource_source.string_ptr; /* Copy the string into the buffer */ @@ -436,9 +423,8 @@ acpi_rs_extended_irq_resource ( index += 1; } - /* - * Add the terminating null - */ + /* Add the terminating null */ + *temp_ptr = 0x00; output_struct->data.extended_irq.resource_source.string_length = index + 1; @@ -456,14 +442,12 @@ acpi_rs_extended_irq_resource ( output_struct->data.extended_irq.resource_source.string_ptr = NULL; } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -501,21 +485,18 @@ acpi_rs_extended_irq_stream ( ACPI_FUNCTION_TRACE ("rs_extended_irq_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x89; buffer += 1; - /* - * Set a pointer to the Length field - to be filled in later - */ + /* Set a pointer to the Length field - to be filled in later */ + length_field = ACPI_CAST_PTR (u16, buffer); buffer += 2; - /* - * Set the Interrupt vector flags - */ + /* Set the Interrupt vector flags */ + temp8 = (u8)(linked_list->data.extended_irq.producer_consumer & 0x01); temp8 |= ((linked_list->data.extended_irq.shared_exclusive & 0x01) << 3); @@ -532,17 +513,15 @@ acpi_rs_extended_irq_stream ( temp8 |= 0x2; } - /* - * Set the Interrupt Polarity - */ + /* Set the Interrupt Polarity */ + temp8 |= ((linked_list->data.extended_irq.active_high_low & 0x1) << 2); *buffer = temp8; buffer += 1; - /* - * Set the Interrupt table length - */ + /* Set the Interrupt table length */ + temp8 = (u8) linked_list->data.extended_irq.number_of_interrupts; *buffer = temp8; @@ -555,18 +534,16 @@ acpi_rs_extended_irq_stream ( buffer += 4; } - /* - * Resource Source Index and Resource Source are optional - */ + /* Resource Source Index and Resource Source are optional */ + if (0 != linked_list->data.extended_irq.resource_source.string_length) { *buffer = (u8) linked_list->data.extended_irq.resource_source.index; buffer += 1; temp_pointer = (char *) buffer; - /* - * Copy the string - */ + /* Copy the string */ + ACPI_STRCPY (temp_pointer, linked_list->data.extended_irq.resource_source.string_ptr); @@ -574,12 +551,12 @@ acpi_rs_extended_irq_stream ( * Buffer needs to be set to the length of the sting + one for the * terminating null */ - buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.extended_irq.resource_source.string_ptr) + 1); + buffer += (acpi_size) (ACPI_STRLEN ( + linked_list->data.extended_irq.resource_source.string_ptr) + 1); } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); /* diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index e49c1e030f9..db7bcb4e60e 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -55,7 +55,7 @@ * * PARAMETERS: resource_start_byte - Byte 0 of a resource descriptor * - * RETURN: The Resource Type (Name) with no extraneous bits + * RETURN: The Resource Type with no extraneous bits * * DESCRIPTION: Extract the Resource Type/Name from the first byte of * a resource descriptor. @@ -70,28 +70,25 @@ acpi_rs_get_resource_type ( ACPI_FUNCTION_ENTRY (); - /* - * Determine if this is a small or large resource - */ + /* Determine if this is a small or large resource */ + switch (resource_start_byte & ACPI_RDESC_TYPE_MASK) { case ACPI_RDESC_TYPE_SMALL: - /* - * Small Resource Type -- Only bits 6:3 are valid - */ + /* Small Resource Type -- Only bits 6:3 are valid */ + return ((u8) (resource_start_byte & ACPI_RDESC_SMALL_MASK)); case ACPI_RDESC_TYPE_LARGE: - /* - * Large Resource Type -- All bits are valid - */ + /* Large Resource Type -- All bits are valid */ + return (resource_start_byte); default: - /* No other types of resource descriptor */ + /* Invalid type */ break; } @@ -135,9 +132,8 @@ acpi_rs_byte_stream_to_list ( while (bytes_parsed < byte_stream_buffer_length && !end_tag_processed) { - /* - * The next byte in the stream is the resource type - */ + /* The next byte in the stream is the resource type */ + resource_type = acpi_rs_get_resource_type (*byte_stream_buffer); switch (resource_type) { @@ -299,28 +295,23 @@ acpi_rs_byte_stream_to_list ( return_ACPI_STATUS (status); } - /* - * Update the return value and counter - */ + /* Update the return value and counter */ + bytes_parsed += bytes_consumed; - /* - * Set the byte stream to point to the next resource - */ + /* Set the byte stream to point to the next resource */ + byte_stream_buffer += bytes_consumed; - /* - * Set the Buffer to the next structure - */ + /* Set the Buffer to the next structure */ + resource = ACPI_CAST_PTR (struct acpi_resource, buffer); resource->length = (u32) ACPI_ALIGN_RESOURCE_SIZE (resource->length); buffer += ACPI_ALIGN_RESOURCE_SIZE (structure_size); + } - } /* end while */ + /* Check the reason for exiting the while loop */ - /* - * Check the reason for exiting the while loop - */ if (!end_tag_processed) { return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); } @@ -424,9 +415,8 @@ acpi_rs_list_to_byte_stream ( */ status = acpi_rs_end_tag_stream (linked_list, &buffer, &bytes_consumed); - /* - * An End Tag indicates the end of the Resource Template - */ + /* An End Tag indicates the end of the Resource Template */ + done = TRUE; break; @@ -488,27 +478,25 @@ acpi_rs_list_to_byte_stream ( default: /* * If we get here, everything is out of sync, - * so exit with an error + * so exit with an error */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid descriptor type (%X) in resource list\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Invalid descriptor type (%X) in resource list\n", linked_list->id)); status = AE_BAD_DATA; break; - - } /* switch (linked_list->Id) */ + } if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - /* - * Set the Buffer to point to the open byte - */ + /* Set the Buffer to point to the open byte */ + buffer += bytes_consumed; - /* - * Point to the next object - */ + /* Point to the next object */ + linked_list = ACPI_PTR_ADD (struct acpi_resource, linked_list, linked_list->length); } diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c index 7c935aecf07..91d0207f01a 100644 --- a/drivers/acpi/resources/rsmemory.c +++ b/drivers/acpi/resources/rsmemory.c @@ -81,15 +81,15 @@ acpi_rs_memory24_resource ( struct acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem24); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_mem24); ACPI_FUNCTION_TRACE ("rs_memory24_resource"); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -97,48 +97,41 @@ acpi_rs_memory24_resource ( *bytes_consumed = (acpi_size) temp16 + 3; output_struct->id = ACPI_RSTYPE_MEM24; - /* - * Check Byte 3 the Read/Write bit - */ + /* Check Byte 3 the Read/Write bit */ + temp8 = *buffer; buffer += 1; output_struct->data.memory24.read_write_attribute = temp8 & 0x01; - /* - * Get min_base_address (Bytes 4-5) - */ + /* Get min_base_address (Bytes 4-5) */ + ACPI_MOVE_16_TO_16 (&temp16, buffer); buffer += 2; output_struct->data.memory24.min_base_address = temp16; - /* - * Get max_base_address (Bytes 6-7) - */ + /* Get max_base_address (Bytes 6-7) */ + ACPI_MOVE_16_TO_16 (&temp16, buffer); buffer += 2; output_struct->data.memory24.max_base_address = temp16; - /* - * Get Alignment (Bytes 8-9) - */ + /* Get Alignment (Bytes 8-9) */ + ACPI_MOVE_16_TO_16 (&temp16, buffer); buffer += 2; output_struct->data.memory24.alignment = temp16; - /* - * Get range_length (Bytes 10-11) - */ + /* Get range_length (Bytes 10-11) */ + ACPI_MOVE_16_TO_16 (&temp16, buffer); output_struct->data.memory24.range_length = temp16; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -174,53 +167,45 @@ acpi_rs_memory24_stream ( ACPI_FUNCTION_TRACE ("rs_memory24_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x81; buffer += 1; - /* - * The length field is static - */ + /* The length field is static */ + temp16 = 0x09; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the Information Byte - */ + /* Set the Information Byte */ + temp8 = (u8) (linked_list->data.memory24.read_write_attribute & 0x01); *buffer = temp8; buffer += 1; - /* - * Set the Range minimum base address - */ + /* Set the Range minimum base address */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.min_base_address); buffer += 2; - /* - * Set the Range maximum base address - */ + /* Set the Range maximum base address */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.max_base_address); buffer += 2; - /* - * Set the base alignment - */ + /* Set the base alignment */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.alignment); buffer += 2; - /* - * Set the range length - */ + /* Set the range length */ + ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.range_length); buffer += 2; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -258,15 +243,15 @@ acpi_rs_memory32_range_resource ( struct acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem32); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_mem32); ACPI_FUNCTION_TRACE ("rs_memory32_range_resource"); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -285,45 +270,38 @@ acpi_rs_memory32_range_resource ( * 4 * sizeof(RESOURCE_DATA) instead of 4 * sizeof(u8) */ - /* - * Check Byte 3 the Read/Write bit - */ + /* Check Byte 3 the Read/Write bit */ + temp8 = *buffer; buffer += 1; output_struct->data.memory32.read_write_attribute = temp8 & 0x01; - /* - * Get min_base_address (Bytes 4-7) - */ + /* Get min_base_address (Bytes 4-7) */ + ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.min_base_address, buffer); buffer += 4; - /* - * Get max_base_address (Bytes 8-11) - */ + /* Get max_base_address (Bytes 8-11) */ + ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.max_base_address, buffer); buffer += 4; - /* - * Get Alignment (Bytes 12-15) - */ + /* Get Alignment (Bytes 12-15) */ + ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.alignment, buffer); buffer += 4; - /* - * Get range_length (Bytes 16-19) - */ + /* Get range_length (Bytes 16-19) */ + ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.range_length, buffer); - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -361,15 +339,15 @@ acpi_rs_fixed_memory32_resource ( struct acpi_resource *output_struct = (void *) *output_buffer; u16 temp16 = 0; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_mem32); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_fixed_mem32); ACPI_FUNCTION_TRACE ("rs_fixed_memory32_resource"); - /* - * Point past the Descriptor to get the number of bytes consumed - */ + /* Point past the Descriptor to get the number of bytes consumed */ + buffer += 1; ACPI_MOVE_16_TO_16 (&temp16, buffer); @@ -378,32 +356,28 @@ acpi_rs_fixed_memory32_resource ( output_struct->id = ACPI_RSTYPE_FIXED_MEM32; - /* - * Check Byte 3 the Read/Write bit - */ + /* Check Byte 3 the Read/Write bit */ + temp8 = *buffer; buffer += 1; output_struct->data.fixed_memory32.read_write_attribute = temp8 & 0x01; - /* - * Get range_base_address (Bytes 4-7) - */ - ACPI_MOVE_32_TO_32 (&output_struct->data.fixed_memory32.range_base_address, buffer); + /* Get range_base_address (Bytes 4-7) */ + + ACPI_MOVE_32_TO_32 (&output_struct->data.fixed_memory32.range_base_address, + buffer); buffer += 4; - /* - * Get range_length (Bytes 8-11) - */ + /* Get range_length (Bytes 8-11) */ + ACPI_MOVE_32_TO_32 (&output_struct->data.fixed_memory32.range_length, buffer); - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -439,54 +413,46 @@ acpi_rs_memory32_range_stream ( ACPI_FUNCTION_TRACE ("rs_memory32_range_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x85; buffer += 1; - /* - * The length field is static - */ + /* The length field is static */ + temp16 = 0x11; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the Information Byte - */ + /* Set the Information Byte */ + temp8 = (u8) (linked_list->data.memory32.read_write_attribute & 0x01); *buffer = temp8; buffer += 1; - /* - * Set the Range minimum base address - */ + /* Set the Range minimum base address */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.min_base_address); buffer += 4; - /* - * Set the Range maximum base address - */ + /* Set the Range maximum base address */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.max_base_address); buffer += 4; - /* - * Set the base alignment - */ + /* Set the base alignment */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.alignment); buffer += 4; - /* - * Set the range length - */ + /* Set the range length */ + ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.range_length); buffer += 4; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -522,44 +488,38 @@ acpi_rs_fixed_memory32_stream ( ACPI_FUNCTION_TRACE ("rs_fixed_memory32_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x86; buffer += 1; - /* - * The length field is static - */ + /* The length field is static */ + temp16 = 0x09; ACPI_MOVE_16_TO_16 (buffer, &temp16); buffer += 2; - /* - * Set the Information Byte - */ + /* Set the Information Byte */ + temp8 = (u8) (linked_list->data.fixed_memory32.read_write_attribute & 0x01); *buffer = temp8; buffer += 1; - /* - * Set the Range base address - */ + /* Set the Range base address */ + ACPI_MOVE_32_TO_32 (buffer, - &linked_list->data.fixed_memory32.range_base_address); + &linked_list->data.fixed_memory32.range_base_address); buffer += 4; - /* - * Set the range length - */ + /* Set the range length */ + ACPI_MOVE_32_TO_32 (buffer, - &linked_list->data.fixed_memory32.range_length); + &linked_list->data.fixed_memory32.range_length); buffer += 4; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c index d16be44b5df..a1f1741f0d8 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/resources/rsmisc.c @@ -84,24 +84,20 @@ acpi_rs_end_tag_resource ( ACPI_FUNCTION_TRACE ("rs_end_tag_resource"); - /* - * The number of bytes consumed is static - */ + /* The number of bytes consumed is static */ + *bytes_consumed = 2; - /* - * Fill out the structure - */ + /* Fill out the structure */ + output_struct->id = ACPI_RSTYPE_END_TAG; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = 0; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -136,9 +132,8 @@ acpi_rs_end_tag_stream ( ACPI_FUNCTION_TRACE ("rs_end_tag_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x79; buffer += 1; @@ -151,9 +146,8 @@ acpi_rs_end_tag_stream ( *buffer = temp8; buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -192,21 +186,20 @@ acpi_rs_vendor_resource ( u16 temp16 = 0; u8 temp8 = 0; u8 index; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_vendor); ACPI_FUNCTION_TRACE ("rs_vendor_resource"); - /* - * Dereference the Descriptor to find if this is a large or small item. - */ + /* Dereference the Descriptor to find if this is a large or small item. */ + temp8 = *buffer; if (temp8 & 0x80) { - /* - * Large Item, point to the length field - */ + /* Large Item, point to the length field */ + buffer += 1; /* Dereference */ @@ -222,9 +215,8 @@ acpi_rs_vendor_resource ( buffer += 2; } else { - /* - * Small Item, dereference the size - */ + /* Small Item, dereference the size */ + temp16 = (u8)(*buffer & 0x07); /* Calculate bytes consumed */ @@ -251,14 +243,12 @@ acpi_rs_vendor_resource ( */ struct_size += ACPI_ROUND_UP_to_32_bITS (temp16); - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -295,13 +285,11 @@ acpi_rs_vendor_stream ( ACPI_FUNCTION_TRACE ("rs_vendor_stream"); - /* - * Dereference the length to find if this is a large or small item. - */ + /* Dereference the length to find if this is a large or small item. */ + if(linked_list->data.vendor_specific.length > 7) { - /* - * Large Item, Set the descriptor field and length bytes - */ + /* Large Item, Set the descriptor field and length bytes */ + *buffer = 0x84; buffer += 1; @@ -311,9 +299,8 @@ acpi_rs_vendor_stream ( buffer += 2; } else { - /* - * Small Item, Set the descriptor field - */ + /* Small Item, Set the descriptor field */ + temp8 = 0x70; temp8 |= (u8) linked_list->data.vendor_specific.length; @@ -321,9 +308,8 @@ acpi_rs_vendor_stream ( buffer += 1; } - /* - * Loop through all of the Vendor Specific fields - */ + /* Loop through all of the Vendor Specific fields */ + for (index = 0; index < linked_list->data.vendor_specific.length; index++) { temp8 = linked_list->data.vendor_specific.reserved[index]; @@ -331,9 +317,8 @@ acpi_rs_vendor_stream ( buffer += 1; } - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -370,40 +355,37 @@ acpi_rs_start_depend_fns_resource ( u8 *buffer = byte_stream_buffer; struct acpi_resource *output_struct = (void *) *output_buffer; u8 temp8 = 0; - acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_start_dpf); + acpi_size struct_size = ACPI_SIZEOF_RESOURCE ( + struct acpi_resource_start_dpf); ACPI_FUNCTION_TRACE ("rs_start_depend_fns_resource"); - /* - * The number of bytes consumed are contained in the descriptor (Bits:0-1) - */ + /* The number of bytes consumed are found in the descriptor (Bits:0-1) */ + temp8 = *buffer; *bytes_consumed = (temp8 & 0x01) + 1; output_struct->id = ACPI_RSTYPE_START_DPF; - /* - * Point to Byte 1 if it is used - */ + /* Point to Byte 1 if it is used */ + if (2 == *bytes_consumed) { buffer += 1; temp8 = *buffer; - /* - * Check Compatibility priority - */ + /* Check Compatibility priority */ + output_struct->data.start_dpf.compatibility_priority = temp8 & 0x03; if (3 == output_struct->data.start_dpf.compatibility_priority) { return_ACPI_STATUS (AE_AML_BAD_RESOURCE_VALUE); } - /* - * Check Performance/Robustness preference - */ + /* Check Performance/Robustness preference */ + output_struct->data.start_dpf.performance_robustness = (temp8 >> 2) & 0x03; if (3 == output_struct->data.start_dpf.performance_robustness) { @@ -412,20 +394,18 @@ acpi_rs_start_depend_fns_resource ( } else { output_struct->data.start_dpf.compatibility_priority = - ACPI_ACCEPTABLE_CONFIGURATION; + ACPI_ACCEPTABLE_CONFIGURATION; output_struct->data.start_dpf.performance_robustness = - ACPI_ACCEPTABLE_CONFIGURATION; + ACPI_ACCEPTABLE_CONFIGURATION; } - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -466,24 +446,20 @@ acpi_rs_end_depend_fns_resource ( ACPI_FUNCTION_TRACE ("rs_end_depend_fns_resource"); - /* - * The number of bytes consumed is static - */ + /* The number of bytes consumed is static */ + *bytes_consumed = 1; - /* - * Fill out the structure - */ + /* Fill out the structure */ + output_struct->id = ACPI_RSTYPE_END_DPF; - /* - * Set the Length parameter - */ + /* Set the Length parameter */ + output_struct->length = (u32) struct_size; - /* - * Return the final size of the structure - */ + /* Return the final size of the structure */ + *structure_size = struct_size; return_ACPI_STATUS (AE_OK); } @@ -533,9 +509,8 @@ acpi_rs_start_depend_fns_stream ( *buffer = 0x31; buffer += 1; - /* - * Set the Priority Byte Definition - */ + /* Set the Priority Byte Definition */ + temp8 = 0; temp8 = (u8) ((linked_list->data.start_dpf.performance_robustness & 0x03) << 2); @@ -546,9 +521,8 @@ acpi_rs_start_depend_fns_stream ( buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } @@ -582,15 +556,13 @@ acpi_rs_end_depend_fns_stream ( ACPI_FUNCTION_TRACE ("rs_end_depend_fns_stream"); - /* - * The descriptor field is static - */ + /* The descriptor field is static */ + *buffer = 0x38; buffer += 1; - /* - * Return the number of bytes consumed in this operation - */ + /* Return the number of bytes consumed in this operation */ + *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer); return_ACPI_STATUS (AE_OK); } diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index ee9ce13c053..700cf7d65d7 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -83,10 +83,10 @@ acpi_rs_get_prt_method_data ( /* Parameters guaranteed valid by caller */ - /* - * Execute the method, no parameters - */ - status = acpi_ut_evaluate_object (handle, "_PRT", ACPI_BTYPE_PACKAGE, &obj_desc); + /* Execute the method, no parameters */ + + status = acpi_ut_evaluate_object (handle, METHOD_NAME__PRT, + ACPI_BTYPE_PACKAGE, &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -136,10 +136,10 @@ acpi_rs_get_crs_method_data ( /* Parameters guaranteed valid by caller */ - /* - * Execute the method, no parameters - */ - status = acpi_ut_evaluate_object (handle, "_CRS", ACPI_BTYPE_BUFFER, &obj_desc); + /* Execute the method, no parameters */ + + status = acpi_ut_evaluate_object (handle, METHOD_NAME__CRS, + ACPI_BTYPE_BUFFER, &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -175,6 +175,7 @@ acpi_rs_get_crs_method_data ( * and the contents of the callers buffer is undefined. * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_rs_get_prs_method_data ( @@ -190,10 +191,10 @@ acpi_rs_get_prs_method_data ( /* Parameters guaranteed valid by caller */ - /* - * Execute the method, no parameters - */ - status = acpi_ut_evaluate_object (handle, "_PRS", ACPI_BTYPE_BUFFER, &obj_desc); + /* Execute the method, no parameters */ + + status = acpi_ut_evaluate_object (handle, METHOD_NAME__PRS, + ACPI_BTYPE_BUFFER, &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -218,6 +219,7 @@ acpi_rs_get_prs_method_data ( * FUNCTION: acpi_rs_get_method_data * * PARAMETERS: Handle - a handle to the containing object + * Path - Path to method, relative to Handle * ret_buffer - a pointer to a buffer structure for the * results * @@ -246,9 +248,8 @@ acpi_rs_get_method_data ( /* Parameters guaranteed valid by caller */ - /* - * Execute the method, no parameters - */ + /* Execute the method, no parameters */ + status = acpi_ut_evaluate_object (handle, path, ACPI_BTYPE_BUFFER, &obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -314,18 +315,16 @@ acpi_rs_set_srs_method_data ( return_ACPI_STATUS (status); } - /* - * Init the param object - */ + /* Init the param object */ + params[0] = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); if (!params[0]) { acpi_os_free (buffer.pointer); return_ACPI_STATUS (AE_NO_MEMORY); } - /* - * Set up the parameter object - */ + /* Set up the parameter object */ + params[0]->buffer.length = (u32) buffer.length; params[0]->buffer.pointer = buffer.pointer; params[0]->common.flags = AOPOBJ_DATA_VALID; @@ -335,10 +334,9 @@ acpi_rs_set_srs_method_data ( info.parameters = params; info.parameter_type = ACPI_PARAM_ARGS; - /* - * Execute the method, no return value - */ - status = acpi_ns_evaluate_relative ("_SRS", &info); + /* Execute the method, no return value */ + + status = acpi_ns_evaluate_relative (METHOD_NAME__SRS, &info); if (ACPI_SUCCESS (status)) { /* Delete any return object (especially if implicit_return is enabled) */ @@ -347,9 +345,8 @@ acpi_rs_set_srs_method_data ( } } - /* - * Clean up and return the status from acpi_ns_evaluate_relative - */ + /* Clean up and return the status from acpi_ns_evaluate_relative */ + acpi_ut_remove_reference (params[0]); return_ACPI_STATUS (status); } diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index a9cdcbeb343..83c944b8b09 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -49,6 +49,23 @@ #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME ("rsxface") +/* Local macros for 16,32-bit to 64-bit conversion */ + +#define ACPI_COPY_FIELD(out, in, field) ((out)->field = (in)->field) +#define ACPI_COPY_ADDRESS(out, in) \ + ACPI_COPY_FIELD(out, in, resource_type); \ + ACPI_COPY_FIELD(out, in, producer_consumer); \ + ACPI_COPY_FIELD(out, in, decode); \ + ACPI_COPY_FIELD(out, in, min_address_fixed); \ + ACPI_COPY_FIELD(out, in, max_address_fixed); \ + ACPI_COPY_FIELD(out, in, attribute); \ + ACPI_COPY_FIELD(out, in, granularity); \ + ACPI_COPY_FIELD(out, in, min_address_range); \ + ACPI_COPY_FIELD(out, in, max_address_range); \ + ACPI_COPY_FIELD(out, in, address_translation_offset); \ + ACPI_COPY_FIELD(out, in, address_length); \ + ACPI_COPY_FIELD(out, in, resource_source); + /******************************************************************************* * @@ -180,6 +197,7 @@ EXPORT_SYMBOL(acpi_get_current_resources); * and the value of ret_buffer is undefined. * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_possible_resources ( @@ -346,9 +364,8 @@ acpi_set_current_resources ( ACPI_FUNCTION_TRACE ("acpi_set_current_resources"); - /* - * Must have a valid handle and buffer - */ + /* Must have a valid handle and buffer */ + if ((!device_handle) || (!in_buffer) || (!in_buffer->pointer) || @@ -362,21 +379,6 @@ acpi_set_current_resources ( EXPORT_SYMBOL(acpi_set_current_resources); -#define ACPI_COPY_FIELD(out, in, field) ((out)->field = (in)->field) -#define ACPI_COPY_ADDRESS(out, in) \ - ACPI_COPY_FIELD(out, in, resource_type); \ - ACPI_COPY_FIELD(out, in, producer_consumer); \ - ACPI_COPY_FIELD(out, in, decode); \ - ACPI_COPY_FIELD(out, in, min_address_fixed); \ - ACPI_COPY_FIELD(out, in, max_address_fixed); \ - ACPI_COPY_FIELD(out, in, attribute); \ - ACPI_COPY_FIELD(out, in, granularity); \ - ACPI_COPY_FIELD(out, in, min_address_range); \ - ACPI_COPY_FIELD(out, in, max_address_range); \ - ACPI_COPY_FIELD(out, in, address_translation_offset); \ - ACPI_COPY_FIELD(out, in, address_length); \ - ACPI_COPY_FIELD(out, in, resource_source); - /****************************************************************************** * * FUNCTION: acpi_resource_to_address64 @@ -408,14 +410,14 @@ acpi_resource_to_address64 ( case ACPI_RSTYPE_ADDRESS16: address16 = (struct acpi_resource_address16 *) &resource->data; - ACPI_COPY_ADDRESS(out, address16); + ACPI_COPY_ADDRESS (out, address16); break; case ACPI_RSTYPE_ADDRESS32: address32 = (struct acpi_resource_address32 *) &resource->data; - ACPI_COPY_ADDRESS(out, address32); + ACPI_COPY_ADDRESS (out, address32); break; @@ -434,4 +436,3 @@ acpi_resource_to_address64 ( return (AE_OK); } EXPORT_SYMBOL(acpi_resource_to_address64); - diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c index 334327c1f66..92e0c31539b 100644 --- a/drivers/acpi/tables/tbconvrt.c +++ b/drivers/acpi/tables/tbconvrt.c @@ -50,6 +50,24 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbconvrt") +/* Local prototypes */ + +static void +acpi_tb_init_generic_address ( + struct acpi_generic_address *new_gas_struct, + u8 register_bit_width, + acpi_physical_address address); + +static void +acpi_tb_convert_fadt1 ( + struct fadt_descriptor_rev2 *local_fadt, + struct fadt_descriptor_rev1 *original_fadt); + +static void +acpi_tb_convert_fadt2 ( + struct fadt_descriptor_rev2 *local_fadt, + struct fadt_descriptor_rev2 *original_fadt); + u8 acpi_fadt_is_v1; EXPORT_SYMBOL(acpi_fadt_is_v1); @@ -142,11 +160,13 @@ acpi_tb_convert_to_xsdt ( for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { if (acpi_gbl_RSDP->revision < 2) { ACPI_STORE_ADDRESS (new_table->table_offset_entry[i], - (ACPI_CAST_PTR (struct rsdt_descriptor_rev1, table_info->pointer))->table_offset_entry[i]); + (ACPI_CAST_PTR (struct rsdt_descriptor_rev1, + table_info->pointer))->table_offset_entry[i]); } else { new_table->table_offset_entry[i] = - (ACPI_CAST_PTR (XSDT_DESCRIPTOR, table_info->pointer))->table_offset_entry[i]; + (ACPI_CAST_PTR (XSDT_DESCRIPTOR, + table_info->pointer))->table_offset_entry[i]; } } @@ -164,7 +184,7 @@ acpi_tb_convert_to_xsdt ( } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_tb_init_generic_address * @@ -201,7 +221,7 @@ acpi_tb_init_generic_address ( * PARAMETERS: local_fadt - Pointer to new FADT * original_fadt - Pointer to old FADT * - * RETURN: Populates local_fadt + * RETURN: None, populates local_fadt * * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format * @@ -213,7 +233,6 @@ acpi_tb_convert_fadt1 ( struct fadt_descriptor_rev1 *original_fadt) { - /* ACPI 1.0 FACS */ /* The BIOS stored FADT should agree with Revision 1.0 */ acpi_fadt_is_v1 = 1; @@ -232,7 +251,8 @@ acpi_tb_convert_fadt1 ( ACPI_STORE_ADDRESS (local_fadt->Xdsdt, local_fadt->V1_dsdt); /* - * System Interrupt Model isn't used in ACPI 2.0 (local_fadt->Reserved1 = 0;) + * System Interrupt Model isn't used in ACPI 2.0 + * (local_fadt->Reserved1 = 0;) */ /* @@ -269,7 +289,8 @@ acpi_tb_convert_fadt1 ( * that immediately follows. */ ACPI_MEMCPY (&local_fadt->reset_register, - &(ACPI_CAST_PTR (struct fadt_descriptor_rev2_minus, original_fadt))->reset_register, + &(ACPI_CAST_PTR (struct fadt_descriptor_rev2_minus, + original_fadt))->reset_register, sizeof (struct acpi_generic_address) + 1); } else { @@ -304,7 +325,8 @@ acpi_tb_convert_fadt1 ( acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable, (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address + + (acpi_physical_address) + (local_fadt->xpm1a_evt_blk.address + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); /* PM1B is optional; leave null if not present */ @@ -312,7 +334,8 @@ acpi_tb_convert_fadt1 ( if (local_fadt->xpm1b_evt_blk.address) { acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + + (acpi_physical_address) + (local_fadt->xpm1b_evt_blk.address + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); } } @@ -325,7 +348,7 @@ acpi_tb_convert_fadt1 ( * PARAMETERS: local_fadt - Pointer to new FADT * original_fadt - Pointer to old FADT * - * RETURN: Populates local_fadt + * RETURN: None, populates local_fadt * * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format. * Handles optional "X" fields. @@ -348,7 +371,8 @@ acpi_tb_convert_fadt2 ( * is zero. */ if (!(local_fadt->xfirmware_ctrl)) { - ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl, local_fadt->V1_firmware_ctrl); + ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl, + local_fadt->V1_firmware_ctrl); } if (!(local_fadt->Xdsdt)) { @@ -357,32 +381,38 @@ acpi_tb_convert_fadt2 ( if (!(local_fadt->xpm1a_evt_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm1a_evt_blk, - local_fadt->pm1_evt_len, (acpi_physical_address) local_fadt->V1_pm1a_evt_blk); + local_fadt->pm1_evt_len, + (acpi_physical_address) local_fadt->V1_pm1a_evt_blk); } if (!(local_fadt->xpm1b_evt_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm1b_evt_blk, - local_fadt->pm1_evt_len, (acpi_physical_address) local_fadt->V1_pm1b_evt_blk); + local_fadt->pm1_evt_len, + (acpi_physical_address) local_fadt->V1_pm1b_evt_blk); } if (!(local_fadt->xpm1a_cnt_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm1a_cnt_blk, - local_fadt->pm1_cnt_len, (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk); + local_fadt->pm1_cnt_len, + (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk); } if (!(local_fadt->xpm1b_cnt_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm1b_cnt_blk, - local_fadt->pm1_cnt_len, (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk); + local_fadt->pm1_cnt_len, + (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk); } if (!(local_fadt->xpm2_cnt_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm2_cnt_blk, - local_fadt->pm2_cnt_len, (acpi_physical_address) local_fadt->V1_pm2_cnt_blk); + local_fadt->pm2_cnt_len, + (acpi_physical_address) local_fadt->V1_pm2_cnt_blk); } if (!(local_fadt->xpm_tmr_blk.address)) { acpi_tb_init_generic_address (&local_fadt->xpm_tmr_blk, - local_fadt->pm_tm_len, (acpi_physical_address) local_fadt->V1_pm_tmr_blk); + local_fadt->pm_tm_len, + (acpi_physical_address) local_fadt->V1_pm_tmr_blk); } if (!(local_fadt->xgpe0_blk.address)) { @@ -399,18 +429,24 @@ acpi_tb_convert_fadt2 ( acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable, (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address + + (acpi_physical_address) + (local_fadt->xpm1a_evt_blk.address + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); - acpi_gbl_xpm1a_enable.address_space_id = local_fadt->xpm1a_evt_blk.address_space_id; + + acpi_gbl_xpm1a_enable.address_space_id = + local_fadt->xpm1a_evt_blk.address_space_id; /* PM1B is optional; leave null if not present */ if (local_fadt->xpm1b_evt_blk.address) { acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + + (acpi_physical_address) + (local_fadt->xpm1b_evt_blk.address + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); - acpi_gbl_xpm1b_enable.address_space_id = local_fadt->xpm1b_evt_blk.address_space_id; + + acpi_gbl_xpm1b_enable.address_space_id = + local_fadt->xpm1b_evt_blk.address_space_id; } } @@ -432,7 +468,8 @@ acpi_tb_convert_fadt2 ( ******************************************************************************/ acpi_status -acpi_tb_convert_table_fadt (void) +acpi_tb_convert_table_fadt ( + void) { struct fadt_descriptor_rev2 *local_fadt; struct acpi_table_desc *table_desc; @@ -446,7 +483,8 @@ acpi_tb_convert_table_fadt (void) * at least as long as the version 1.0 FADT */ if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev1)) { - ACPI_REPORT_ERROR (("FADT is invalid, too short: 0x%X\n", acpi_gbl_FADT->length)); + ACPI_REPORT_ERROR (("FADT is invalid, too short: 0x%X\n", + acpi_gbl_FADT->length)); return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); } @@ -461,8 +499,9 @@ acpi_tb_convert_table_fadt (void) if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev2)) { /* Length is too short to be a V2.0 table */ - ACPI_REPORT_WARNING (("Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table\n", - acpi_gbl_FADT->length, acpi_gbl_FADT->revision)); + ACPI_REPORT_WARNING (( + "Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table\n", + acpi_gbl_FADT->length, acpi_gbl_FADT->revision)); acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT); } @@ -478,9 +517,8 @@ acpi_tb_convert_table_fadt (void) acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT); } - /* - * Global FADT pointer will point to the new common V2.0 FADT - */ + /* Global FADT pointer will point to the new common V2.0 FADT */ + acpi_gbl_FADT = local_fadt; acpi_gbl_FADT->length = sizeof (FADT_DESCRIPTOR); @@ -508,7 +546,7 @@ acpi_tb_convert_table_fadt (void) /******************************************************************************* * - * FUNCTION: acpi_tb_convert_table_facs + * FUNCTION: acpi_tb_build_common_facs * * PARAMETERS: table_info - Info for currently installed FACS * @@ -530,12 +568,14 @@ acpi_tb_build_common_facs ( /* Absolute minimum length is 24, but the ACPI spec says 64 */ if (acpi_gbl_FACS->length < 24) { - ACPI_REPORT_ERROR (("Invalid FACS table length: 0x%X\n", acpi_gbl_FACS->length)); + ACPI_REPORT_ERROR (("Invalid FACS table length: 0x%X\n", + acpi_gbl_FACS->length)); return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); } if (acpi_gbl_FACS->length < 64) { - ACPI_REPORT_WARNING (("FACS is shorter than the ACPI specification allows: 0x%X, using anyway\n", + ACPI_REPORT_WARNING (( + "FACS is shorter than the ACPI specification allows: 0x%X, using anyway\n", acpi_gbl_FACS->length)); } @@ -548,7 +588,8 @@ acpi_tb_build_common_facs ( (!(acpi_gbl_FACS->xfirmware_waking_vector))) { /* ACPI 1.0 FACS or short table or optional X_ field is zero */ - acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR (u64, &(acpi_gbl_FACS->firmware_waking_vector)); + acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR (u64, + &(acpi_gbl_FACS->firmware_waking_vector)); acpi_gbl_common_fACS.vector_width = 32; } else { diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c index 896f3ddda62..4ab2aadc613 100644 --- a/drivers/acpi/tables/tbget.c +++ b/drivers/acpi/tables/tbget.c @@ -49,6 +49,19 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbget") +/* Local prototypes */ + +static acpi_status +acpi_tb_get_this_table ( + struct acpi_pointer *address, + struct acpi_table_header *header, + struct acpi_table_desc *table_info); + +static acpi_status +acpi_tb_table_override ( + struct acpi_table_header *header, + struct acpi_table_desc *table_info); + /******************************************************************************* * @@ -76,9 +89,8 @@ acpi_tb_get_table ( ACPI_FUNCTION_TRACE ("tb_get_table"); - /* - * Get the header in order to get signature and table size - */ + /* Get the header in order to get signature and table size */ + status = acpi_tb_get_table_header (address, &header); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -127,8 +139,8 @@ acpi_tb_get_table_header ( /* - * Flags contains the current processor mode (Virtual or Physical addressing) - * The pointer_type is either Logical or Physical + * Flags contains the current processor mode (Virtual or Physical + * addressing) The pointer_type is either Logical or Physical */ switch (address->pointer_type) { case ACPI_PHYSMODE_PHYSPTR: @@ -136,7 +148,8 @@ acpi_tb_get_table_header ( /* Pointer matches processor mode, copy the header */ - ACPI_MEMCPY (return_header, address->pointer.logical, sizeof (struct acpi_table_header)); + ACPI_MEMCPY (return_header, address->pointer.logical, + sizeof (struct acpi_table_header)); break; @@ -144,10 +157,11 @@ acpi_tb_get_table_header ( /* Create a logical address for the physical pointer*/ - status = acpi_os_map_memory (address->pointer.physical, sizeof (struct acpi_table_header), - (void *) &header); + status = acpi_os_map_memory (address->pointer.physical, + sizeof (struct acpi_table_header), (void *) &header); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("Could not map memory at %8.8X%8.8X for length %X\n", + ACPI_REPORT_ERROR (( + "Could not map memory at %8.8X%8.8X for length %X\n", ACPI_FORMAT_UINT64 (address->pointer.physical), sizeof (struct acpi_table_header))); return_ACPI_STATUS (status); @@ -210,9 +224,8 @@ acpi_tb_get_table_body ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* - * Attempt table override. - */ + /* Attempt table override. */ + status = acpi_tb_table_override (header, table_info); if (ACPI_SUCCESS (status)) { /* Table was overridden by the host OS */ @@ -241,7 +254,7 @@ acpi_tb_get_table_body ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_table_override ( struct acpi_table_header *header, struct acpi_table_desc *table_info) @@ -315,7 +328,7 @@ acpi_tb_table_override ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_get_this_table ( struct acpi_pointer *address, struct acpi_table_header *header, @@ -330,8 +343,8 @@ acpi_tb_get_this_table ( /* - * Flags contains the current processor mode (Virtual or Physical addressing) - * The pointer_type is either Logical or Physical + * Flags contains the current processor mode (Virtual or Physical + * addressing) The pointer_type is either Logical or Physical */ switch (address->pointer_type) { case ACPI_PHYSMODE_PHYSPTR: @@ -341,7 +354,8 @@ acpi_tb_get_this_table ( full_table = ACPI_MEM_ALLOCATE (header->length); if (!full_table) { - ACPI_REPORT_ERROR (("Could not allocate table memory for [%4.4s] length %X\n", + ACPI_REPORT_ERROR (( + "Could not allocate table memory for [%4.4s] length %X\n", header->signature, header->length)); return_ACPI_STATUS (AE_NO_MEMORY); } @@ -362,12 +376,14 @@ acpi_tb_get_this_table ( * Just map the table's physical memory * into our address space. */ - status = acpi_os_map_memory (address->pointer.physical, (acpi_size) header->length, - (void *) &full_table); + status = acpi_os_map_memory (address->pointer.physical, + (acpi_size) header->length, (void *) &full_table); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n", + ACPI_REPORT_ERROR (( + "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n", header->signature, - ACPI_FORMAT_UINT64 (address->pointer.physical), header->length)); + ACPI_FORMAT_UINT64 (address->pointer.physical), + header->length)); return (status); } @@ -465,9 +481,8 @@ acpi_tb_get_table_ptr ( return_ACPI_STATUS (AE_OK); } - /* - * Check for instance out of range - */ + /* Check for instance out of range */ + if (instance > acpi_gbl_table_lists[table_type].count) { return_ACPI_STATUS (AE_NOT_EXIST); } diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c index adc4270988b..eea5b8cb5eb 100644 --- a/drivers/acpi/tables/tbgetall.c +++ b/drivers/acpi/tables/tbgetall.c @@ -49,6 +49,19 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbgetall") +/* Local prototypes */ + +static acpi_status +acpi_tb_get_primary_table ( + struct acpi_pointer *address, + struct acpi_table_desc *table_info); + +static acpi_status +acpi_tb_get_secondary_table ( + struct acpi_pointer *address, + acpi_string signature, + struct acpi_table_desc *table_info); + /******************************************************************************* * @@ -63,7 +76,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_get_primary_table ( struct acpi_pointer *address, struct acpi_table_desc *table_info) @@ -81,9 +94,8 @@ acpi_tb_get_primary_table ( return_ACPI_STATUS (AE_OK); } - /* - * Get the header in order to get signature and table size - */ + /* Get the header in order to get signature and table size */ + status = acpi_tb_get_table_header (address, &header); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); @@ -130,7 +142,7 @@ acpi_tb_get_primary_table ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_get_secondary_table ( struct acpi_pointer *address, acpi_string signature, @@ -153,7 +165,8 @@ acpi_tb_get_secondary_table ( /* Signature must match request */ if (ACPI_STRNCMP (header.signature, signature, ACPI_NAME_SIZE)) { - ACPI_REPORT_ERROR (("Incorrect table signature - wanted [%s] found [%4.4s]\n", + ACPI_REPORT_ERROR (( + "Incorrect table signature - wanted [%s] found [%4.4s]\n", signature, header.signature)); return_ACPI_STATUS (AE_BAD_SIGNATURE); } @@ -230,7 +243,8 @@ acpi_tb_get_required_tables ( for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { /* Get the table address from the common internal XSDT */ - address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i]; + address.pointer.value = + acpi_gbl_XSDT->table_offset_entry[i]; /* * Get the tables needed by this subsystem (FADT and any SSDTs). @@ -252,18 +266,18 @@ acpi_tb_get_required_tables ( } /* - * Convert the FADT to a common format. This allows earlier revisions of the - * table to coexist with newer versions, using common access code. + * Convert the FADT to a common format. This allows earlier revisions of + * the table to coexist with newer versions, using common access code. */ status = acpi_tb_convert_table_fadt (); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("Could not convert FADT to internal common format\n")); + ACPI_REPORT_ERROR (( + "Could not convert FADT to internal common format\n")); return_ACPI_STATUS (status); } - /* - * Get the FACS (Pointed to by the FADT) - */ + /* Get the FACS (Pointed to by the FADT) */ + address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl; status = acpi_tb_get_secondary_table (&address, FACS_SIG, &table_info); @@ -282,9 +296,8 @@ acpi_tb_get_required_tables ( return_ACPI_STATUS (status); } - /* - * Get/install the DSDT (Pointed to by the FADT) - */ + /* Get/install the DSDT (Pointed to by the FADT) */ + address.pointer.value = acpi_gbl_FADT->Xdsdt; status = acpi_tb_get_secondary_table (&address, DSDT_SIG, &table_info); diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index 85d5bb01022..629b64c8193 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -49,6 +49,14 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbinstal") +/* Local prototypes */ + +static acpi_status +acpi_tb_match_signature ( + char *signature, + struct acpi_table_desc *table_info, + u8 search_type); + /******************************************************************************* * @@ -56,6 +64,7 @@ * * PARAMETERS: Signature - Table signature to match * table_info - Return data + * search_type - Table type to match (primary/secondary) * * RETURN: Status * @@ -64,7 +73,7 @@ * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_match_signature ( char *signature, struct acpi_table_desc *table_info, @@ -76,9 +85,8 @@ acpi_tb_match_signature ( ACPI_FUNCTION_TRACE ("tb_match_signature"); - /* - * Search for a signature match among the known table types - */ + /* Search for a signature match among the known table types */ + for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) { if (!(acpi_gbl_table_data[i].flags & search_type)) { continue; @@ -161,6 +169,7 @@ acpi_tb_install_table ( * FUNCTION: acpi_tb_recognize_table * * PARAMETERS: table_info - Return value from acpi_tb_get_table_body + * search_type - Table type to match (primary/secondary) * * RETURN: Status * @@ -203,7 +212,8 @@ acpi_tb_recognize_table ( * This can be any one of many valid ACPI tables, it just isn't one of * the tables that is consumed by the core subsystem */ - status = acpi_tb_match_signature (table_header->signature, table_info, search_type); + status = acpi_tb_match_signature (table_header->signature, + table_info, search_type); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -253,9 +263,8 @@ acpi_tb_init_table_descriptor ( return_ACPI_STATUS (AE_NO_MEMORY); } - /* - * Install the table into the global data structure - */ + /* Install the table into the global data structure */ + list_head = &acpi_gbl_table_lists[table_type]; /* @@ -316,7 +325,8 @@ acpi_tb_init_table_descriptor ( table_desc->aml_start = (u8 *) (table_desc->pointer + 1), table_desc->aml_length = (u32) (table_desc->length - (u32) sizeof (struct acpi_table_header)); - table_desc->table_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_TABLE); + table_desc->table_id = acpi_ut_allocate_owner_id ( + ACPI_OWNER_TYPE_TABLE); table_desc->loaded_into_namespace = FALSE; /* @@ -349,7 +359,8 @@ acpi_tb_init_table_descriptor ( ******************************************************************************/ void -acpi_tb_delete_all_tables (void) +acpi_tb_delete_all_tables ( + void) { acpi_table_type type; diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c index 9c6913238d5..b7ffe39c362 100644 --- a/drivers/acpi/tables/tbrsdt.c +++ b/drivers/acpi/tables/tbrsdt.c @@ -84,8 +84,9 @@ acpi_tb_verify_rsdp ( /* * Obtain access to the RSDP structure */ - status = acpi_os_map_memory (address->pointer.physical, sizeof (struct rsdp_descriptor), - (void *) &rsdp); + status = acpi_os_map_memory (address->pointer.physical, + sizeof (struct rsdp_descriptor), + (void *) &rsdp); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -154,9 +155,9 @@ cleanup: * * FUNCTION: acpi_tb_get_rsdt_address * - * PARAMETERS: None + * PARAMETERS: out_address - Where the address is returned * - * RETURN: RSDT physical address + * RETURN: None, Address * * DESCRIPTION: Extract the address of the RSDT or XSDT, depending on the * version of the RSDP @@ -181,7 +182,8 @@ acpi_tb_get_rsdt_address ( out_address->pointer.value = acpi_gbl_RSDP->rsdt_physical_address; } else { - out_address->pointer.value = acpi_gbl_RSDP->xsdt_physical_address; + out_address->pointer.value = + acpi_gbl_RSDP->xsdt_physical_address; } } @@ -224,7 +226,8 @@ acpi_tb_validate_rsdt ( if (no_match) { /* Invalid RSDT or XSDT signature */ - ACPI_REPORT_ERROR (("Invalid signature where RSDP indicates RSDT/XSDT should be located\n")); + ACPI_REPORT_ERROR (( + "Invalid signature where RSDP indicates RSDT/XSDT should be located\n")); ACPI_DUMP_BUFFER (acpi_gbl_RSDP, 20); @@ -282,6 +285,7 @@ acpi_tb_get_table_rsdt ( if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the RSDT/XSDT, %s\n", acpi_format_exception (status))); + return_ACPI_STATUS (status); } @@ -299,7 +303,8 @@ acpi_tb_get_table_rsdt ( /* Get the number of tables defined in the RSDT or XSDT */ - acpi_gbl_rsdt_table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info.pointer); + acpi_gbl_rsdt_table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, + table_info.pointer); /* Convert and/or copy to an XSDT structure */ diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index fede5804c78..e69d01d443d 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -49,48 +49,14 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbutils") +/* Local prototypes */ -/******************************************************************************* - * - * FUNCTION: acpi_tb_handle_to_object - * - * PARAMETERS: table_id - Id for which the function is searching - * table_desc - Pointer to return the matching table - * descriptor. - * - * RETURN: Search the tables to find one with a matching table_id and - * return a pointer to that table descriptor. - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE +#ifdef ACPI_OBSOLETE_FUNCTIONS acpi_status acpi_tb_handle_to_object ( u16 table_id, - struct acpi_table_desc **return_table_desc) -{ - u32 i; - struct acpi_table_desc *table_desc; - - - ACPI_FUNCTION_NAME ("tb_handle_to_object"); - - - for (i = 0; i < ACPI_TABLE_MAX; i++) { - table_desc = acpi_gbl_table_lists[i].next; - while (table_desc) { - if (table_desc->table_id == table_id) { - *return_table_desc = table_desc; - return (AE_OK); - } - - table_desc = table_desc->next; - } - } - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "table_id=%X does not exist\n", table_id)); - return (AE_BAD_PARAMETER); -} -#endif /* ACPI_FUTURE_USAGE */ + struct acpi_table_desc **table_desc); +#endif /******************************************************************************* @@ -128,6 +94,7 @@ acpi_tb_validate_table_header ( if (!acpi_os_readable (table_header, sizeof (struct acpi_table_header))) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Cannot read table header at %p\n", table_header)); + return (AE_BAD_ADDRESS); } @@ -141,6 +108,7 @@ acpi_tb_validate_table_header ( ACPI_REPORT_WARNING (("Invalid table signature found: [%4.4s]\n", (char *) &signature)); + ACPI_DUMP_BUFFER (table_header, sizeof (struct acpi_table_header)); return (AE_BAD_SIGNATURE); } @@ -154,6 +122,7 @@ acpi_tb_validate_table_header ( ACPI_REPORT_WARNING (("Invalid table header length (0x%X) found\n", (u32) table_header->length)); + ACPI_DUMP_BUFFER (table_header, sizeof (struct acpi_table_header)); return (AE_BAD_HEADER); } @@ -193,8 +162,10 @@ acpi_tb_verify_table_checksum ( /* Return the appropriate exception */ if (checksum) { - ACPI_REPORT_WARNING (("Invalid checksum in table [%4.4s] (%02X, sum %02X is not zero)\n", - table_header->signature, (u32) table_header->checksum, (u32) checksum)); + ACPI_REPORT_WARNING (( + "Invalid checksum in table [%4.4s] (%02X, sum %02X is not zero)\n", + table_header->signature, (u32) table_header->checksum, + (u32) checksum)); status = AE_BAD_CHECKSUM; } @@ -209,7 +180,7 @@ acpi_tb_verify_table_checksum ( * PARAMETERS: Buffer - Buffer to checksum * Length - Size of the buffer * - * RETURNS 8 bit checksum of buffer + * RETURN: 8 bit checksum of buffer * * DESCRIPTION: Computes an 8 bit checksum of the buffer(length) and returns it. * @@ -238,3 +209,47 @@ acpi_tb_checksum ( } +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: acpi_tb_handle_to_object + * + * PARAMETERS: table_id - Id for which the function is searching + * table_desc - Pointer to return the matching table + * descriptor. + * + * RETURN: Search the tables to find one with a matching table_id and + * return a pointer to that table descriptor. + * + ******************************************************************************/ + +acpi_status +acpi_tb_handle_to_object ( + u16 table_id, + struct acpi_table_desc **return_table_desc) +{ + u32 i; + struct acpi_table_desc *table_desc; + + + ACPI_FUNCTION_NAME ("tb_handle_to_object"); + + + for (i = 0; i < ACPI_TABLE_MAX; i++) { + table_desc = acpi_gbl_table_lists[i].next; + while (table_desc) { + if (table_desc->table_id == table_id) { + *return_table_desc = table_desc; + return (AE_OK); + } + + table_desc = table_desc->next; + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "table_id=%X does not exist\n", table_id)); + return (AE_BAD_PARAMETER); +} +#endif + + diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 7715043461c..0c0b9085dbe 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -67,7 +67,8 @@ ******************************************************************************/ acpi_status -acpi_load_tables (void) +acpi_load_tables ( + void) { struct acpi_pointer rsdp_address; acpi_status status; @@ -82,7 +83,7 @@ acpi_load_tables (void) &rsdp_address); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("acpi_load_tables: Could not get RSDP, %s\n", - acpi_format_exception (status))); + acpi_format_exception (status))); goto error_exit; } @@ -93,7 +94,7 @@ acpi_load_tables (void) status = acpi_tb_verify_rsdp (&rsdp_address); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("acpi_load_tables: RSDP Failed validation: %s\n", - acpi_format_exception (status))); + acpi_format_exception (status))); goto error_exit; } @@ -102,7 +103,7 @@ acpi_load_tables (void) status = acpi_tb_get_table_rsdt (); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("acpi_load_tables: Could not load RSDT: %s\n", - acpi_format_exception (status))); + acpi_format_exception (status))); goto error_exit; } @@ -110,20 +111,20 @@ acpi_load_tables (void) status = acpi_tb_get_required_tables (); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("acpi_load_tables: Error getting required tables (DSDT/FADT/FACS): %s\n", - acpi_format_exception (status))); + ACPI_REPORT_ERROR (( + "acpi_load_tables: Error getting required tables (DSDT/FADT/FACS): %s\n", + acpi_format_exception (status))); goto error_exit; } ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "ACPI Tables successfully acquired\n")); - /* Load the namespace from the tables */ status = acpi_ns_load_namespace (); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("acpi_load_tables: Could not load namespace: %s\n", - acpi_format_exception (status))); + acpi_format_exception (status))); goto error_exit; } @@ -139,7 +140,6 @@ error_exit: #ifdef ACPI_FUTURE_USAGE - /******************************************************************************* * * FUNCTION: acpi_load_table @@ -250,7 +250,6 @@ acpi_unload_table ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Find all tables of the requested type */ table_desc = acpi_gbl_table_lists[table_type].next; @@ -321,7 +320,6 @@ acpi_get_table_header ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Get a pointer to the entire table */ status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr); @@ -329,23 +327,20 @@ acpi_get_table_header ( return_ACPI_STATUS (status); } - /* - * The function will return a NULL pointer if the table is not loaded - */ + /* The function will return a NULL pointer if the table is not loaded */ + if (tbl_ptr == NULL) { return_ACPI_STATUS (AE_NOT_EXIST); } - /* - * Copy the header to the caller's buffer - */ + /* Copy the header to the caller's buffer */ + ACPI_MEMCPY ((void *) out_table_header, (void *) tbl_ptr, - sizeof (struct acpi_table_header)); + sizeof (struct acpi_table_header)); return_ACPI_STATUS (status); } - #endif /* ACPI_FUTURE_USAGE */ /******************************************************************************* @@ -404,7 +399,6 @@ acpi_get_table ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Get a pointer to the entire table */ status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr); @@ -423,9 +417,8 @@ acpi_get_table ( /* Get the table length */ if (table_type == ACPI_TABLE_RSDP) { - /* - * RSD PTR is the only "table" without a header - */ + /* RSD PTR is the only "table" without a header */ + table_length = sizeof (struct rsdp_descriptor); } else { diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index 6e8072ebbac..dc3c3f6a9f6 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -50,6 +50,18 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME ("tbxfroot") +/* Local prototypes */ + +static acpi_status +acpi_tb_find_rsdp ( + struct acpi_table_desc *table_info, + u32 flags); + +static u8 * +acpi_tb_scan_memory_for_rsdp ( + u8 *start_address, + u32 length); + /******************************************************************************* * @@ -57,7 +69,8 @@ * * PARAMETERS: Signature - String with ACPI table signature * oem_id - String with the table OEM ID - * oem_table_id - String with the OEM Table ID. + * oem_table_id - String with the OEM Table ID + * table_ptr - Where the table pointer is returned * * RETURN: Status * @@ -99,14 +112,13 @@ acpi_tb_find_table ( if (!acpi_gbl_DSDT) { return_ACPI_STATUS (AE_NO_ACPI_TABLES); } - table = acpi_gbl_DSDT; } else { /* Find the table */ status = acpi_get_firmware_table (signature, 1, - ACPI_LOGICAL_ADDRESSING, &table); + ACPI_LOGICAL_ADDRESSING, &table); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -114,14 +126,19 @@ acpi_tb_find_table ( /* Check oem_id and oem_table_id */ - if ((oem_id[0] && ACPI_STRNCMP ( - oem_id, table->oem_id, sizeof (table->oem_id))) || + if ((oem_id[0] && ACPI_STRNCMP ( + oem_id, table->oem_id, + sizeof (table->oem_id))) || + (oem_table_id[0] && ACPI_STRNCMP ( - oem_table_id, table->oem_table_id, sizeof (table->oem_table_id)))) { + oem_table_id, table->oem_table_id, + sizeof (table->oem_table_id)))) { return_ACPI_STATUS (AE_AML_NAME_NOT_FOUND); } - ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Found table [%4.4s]\n", table->signature)); + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Found table [%4.4s]\n", + table->signature)); + *table_ptr = table; return_ACPI_STATUS (AE_OK); } @@ -191,8 +208,8 @@ acpi_get_firmware_table ( /* Map and validate the RSDP */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - status = acpi_os_map_memory (address.pointer.physical, sizeof (struct rsdp_descriptor), - (void *) &acpi_gbl_RSDP); + status = acpi_os_map_memory (address.pointer.physical, + sizeof (struct rsdp_descriptor), (void *) &acpi_gbl_RSDP); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -203,7 +220,8 @@ acpi_get_firmware_table ( /* The signature and checksum must both be correct */ - if (ACPI_STRNCMP ((char *) acpi_gbl_RSDP, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { + if (ACPI_STRNCMP ((char *) acpi_gbl_RSDP, RSDP_SIG, + sizeof (RSDP_SIG)-1) != 0) { /* Nope, BAD Signature */ return_ACPI_STATUS (AE_BAD_SIGNATURE); @@ -313,7 +331,8 @@ acpi_get_firmware_table ( cleanup: - acpi_os_unmap_memory (rsdt_info->pointer, (acpi_size) rsdt_info->pointer->length); + acpi_os_unmap_memory (rsdt_info->pointer, + (acpi_size) rsdt_info->pointer->length); ACPI_MEM_FREE (rsdt_info); if (header) { @@ -335,8 +354,8 @@ EXPORT_SYMBOL(acpi_get_firmware_table); * * FUNCTION: acpi_find_root_pointer * - * PARAMETERS: **rsdp_address - Where to place the RSDP address - * Flags - Logical/Physical addressing + * PARAMETERS: Flags - Logical/Physical addressing + * rsdp_address - Where to place the RSDP address * * RETURN: Status, Physical address of the RSDP * @@ -363,6 +382,7 @@ acpi_find_root_pointer ( ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "RSDP structure not found, %s Flags=%X\n", acpi_format_exception (status), flags)); + return_ACPI_STATUS (AE_NO_ACPI_TABLES); } @@ -385,7 +405,7 @@ acpi_find_root_pointer ( * ******************************************************************************/ -u8 * +static u8 * acpi_tb_scan_memory_for_rsdp ( u8 *start_address, u32 length) @@ -406,7 +426,8 @@ acpi_tb_scan_memory_for_rsdp ( mem_rover += ACPI_RSDP_SCAN_STEP) { /* The signature and checksum must both be correct */ - if (ACPI_STRNCMP ((char *) mem_rover, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { + if (ACPI_STRNCMP ((char *) mem_rover, + RSDP_SIG, sizeof (RSDP_SIG) - 1) != 0) { /* No signature match, keep looking */ continue; @@ -450,7 +471,7 @@ acpi_tb_scan_memory_for_rsdp ( * * FUNCTION: acpi_tb_find_rsdp * - * PARAMETERS: *table_info - Where the table info is returned + * PARAMETERS: table_info - Where the table info is returned * Flags - Current memory mode (logical vs. * physical addressing) * @@ -468,7 +489,7 @@ acpi_tb_scan_memory_for_rsdp ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_tb_find_rsdp ( struct acpi_table_desc *table_info, u32 flags) @@ -483,43 +504,49 @@ acpi_tb_find_rsdp ( /* - * Scan supports either 1) Logical addressing or 2) Physical addressing + * Scan supports either logical addressing or physical addressing */ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - /* - * 1a) Get the location of the EBDA - */ - status = acpi_os_map_memory ((acpi_physical_address) ACPI_EBDA_PTR_LOCATION, - ACPI_EBDA_PTR_LENGTH, - (void *) &table_ptr); + /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ + + status = acpi_os_map_memory ( + (acpi_physical_address) ACPI_EBDA_PTR_LOCATION, + ACPI_EBDA_PTR_LENGTH, (void *) &table_ptr); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH)); + return_ACPI_STATUS (status); } ACPI_MOVE_16_TO_32 (&physical_address, table_ptr); - physical_address <<= 4; /* Convert segment to physical address */ + + /* Convert segment part to physical address */ + + physical_address <<= 4; acpi_os_unmap_memory (table_ptr, ACPI_EBDA_PTR_LENGTH); /* EBDA present? */ if (physical_address > 0x400) { /* - * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + * 1b) Search EBDA paragraphs (EBDa is required to be a + * minimum of 1_k length) */ - status = acpi_os_map_memory ((acpi_physical_address) physical_address, - ACPI_EBDA_WINDOW_SIZE, - (void *) &table_ptr); + status = acpi_os_map_memory ( + (acpi_physical_address) physical_address, + ACPI_EBDA_WINDOW_SIZE, (void *) &table_ptr); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", physical_address, ACPI_EBDA_WINDOW_SIZE)); + return_ACPI_STATUS (status); } - mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_EBDA_WINDOW_SIZE); + mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, + ACPI_EBDA_WINDOW_SIZE); acpi_os_unmap_memory (table_ptr, ACPI_EBDA_WINDOW_SIZE); if (mem_rover) { @@ -527,7 +554,8 @@ acpi_tb_find_rsdp ( physical_address += ACPI_PTR_DIFF (mem_rover, table_ptr); - table_info->physical_address = (acpi_physical_address) physical_address; + table_info->physical_address = + (acpi_physical_address) physical_address; return_ACPI_STATUS (AE_OK); } } @@ -535,13 +563,15 @@ acpi_tb_find_rsdp ( /* * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ - status = acpi_os_map_memory ((acpi_physical_address) ACPI_HI_RSDP_WINDOW_BASE, - ACPI_HI_RSDP_WINDOW_SIZE, - (void *) &table_ptr); + status = acpi_os_map_memory ( + (acpi_physical_address) ACPI_HI_RSDP_WINDOW_BASE, + ACPI_HI_RSDP_WINDOW_SIZE, (void *) &table_ptr); + if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X for length %X\n", ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE)); + return_ACPI_STATUS (status); } @@ -551,9 +581,11 @@ acpi_tb_find_rsdp ( if (mem_rover) { /* Found it, return the physical address */ - physical_address = ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF (mem_rover, table_ptr); + physical_address = + ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF (mem_rover, table_ptr); - table_info->physical_address = (acpi_physical_address) physical_address; + table_info->physical_address = + (acpi_physical_address) physical_address; return_ACPI_STATUS (AE_OK); } } @@ -562,9 +594,8 @@ acpi_tb_find_rsdp ( * Physical addressing */ else { - /* - * 1a) Get the location of the EBDA - */ + /* 1a) Get the location of the EBDA */ + ACPI_MOVE_16_TO_32 (&physical_address, ACPI_EBDA_PTR_LOCATION); physical_address <<= 4; /* Convert segment to physical address */ @@ -572,9 +603,11 @@ acpi_tb_find_rsdp ( if (physical_address > 0x400) { /* - * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length) + * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of + * 1_k length) */ - mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (physical_address), + mem_rover = acpi_tb_scan_memory_for_rsdp ( + ACPI_PHYSADDR_TO_PTR (physical_address), ACPI_EBDA_WINDOW_SIZE); if (mem_rover) { /* Found it, return the physical address */ @@ -584,10 +617,10 @@ acpi_tb_find_rsdp ( } } - /* - * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh - */ - mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_HI_RSDP_WINDOW_BASE), + /* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ + + mem_rover = acpi_tb_scan_memory_for_rsdp ( + ACPI_PHYSADDR_TO_PTR (ACPI_HI_RSDP_WINDOW_BASE), ACPI_HI_RSDP_WINDOW_SIZE); if (mem_rover) { /* Found it, return the physical address */ diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index 3313439c4bc..c4e7f989a2b 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -47,8 +47,35 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utalloc") +/* Local prototypes */ -/****************************************************************************** +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +static struct acpi_debug_mem_block * +acpi_ut_find_allocation ( + u32 list_id, + void *allocation); + +static acpi_status +acpi_ut_track_allocation ( + u32 list_id, + struct acpi_debug_mem_block *address, + acpi_size size, + u8 alloc_type, + u32 component, + char *module, + u32 line); + +static acpi_status +acpi_ut_remove_allocation ( + u32 list_id, + struct acpi_debug_mem_block *address, + u32 component, + char *module, + u32 line); +#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ + + +/******************************************************************************* * * FUNCTION: acpi_ut_release_to_cache * @@ -98,7 +125,8 @@ acpi_ut_release_to_cache ( /* Put the object at the head of the cache list */ - * (ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset]))) = cache_info->list_head; + * (ACPI_CAST_INDIRECT_PTR (char, + &(((char *) object)[cache_info->link_offset]))) = cache_info->list_head; cache_info->list_head = object; cache_info->cache_depth++; @@ -115,7 +143,7 @@ acpi_ut_release_to_cache ( } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_acquire_from_cache * @@ -156,7 +184,8 @@ acpi_ut_acquire_from_cache ( /* There is an object available, use it */ object = cache_info->list_head; - cache_info->list_head = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset]))); + cache_info->list_head = *(ACPI_CAST_INDIRECT_PTR (char, + &(((char *) object)[cache_info->link_offset]))); ACPI_MEM_TRACKING (cache_info->cache_hits++); cache_info->cache_depth--; @@ -201,7 +230,7 @@ acpi_ut_acquire_from_cache ( #ifdef ACPI_ENABLE_OBJECT_CACHE -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_delete_generic_cache * @@ -228,7 +257,8 @@ acpi_ut_delete_generic_cache ( while (cache_info->list_head) { /* Delete one cached state object */ - next = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) cache_info->list_head)[cache_info->link_offset]))); + next = *(ACPI_CAST_INDIRECT_PTR (char, + &(((char *) cache_info->list_head)[cache_info->link_offset]))); ACPI_MEM_FREE (cache_info->list_head); cache_info->list_head = next; @@ -497,8 +527,8 @@ acpi_ut_allocate_and_track ( acpi_status status; - allocation = acpi_ut_allocate (size + sizeof (struct acpi_debug_mem_header), component, - module, line); + allocation = acpi_ut_allocate (size + sizeof (struct acpi_debug_mem_header), + component, module, line); if (!allocation) { return (NULL); } @@ -543,8 +573,8 @@ acpi_ut_callocate_and_track ( acpi_status status; - allocation = acpi_ut_callocate (size + sizeof (struct acpi_debug_mem_header), component, - module, line); + allocation = acpi_ut_callocate (size + sizeof (struct acpi_debug_mem_header), + component, module, line); if (!allocation) { /* Report allocation error */ @@ -637,7 +667,7 @@ acpi_ut_free_and_track ( * ******************************************************************************/ -struct acpi_debug_mem_block * +static struct acpi_debug_mem_block * acpi_ut_find_allocation ( u32 list_id, void *allocation) @@ -686,7 +716,7 @@ acpi_ut_find_allocation ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_track_allocation ( u32 list_id, struct acpi_debug_mem_block *allocation, @@ -721,10 +751,12 @@ acpi_ut_track_allocation ( element = acpi_ut_find_allocation (list_id, allocation); if (element) { - ACPI_REPORT_ERROR (("ut_track_allocation: Allocation already present in list! (%p)\n", + ACPI_REPORT_ERROR (( + "ut_track_allocation: Allocation already present in list! (%p)\n", allocation)); - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Element %p Address %p\n", element, allocation)); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Element %p Address %p\n", + element, allocation)); goto unlock_and_exit; } @@ -773,7 +805,7 @@ unlock_and_exit: * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_remove_allocation ( u32 list_id, struct acpi_debug_mem_block *allocation, @@ -797,7 +829,7 @@ acpi_ut_remove_allocation ( /* No allocations! */ _ACPI_REPORT_ERROR (module, line, component, - ("ut_remove_allocation: Empty allocation list, nothing to free!\n")); + ("ut_remove_allocation: Empty allocation list, nothing to free!\n")); return_ACPI_STATUS (AE_OK); } @@ -824,7 +856,8 @@ acpi_ut_remove_allocation ( ACPI_MEMSET (&allocation->user_space, 0xEA, allocation->size); - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", allocation->size)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", + allocation->size)); status = acpi_ut_release_mutex (ACPI_MTX_MEMORY); return_ACPI_STATUS (status); @@ -842,6 +875,7 @@ acpi_ut_remove_allocation ( * DESCRIPTION: Print some info about the outstanding allocations. * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE void acpi_ut_dump_allocation_info ( @@ -884,7 +918,8 @@ acpi_ut_dump_allocation_info ( ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, ("%30s: %4d (%3d Kb)\n", "Max Nodes", acpi_gbl_max_concurrent_node_count, - ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * sizeof (struct acpi_namespace_node))))); + ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * + sizeof (struct acpi_namespace_node))))); */ return_VOID; } @@ -933,26 +968,26 @@ acpi_ut_dump_allocations ( descriptor = ACPI_CAST_PTR (union acpi_descriptor, &element->user_space); if (descriptor->descriptor_id != ACPI_DESC_TYPE_CACHED) { acpi_os_printf ("%p Len %04X %9.9s-%d [%s] ", - descriptor, element->size, element->module, - element->line, acpi_ut_get_descriptor_name (descriptor)); + descriptor, element->size, element->module, + element->line, acpi_ut_get_descriptor_name (descriptor)); /* Most of the elements will be Operand objects. */ switch (ACPI_GET_DESCRIPTOR_TYPE (descriptor)) { case ACPI_DESC_TYPE_OPERAND: acpi_os_printf ("%12.12s R%hd", - acpi_ut_get_type_name (descriptor->object.common.type), - descriptor->object.common.reference_count); + acpi_ut_get_type_name (descriptor->object.common.type), + descriptor->object.common.reference_count); break; case ACPI_DESC_TYPE_PARSER: acpi_os_printf ("aml_opcode %04hX", - descriptor->op.asl.aml_opcode); + descriptor->op.asl.aml_opcode); break; case ACPI_DESC_TYPE_NAMED: acpi_os_printf ("%4.4s", - acpi_ut_get_node_name (&descriptor->node)); + acpi_ut_get_node_name (&descriptor->node)); break; default: @@ -983,6 +1018,5 @@ acpi_ut_dump_allocations ( return_VOID; } - #endif /* #ifdef ACPI_DBG_TRACK_ALLOCATIONS */ diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c index 0fcd98bde0d..11e88495716 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/utilities/utcopy.c @@ -49,21 +49,69 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utcopy") +/* Local prototypes */ + +static acpi_status +acpi_ut_copy_isimple_to_esimple ( + union acpi_operand_object *internal_object, + union acpi_object *external_object, + u8 *data_space, + acpi_size *buffer_space_used); + +static acpi_status +acpi_ut_copy_ielement_to_ielement ( + u8 object_type, + union acpi_operand_object *source_object, + union acpi_generic_state *state, + void *context); + +static acpi_status +acpi_ut_copy_ipackage_to_epackage ( + union acpi_operand_object *internal_object, + u8 *buffer, + acpi_size *space_used); + +static acpi_status +acpi_ut_copy_esimple_to_isimple( + union acpi_object *user_obj, + union acpi_operand_object **return_obj); + +static acpi_status +acpi_ut_copy_simple_object ( + union acpi_operand_object *source_desc, + union acpi_operand_object *dest_desc); + +static acpi_status +acpi_ut_copy_ielement_to_eelement ( + u8 object_type, + union acpi_operand_object *source_object, + union acpi_generic_state *state, + void *context); + +static acpi_status +acpi_ut_copy_ipackage_to_ipackage ( + union acpi_operand_object *source_obj, + union acpi_operand_object *dest_obj, + struct acpi_walk_state *walk_state); + /******************************************************************************* * * FUNCTION: acpi_ut_copy_isimple_to_esimple * - * PARAMETERS: *internal_object - Pointer to the object we are examining - * *Buffer - Where the object is returned - * *space_used - Where the data length is returned + * PARAMETERS: internal_object - Source object to be copied + * external_object - Where to return the copied object + * data_space - Where object data is returned (such as + * buffer and string data) + * buffer_space_used - Length of data_space that was used * * RETURN: Status * - * DESCRIPTION: This function is called to place a simple object in a user - * buffer. + * DESCRIPTION: This function is called to copy a simple internal object to + * an external object. * - * The buffer is assumed to have sufficient space for the object. + * The data_space buffer is assumed to have sufficient space for + * the object. * ******************************************************************************/ @@ -107,10 +155,12 @@ acpi_ut_copy_isimple_to_esimple ( external_object->string.pointer = (char *) data_space; external_object->string.length = internal_object->string.length; - *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD ((acpi_size) internal_object->string.length + 1); + *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD ( + (acpi_size) internal_object->string.length + 1); - ACPI_MEMCPY ((void *) data_space, (void *) internal_object->string.pointer, - (acpi_size) internal_object->string.length + 1); + ACPI_MEMCPY ((void *) data_space, + (void *) internal_object->string.pointer, + (acpi_size) internal_object->string.length + 1); break; @@ -118,10 +168,12 @@ acpi_ut_copy_isimple_to_esimple ( external_object->buffer.pointer = data_space; external_object->buffer.length = internal_object->buffer.length; - *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD (internal_object->string.length); + *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD ( + internal_object->string.length); - ACPI_MEMCPY ((void *) data_space, (void *) internal_object->buffer.pointer, - internal_object->buffer.length); + ACPI_MEMCPY ((void *) data_space, + (void *) internal_object->buffer.pointer, + internal_object->buffer.length); break; @@ -194,7 +246,7 @@ acpi_ut_copy_isimple_to_esimple ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_copy_ielement_to_eelement ( u8 object_type, union acpi_operand_object *source_object, @@ -213,7 +265,7 @@ acpi_ut_copy_ielement_to_eelement ( this_index = state->pkg.index; target_object = (union acpi_object *) - &((union acpi_object *)(state->pkg.dest_object))->package.elements[this_index]; + &((union acpi_object *)(state->pkg.dest_object))->package.elements[this_index]; switch (object_type) { case ACPI_COPY_TYPE_SIMPLE: @@ -236,7 +288,8 @@ acpi_ut_copy_ielement_to_eelement ( */ target_object->type = ACPI_TYPE_PACKAGE; target_object->package.count = source_object->package.count; - target_object->package.elements = ACPI_CAST_PTR (union acpi_object, info->free_space); + target_object->package.elements = + ACPI_CAST_PTR (union acpi_object, info->free_space); /* * Pass the new package object back to the package walk routine @@ -248,7 +301,8 @@ acpi_ut_copy_ielement_to_eelement ( * update the buffer length counter */ object_space = ACPI_ROUND_UP_TO_NATIVE_WORD ( - (acpi_size) target_object->package.count * sizeof (union acpi_object)); + (acpi_size) target_object->package.count * + sizeof (union acpi_object)); break; @@ -266,9 +320,9 @@ acpi_ut_copy_ielement_to_eelement ( * * FUNCTION: acpi_ut_copy_ipackage_to_epackage * - * PARAMETERS: *internal_object - Pointer to the object we are returning - * *Buffer - Where the object is returned - * *space_used - Where the object length is returned + * PARAMETERS: internal_object - Pointer to the object we are returning + * Buffer - Where the object is returned + * space_used - Where the object length is returned * * RETURN: Status * @@ -304,13 +358,15 @@ acpi_ut_copy_ipackage_to_epackage ( * Free space begins right after the first package */ info.length = ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object)); - info.free_space = buffer + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object)); + info.free_space = buffer + ACPI_ROUND_UP_TO_NATIVE_WORD ( + sizeof (union acpi_object)); info.object_space = 0; info.num_packages = 1; external_object->type = ACPI_GET_OBJECT_TYPE (internal_object); external_object->package.count = internal_object->package.count; - external_object->package.elements = ACPI_CAST_PTR (union acpi_object, info.free_space); + external_object->package.elements = ACPI_CAST_PTR (union acpi_object, + info.free_space); /* * Leave room for an array of ACPI_OBJECTS in the buffer @@ -333,8 +389,8 @@ acpi_ut_copy_ipackage_to_epackage ( * * FUNCTION: acpi_ut_copy_iobject_to_eobject * - * PARAMETERS: *internal_object - The internal object to be converted - * *buffer_ptr - Where the object is returned + * PARAMETERS: internal_object - The internal object to be converted + * buffer_ptr - Where the object is returned * * RETURN: Status * @@ -367,10 +423,10 @@ acpi_ut_copy_iobject_to_eobject ( * Build a simple object (no nested objects) */ status = acpi_ut_copy_isimple_to_esimple (internal_object, - (union acpi_object *) ret_buffer->pointer, - ((u8 *) ret_buffer->pointer + - ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object))), - &ret_buffer->length); + (union acpi_object *) ret_buffer->pointer, + ((u8 *) ret_buffer->pointer + + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object))), + &ret_buffer->length); /* * build simple does not include the object size in the length * so we add it in here @@ -386,8 +442,8 @@ acpi_ut_copy_iobject_to_eobject ( * * FUNCTION: acpi_ut_copy_esimple_to_isimple * - * PARAMETERS: *external_object - The external object to be converted - * *internal_object - Where the internal object is returned + * PARAMETERS: external_object - The external object to be converted + * ret_internal_object - Where the internal object is returned * * RETURN: Status * @@ -398,7 +454,7 @@ acpi_ut_copy_iobject_to_eobject ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_copy_esimple_to_isimple ( union acpi_object *external_object, union acpi_operand_object **ret_internal_object) @@ -417,7 +473,8 @@ acpi_ut_copy_esimple_to_isimple ( case ACPI_TYPE_BUFFER: case ACPI_TYPE_INTEGER: - internal_object = acpi_ut_create_internal_object ((u8) external_object->type); + internal_object = acpi_ut_create_internal_object ( + (u8) external_object->type); if (!internal_object) { return_ACPI_STATUS (AE_NO_MEMORY); } @@ -486,7 +543,6 @@ error_exit: #ifdef ACPI_FUTURE_IMPLEMENTATION - /* Code to convert packages that are parameters to control methods */ /******************************************************************************* @@ -614,7 +670,7 @@ acpi_ut_copy_eobject_to_iobject ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_copy_simple_object ( union acpi_operand_object *source_desc, union acpi_operand_object *dest_desc) @@ -724,7 +780,7 @@ acpi_ut_copy_simple_object ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_copy_ielement_to_ielement ( u8 object_type, union acpi_operand_object *source_object, @@ -837,7 +893,7 @@ error_exit: * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_copy_ipackage_to_ipackage ( union acpi_operand_object *source_obj, union acpi_operand_object *dest_obj, diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index 985c5d045b7..794c7df3f2a 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -56,7 +56,7 @@ static char *acpi_gbl_fn_entry_str = "----Entry"; static char *acpi_gbl_fn_exit_str = "----Exit-"; -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_init_stack_ptr_trace * @@ -64,9 +64,9 @@ static char *acpi_gbl_fn_exit_str = "----Exit-"; * * RETURN: None * - * DESCRIPTION: Save the current stack pointer + * DESCRIPTION: Save the current CPU stack pointer at subsystem startup * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_init_stack_ptr_trace ( @@ -79,7 +79,7 @@ acpi_ut_init_stack_ptr_trace ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_track_stack_ptr * @@ -87,9 +87,9 @@ acpi_ut_init_stack_ptr_trace ( * * RETURN: None * - * DESCRIPTION: Save the current stack pointer + * DESCRIPTION: Save the current CPU stack pointer * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_track_stack_ptr ( @@ -110,16 +110,16 @@ acpi_ut_track_stack_ptr ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_debug_print * - * PARAMETERS: debug_level - Requested debug print level - * proc_name - Caller's procedure name - * module_name - Caller's module name (for error output) + * PARAMETERS: requested_debug_level - Requested debug print level * line_number - Caller's line number (for error output) - * component_id - Caller's component ID (for error output) - * + * dbg_info - Contains: + * proc_name - Caller's procedure name + * module_name - Caller's module name + * component_id - Caller's component ID * Format - Printf format field * ... - Optional printf arguments * @@ -128,7 +128,7 @@ acpi_ut_track_stack_ptr ( * DESCRIPTION: Print error message with prefix consisting of the module name, * line number, and component ID. * - ****************************************************************************/ + ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE acpi_ut_debug_print ( @@ -157,7 +157,8 @@ acpi_ut_debug_print ( if (thread_id != acpi_gbl_prev_thread_id) { if (ACPI_LV_THREADS & acpi_dbg_level) { - acpi_os_printf ("\n**** Context Switch from TID %X to TID %X ****\n\n", + acpi_os_printf ( + "\n**** Context Switch from TID %X to TID %X ****\n\n", acpi_gbl_prev_thread_id, thread_id); } @@ -174,15 +175,16 @@ acpi_ut_debug_print ( acpi_os_printf ("[%04lX] ", thread_id); } - acpi_os_printf ("[%02ld] %-22.22s: ", acpi_gbl_nesting_level, dbg_info->proc_name); + acpi_os_printf ("[%02ld] %-22.22s: ", + acpi_gbl_nesting_level, dbg_info->proc_name); va_start (args, format); acpi_os_vprintf (format, args); } -EXPORT_SYMBOL(acpi_ut_debug_print); +EXPORT_SYMBOL(acpi_ut_debug_print); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_debug_print_raw * @@ -200,7 +202,7 @@ EXPORT_SYMBOL(acpi_ut_debug_print); * DESCRIPTION: Print message with no headers. Has same interface as * debug_print so that the same macros can be used. * - ****************************************************************************/ + ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE acpi_ut_debug_print_raw ( @@ -224,7 +226,7 @@ acpi_ut_debug_print_raw ( EXPORT_SYMBOL(acpi_ut_debug_print_raw); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_trace * @@ -239,7 +241,7 @@ EXPORT_SYMBOL(acpi_ut_debug_print_raw); * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_trace ( @@ -256,7 +258,7 @@ acpi_ut_trace ( EXPORT_SYMBOL(acpi_ut_trace); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_trace_ptr * @@ -272,7 +274,7 @@ EXPORT_SYMBOL(acpi_ut_trace); * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_trace_ptr ( @@ -288,7 +290,7 @@ acpi_ut_trace_ptr ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_trace_str * @@ -304,7 +306,7 @@ acpi_ut_trace_ptr ( * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_trace_str ( @@ -321,7 +323,7 @@ acpi_ut_trace_str ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_trace_u32 * @@ -337,7 +339,7 @@ acpi_ut_trace_str ( * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_trace_u32 ( @@ -354,7 +356,7 @@ acpi_ut_trace_u32 ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_exit * @@ -369,7 +371,7 @@ acpi_ut_trace_u32 ( * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_exit ( @@ -385,7 +387,7 @@ acpi_ut_exit ( EXPORT_SYMBOL(acpi_ut_exit); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_status_exit * @@ -401,7 +403,7 @@ EXPORT_SYMBOL(acpi_ut_exit); * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit status also. * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_status_exit ( @@ -426,7 +428,7 @@ acpi_ut_status_exit ( EXPORT_SYMBOL(acpi_ut_status_exit); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_value_exit * @@ -442,7 +444,7 @@ EXPORT_SYMBOL(acpi_ut_status_exit); * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit value also. * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_value_exit ( @@ -460,7 +462,7 @@ acpi_ut_value_exit ( EXPORT_SYMBOL(acpi_ut_value_exit); -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_ptr_exit * @@ -469,14 +471,14 @@ EXPORT_SYMBOL(acpi_ut_value_exit); * proc_name - Caller's procedure name * module_name - Caller's module name * component_id - Caller's component ID - * Value - Value to be printed with exit msg + * Ptr - Pointer to display * * RETURN: None * * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit value also. * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_ptr_exit ( @@ -494,7 +496,7 @@ acpi_ut_ptr_exit ( #endif -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_dump_buffer * @@ -507,7 +509,7 @@ acpi_ut_ptr_exit ( * * DESCRIPTION: Generic dump buffer in both hex and ascii. * - ****************************************************************************/ + ******************************************************************************/ void acpi_ut_dump_buffer ( @@ -533,34 +535,28 @@ acpi_ut_dump_buffer ( display = DB_BYTE_DISPLAY; } - acpi_os_printf ("\nOffset Value\n"); + /* Nasty little dump buffer routine! */ - /* - * Nasty little dump buffer routine! - */ while (i < count) { /* Print current offset */ - acpi_os_printf ("%05X ", (u32) i); + acpi_os_printf ("%6.4X: ", (u32) i); /* Print 16 hex chars */ for (j = 0; j < 16;) { if (i + j >= count) { - acpi_os_printf ("\n"); - return; - } + /* Dump fill spaces */ - /* Make sure that the s8 doesn't get sign-extended! */ + acpi_os_printf ("%*s", ((display * 2) + 1), " "); + j += display; + continue; + } switch (display) { - /* Default is BYTE display */ + default: /* Default is BYTE display */ - default: - - acpi_os_printf ("%02X ", - *((u8 *) &buffer[i + j])); - j += 1; + acpi_os_printf ("%02X ", buffer[i + j]); break; @@ -568,7 +564,6 @@ acpi_ut_dump_buffer ( ACPI_MOVE_16_TO_32 (&temp32, &buffer[i + j]); acpi_os_printf ("%04X ", temp32); - j += 2; break; @@ -576,7 +571,6 @@ acpi_ut_dump_buffer ( ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j]); acpi_os_printf ("%08X ", temp32); - j += 4; break; @@ -587,15 +581,17 @@ acpi_ut_dump_buffer ( ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j + 4]); acpi_os_printf ("%08X ", temp32); - j += 8; break; } + + j += display; } /* * Print the ASCII equivalent characters * But watch out for the bad unprintable ones... */ + acpi_os_printf (" "); for (j = 0; j < 16; j++) { if (i + j >= count) { acpi_os_printf ("\n"); diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index 9a52ad52a23..bc540302268 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -51,12 +51,23 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utdelete") +/* Local prototypes */ + +static void +acpi_ut_delete_internal_obj ( + union acpi_operand_object *object); + +static void +acpi_ut_update_ref_count ( + union acpi_operand_object *object, + u32 action); + /******************************************************************************* * * FUNCTION: acpi_ut_delete_internal_obj * - * PARAMETERS: *Object - Pointer to the list to be deleted + * PARAMETERS: Object - Object to be deleted * * RETURN: None * @@ -65,7 +76,7 @@ * ******************************************************************************/ -void +static void acpi_ut_delete_internal_obj ( union acpi_operand_object *object) { @@ -152,7 +163,8 @@ acpi_ut_delete_internal_obj ( case ACPI_TYPE_MUTEX: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Mutex %p, Semaphore %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Mutex %p, Semaphore %p\n", object, object->mutex.semaphore)); acpi_ex_unlink_mutex (object); @@ -162,7 +174,8 @@ acpi_ut_delete_internal_obj ( case ACPI_TYPE_EVENT: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Event %p, Semaphore %p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Event %p, Semaphore %p\n", object, object->event.semaphore)); (void) acpi_os_delete_semaphore (object->event.semaphore); @@ -172,7 +185,8 @@ acpi_ut_delete_internal_obj ( case ACPI_TYPE_METHOD: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Method %p\n", object)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Method %p\n", object)); /* Delete the method semaphore if it exists */ @@ -185,7 +199,8 @@ acpi_ut_delete_internal_obj ( case ACPI_TYPE_REGION: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Region %p\n", object)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Region %p\n", object)); second_desc = acpi_ns_get_secondary_object (object); if (second_desc) { @@ -212,7 +227,8 @@ acpi_ut_delete_internal_obj ( case ACPI_TYPE_BUFFER_FIELD: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Buffer Field %p\n", object)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "***** Buffer Field %p\n", object)); second_desc = acpi_ns_get_secondary_object (object); if (second_desc) { @@ -247,7 +263,7 @@ acpi_ut_delete_internal_obj ( * * FUNCTION: acpi_ut_delete_internal_object_list * - * PARAMETERS: *obj_list - Pointer to the list to be deleted + * PARAMETERS: obj_list - Pointer to the list to be deleted * * RETURN: None * @@ -283,7 +299,7 @@ acpi_ut_delete_internal_object_list ( * * FUNCTION: acpi_ut_update_ref_count * - * PARAMETERS: *Object - Object whose ref count is to be updated + * PARAMETERS: Object - Object whose ref count is to be updated * Action - What to do * * RETURN: New ref count @@ -312,7 +328,8 @@ acpi_ut_update_ref_count ( new_count = count; /* - * Perform the reference count action (increment, decrement, or force delete) + * Perform the reference count action + * (increment, decrement, or force delete) */ switch (action) { @@ -321,7 +338,8 @@ acpi_ut_update_ref_count ( new_count++; object->common.reference_count = new_count; - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Incremented]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Refs=%X, [Incremented]\n", object, new_count)); break; @@ -329,7 +347,8 @@ acpi_ut_update_ref_count ( case REF_DECREMENT: if (count < 1) { - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, can't decrement! (Set to 0)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Refs=%X, can't decrement! (Set to 0)\n", object, new_count)); new_count = 0; @@ -337,12 +356,14 @@ acpi_ut_update_ref_count ( else { new_count--; - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Decremented]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Refs=%X, [Decremented]\n", object, new_count)); } if (ACPI_GET_OBJECT_TYPE (object) == ACPI_TYPE_METHOD) { - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Method Obj %p Refs=%X, [Decremented]\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Method Obj %p Refs=%X, [Decremented]\n", object, new_count)); } @@ -356,7 +377,8 @@ acpi_ut_update_ref_count ( case REF_FORCE_DELETE: - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, Force delete! (Set to 0)\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Obj %p Refs=%X, Force delete! (Set to 0)\n", object, count)); new_count = 0; @@ -390,7 +412,7 @@ acpi_ut_update_ref_count ( * * FUNCTION: acpi_ut_update_object_reference * - * PARAMETERS: *Object - Increment ref count for this object + * PARAMETERS: Object - Increment ref count for this object * and all sub-objects * Action - Either REF_INCREMENT or REF_DECREMENT or * REF_FORCE_DELETE @@ -431,7 +453,8 @@ acpi_ut_update_object_reference ( /* Make sure that this isn't a namespace handle */ if (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED) { - ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p is NS handle\n", object)); + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, + "Object %p is NS handle\n", object)); return_ACPI_STATUS (AE_OK); } @@ -614,8 +637,8 @@ error_exit: * * FUNCTION: acpi_ut_add_reference * - * PARAMETERS: *Object - Object whose reference count is to be - * incremented + * PARAMETERS: Object - Object whose reference count is to be + * incremented * * RETURN: None * @@ -652,7 +675,7 @@ acpi_ut_add_reference ( * * FUNCTION: acpi_ut_remove_reference * - * PARAMETERS: *Object - Object whose ref count will be decremented + * PARAMETERS: Object - Object whose ref count will be decremented * * RETURN: None * diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index ead27d2c4d1..00046dd5d92 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -50,6 +50,19 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("uteval") +/* Local prototypes */ + +static void +acpi_ut_copy_id_string ( + char *destination, + char *source, + acpi_size max_length); + +static acpi_status +acpi_ut_translate_one_cid ( + union acpi_operand_object *obj_desc, + struct acpi_compatible_id *one_cid); + /******************************************************************************* * @@ -237,9 +250,9 @@ acpi_ut_evaluate_object ( * * FUNCTION: acpi_ut_evaluate_numeric_object * - * PARAMETERS: *object_name - Object name to be evaluated + * PARAMETERS: object_name - Object name to be evaluated * device_node - Node for the device - * *Address - Where the value is returned + * Address - Where the value is returned * * RETURN: Status * @@ -303,7 +316,6 @@ acpi_ut_copy_id_string ( acpi_size max_length) { - /* * Workaround for ID strings that have a leading asterisk. This construct * is not allowed by the ACPI specification (ID strings must be @@ -325,7 +337,7 @@ acpi_ut_copy_id_string ( * FUNCTION: acpi_ut_execute_HID * * PARAMETERS: device_node - Node for the device - * *Hid - Where the HID is returned + * Hid - Where the HID is returned * * RETURN: Status * @@ -429,7 +441,7 @@ acpi_ut_translate_one_cid ( * FUNCTION: acpi_ut_execute_CID * * PARAMETERS: device_node - Node for the device - * *Cid - Where the CID is returned + * return_cid_list - Where the CID list is returned * * RETURN: Status * @@ -488,10 +500,10 @@ acpi_ut_execute_CID ( cid_list->size = size; /* - * A _CID can return either a single compatible ID or a package of compatible - * IDs. Each compatible ID can be one of the following: - * -- Number (32 bit compressed EISA ID) or - * -- String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss"). + * A _CID can return either a single compatible ID or a package of + * compatible IDs. Each compatible ID can be one of the following: + * 1) Integer (32 bit compressed EISA ID) or + * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss") */ /* The _CID object can be either a single CID or a package (list) of CIDs */ @@ -534,7 +546,7 @@ acpi_ut_execute_CID ( * FUNCTION: acpi_ut_execute_UID * * PARAMETERS: device_node - Node for the device - * *Uid - Where the UID is returned + * Uid - Where the UID is returned * * RETURN: Status * @@ -587,7 +599,7 @@ acpi_ut_execute_UID ( * FUNCTION: acpi_ut_execute_STA * * PARAMETERS: device_node - Node for the device - * *Flags - Where the status flags are returned + * Flags - Where the status flags are returned * * RETURN: Status * @@ -641,7 +653,7 @@ acpi_ut_execute_STA ( * FUNCTION: acpi_ut_execute_Sxds * * PARAMETERS: device_node - Node for the device - * *Flags - Where the status flags are returned + * Flags - Where the status flags are returned * * RETURN: Status * diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index 25b0f8ae1bc..4146019b543 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -44,7 +44,6 @@ #define DEFINE_ACPI_GLOBALS #include - #include #include @@ -52,13 +51,14 @@ ACPI_MODULE_NAME ("utglobal") -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_format_exception * * PARAMETERS: Status - The acpi_status code to be formatted * - * RETURN: A string containing the exception text + * RETURN: A string containing the exception text. A valid pointer is + * always returned. * * DESCRIPTION: This function translates an ACPI exception into an ASCII string. * @@ -68,8 +68,8 @@ const char * acpi_format_exception ( acpi_status status) { - const char *exception = "UNKNOWN_STATUS_CODE"; acpi_status sub_status; + const char *exception = NULL; ACPI_FUNCTION_NAME ("format_exception"); @@ -82,57 +82,55 @@ acpi_format_exception ( if (sub_status <= AE_CODE_ENV_MAX) { exception = acpi_gbl_exception_names_env [sub_status]; - break; } - goto unknown; + break; case AE_CODE_PROGRAMMER: if (sub_status <= AE_CODE_PGM_MAX) { exception = acpi_gbl_exception_names_pgm [sub_status -1]; - break; } - goto unknown; + break; case AE_CODE_ACPI_TABLES: if (sub_status <= AE_CODE_TBL_MAX) { exception = acpi_gbl_exception_names_tbl [sub_status -1]; - break; } - goto unknown; + break; case AE_CODE_AML: if (sub_status <= AE_CODE_AML_MAX) { exception = acpi_gbl_exception_names_aml [sub_status -1]; - break; } - goto unknown; + break; case AE_CODE_CONTROL: if (sub_status <= AE_CODE_CTRL_MAX) { exception = acpi_gbl_exception_names_ctrl [sub_status -1]; - break; } - goto unknown; + break; default: - goto unknown; + break; } + if (!exception) { + /* Exception code was not recognized */ - return ((const char *) exception); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown exception code: 0x%8.8X\n", status)); -unknown: + return ((const char *) "UNKNOWN_STATUS_CODE"); + } - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown exception code: 0x%8.8X\n", status)); return ((const char *) exception); } -/****************************************************************************** +/******************************************************************************* * * Static global variable initialization. * @@ -212,13 +210,12 @@ const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STR }; -/****************************************************************************** +/******************************************************************************* * * Namespace globals * ******************************************************************************/ - /* * Predefined ACPI Names (Built-in to the Interpreter) * @@ -241,9 +238,11 @@ const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = #if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) {"_OSI", ACPI_TYPE_METHOD, (char *) 1}, #endif - {NULL, ACPI_TYPE_ANY, NULL} /* Table terminator */ -}; + /* Table terminator */ + + {NULL, ACPI_TYPE_ANY, NULL} +}; /* * Properties of the ACPI Object Types, both internal and external. @@ -288,22 +287,25 @@ const u8 acpi_gbl_ns_properties[] = /* Hex to ASCII conversion table */ static const char acpi_gbl_hex_to_ascii[] = - {'0','1','2','3','4','5','6','7', - '8','9','A','B','C','D','E','F'}; +{ + '0','1','2','3','4','5','6','7', + '8','9','A','B','C','D','E','F' +}; + -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_hex_to_ascii_char * * PARAMETERS: Integer - Contains the hex digit * Position - bit position of the digit within the - * integer + * integer (multiple of 4) * - * RETURN: Ascii character + * RETURN: The converted Ascii character * - * DESCRIPTION: Convert a hex digit to an ascii character + * DESCRIPTION: Convert a hex digit to an Ascii character * - ****************************************************************************/ + ******************************************************************************/ char acpi_ut_hex_to_ascii_char ( @@ -315,7 +317,7 @@ acpi_ut_hex_to_ascii_char ( } -/****************************************************************************** +/******************************************************************************* * * Table name globals * @@ -324,7 +326,7 @@ acpi_ut_hex_to_ascii_char ( * that are not used by the subsystem are simply ignored. * * Do NOT add any table to this list that is not consumed directly by this - * subsystem. + * subsystem (No MADT, ECDT, SBST, etc.) * ******************************************************************************/ @@ -391,7 +393,7 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVE /* ACPI_EVENT_RTC */ {ACPI_BITREG_RT_CLOCK_STATUS, ACPI_BITREG_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_ENABLE}, }; -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_region_name * @@ -401,7 +403,7 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVE * * DESCRIPTION: Translate a Space ID into a name string (Debug only) * - ****************************************************************************/ + ******************************************************************************/ /* Region type decoding */ @@ -429,7 +431,6 @@ acpi_ut_get_region_name ( { return ("user_defined_region"); } - else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) { return ("invalid_space_id"); @@ -439,7 +440,7 @@ acpi_ut_get_region_name ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_event_name * @@ -449,7 +450,7 @@ acpi_ut_get_region_name ( * * DESCRIPTION: Translate a Event ID into a name string (Debug only) * - ****************************************************************************/ + ******************************************************************************/ /* Event type decoding */ @@ -477,7 +478,7 @@ acpi_ut_get_event_name ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_type_name * @@ -487,20 +488,21 @@ acpi_ut_get_event_name ( * * DESCRIPTION: Translate a Type ID into a name string (Debug only) * - ****************************************************************************/ + ******************************************************************************/ /* * Elements of acpi_gbl_ns_type_names below must match * one-to-one with values of acpi_object_type * - * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; when - * stored in a table it really means that we have thus far seen no evidence to - * indicate what type is actually going to be stored for this entry. + * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; + * when stored in a table it really means that we have thus far seen no + * evidence to indicate what type is actually going to be stored for this entry. */ static const char acpi_gbl_bad_type[] = "UNDEFINED"; -#define TYPE_NAME_LENGTH 12 /* Maximum length of each string */ -static const char *acpi_gbl_ns_type_names[] = /* printable names of ACPI types */ +/* Printable names of the ACPI object types */ + +static const char *acpi_gbl_ns_type_names[] = { /* 00 */ "Untyped", /* 01 */ "Integer", @@ -564,7 +566,7 @@ acpi_ut_get_object_type_name ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_node_name * @@ -574,7 +576,7 @@ acpi_ut_get_object_type_name ( * * DESCRIPTION: Validate the node and return the node's ACPI name. * - ****************************************************************************/ + ******************************************************************************/ char * acpi_ut_get_node_name ( @@ -618,7 +620,7 @@ acpi_ut_get_node_name ( } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_descriptor_name * @@ -628,9 +630,11 @@ acpi_ut_get_node_name ( * * DESCRIPTION: Validate object and return the descriptor type * - ****************************************************************************/ + ******************************************************************************/ + +/* Printable names of object descriptor types */ -static const char *acpi_gbl_desc_type_names[] = /* printable names of descriptor types */ +static const char *acpi_gbl_desc_type_names[] = { /* 00 */ "Invalid", /* 01 */ "Cached", @@ -676,17 +680,18 @@ acpi_ut_get_descriptor_name ( * Strings and procedures used for debug only */ -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_get_mutex_name * - * PARAMETERS: None. + * PARAMETERS: mutex_id - The predefined ID for this mutex. * - * RETURN: Status + * RETURN: String containing the name of the mutex. Always returns a valid + * pointer. * * DESCRIPTION: Translate a mutex ID into a name string (Debug only) * - ****************************************************************************/ + ******************************************************************************/ char * acpi_ut_get_mutex_name ( @@ -700,21 +705,20 @@ acpi_ut_get_mutex_name ( return (acpi_gbl_mutex_names[mutex_id]); } - #endif -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_valid_object_type * * PARAMETERS: Type - Object type to be validated * - * RETURN: TRUE if valid object type + * RETURN: TRUE if valid object type, FALSE otherwise * * DESCRIPTION: Validate an object type * - ****************************************************************************/ + ******************************************************************************/ u8 acpi_ut_valid_object_type ( @@ -732,7 +736,7 @@ acpi_ut_valid_object_type ( } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_allocate_owner_id * @@ -740,7 +744,10 @@ acpi_ut_valid_object_type ( * * DESCRIPTION: Allocate a table or method owner id * - ***************************************************************************/ + * NOTE: this algorithm has a wraparound problem at 64_k method invocations, and + * should be revisited (TBD) + * + ******************************************************************************/ acpi_owner_id acpi_ut_allocate_owner_id ( @@ -796,16 +803,18 @@ acpi_ut_allocate_owner_id ( } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_ut_init_globals * - * PARAMETERS: none + * PARAMETERS: None + * + * RETURN: None * * DESCRIPTION: Init library globals. All globals that require specific * initialization should be initialized here! * - ***************************************************************************/ + ******************************************************************************/ void acpi_ut_init_globals ( diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c index bdbadaf48d2..7f3713889ff 100644 --- a/drivers/acpi/utilities/utinit.c +++ b/drivers/acpi/utilities/utinit.c @@ -49,19 +49,29 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utinit") +/* Local prototypes */ + +static void +acpi_ut_fadt_register_error ( + char *register_name, + u32 value, + acpi_size offset); + +static void acpi_ut_terminate ( + void); + /******************************************************************************* * * FUNCTION: acpi_ut_fadt_register_error * - * PARAMETERS: *register_name - Pointer to string identifying register + * PARAMETERS: register_name - Pointer to string identifying register * Value - Actual register contents value - * acpi_test_spec_section - TDS section containing assertion - * acpi_assertion - Assertion number being tested + * Offset - Byte offset in the FADT * * RETURN: AE_BAD_VALUE * - * DESCRIPTION: Display failure message and link failure to TDS assertion + * DESCRIPTION: Display failure message * ******************************************************************************/ @@ -166,12 +176,13 @@ acpi_ut_validate_fadt ( * * RETURN: none * - * DESCRIPTION: free global memory + * DESCRIPTION: Free global memory * ******************************************************************************/ -void -acpi_ut_terminate (void) +static void +acpi_ut_terminate ( + void) { struct acpi_gpe_block_info *gpe_block; struct acpi_gpe_block_info *next_gpe_block; @@ -183,8 +194,6 @@ acpi_ut_terminate (void) /* Free global tables, etc. */ - - /* Free global GPE blocks and related info structures */ gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; @@ -221,7 +230,8 @@ acpi_ut_terminate (void) ******************************************************************************/ void -acpi_ut_subsystem_shutdown (void) +acpi_ut_subsystem_shutdown ( + void) { ACPI_FUNCTION_TRACE ("ut_subsystem_shutdown"); @@ -229,14 +239,16 @@ acpi_ut_subsystem_shutdown (void) /* Just exit if subsystem is already shutdown */ if (acpi_gbl_shutdown) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "ACPI Subsystem is already terminated\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "ACPI Subsystem is already terminated\n")); return_VOID; } /* Subsystem appears active, go ahead and shut it down */ acpi_gbl_shutdown = TRUE; - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Shutting down ACPI Subsystem...\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Shutting down ACPI Subsystem...\n")); /* Close the acpi_event Handling */ diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c index 2525c1a9354..0d527c91543 100644 --- a/drivers/acpi/utilities/utmath.c +++ b/drivers/acpi/utilities/utmath.c @@ -259,6 +259,8 @@ acpi_ut_divide ( * * FUNCTION: acpi_ut_short_divide, acpi_ut_divide * + * PARAMETERS: See function headers above + * * DESCRIPTION: Native versions of the ut_divide functions. Use these if either * 1) The target is a 64-bit platform and therefore 64-bit * integer math is supported directly by the machine. diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index f6598547389..f6de4ed3d52 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -49,12 +49,57 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utmisc") +/* Local prototypes */ + +static acpi_status +acpi_ut_create_mutex ( + acpi_mutex_handle mutex_id); + +static acpi_status +acpi_ut_delete_mutex ( + acpi_mutex_handle mutex_id); + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strupr (strupr) + * + * PARAMETERS: src_string - The source string to convert + * + * RETURN: Converted src_string (same as input pointer) + * + * DESCRIPTION: Convert string to uppercase + * + * NOTE: This is not a POSIX function, so it appears here, not in utclib.c + * + ******************************************************************************/ + +char * +acpi_ut_strupr ( + char *src_string) +{ + char *string; + + + ACPI_FUNCTION_ENTRY (); + + + /* Walk entire string, uppercasing the letters */ + + for (string = src_string; *string; string++) { + *string = (char) ACPI_TOUPPER (*string); + } + + return (src_string); +} + /******************************************************************************* * * FUNCTION: acpi_ut_print_string * * PARAMETERS: String - Null terminated ASCII string + * max_length - Maximum output length * * RETURN: None * @@ -148,6 +193,8 @@ acpi_ut_print_string ( * * PARAMETERS: Value - Value to be converted * + * RETURN: u32 integer with bytes swapped + * * DESCRIPTION: Convert a 32-bit value to big-endian (swap the bytes) * ******************************************************************************/ @@ -160,7 +207,6 @@ acpi_ut_dword_byte_swap ( u32 value; u8 bytes[4]; } out; - union { u32 value; u8 bytes[4]; @@ -219,7 +265,8 @@ acpi_ut_set_integer_width ( * * FUNCTION: acpi_ut_display_init_pathname * - * PARAMETERS: obj_handle - Handle whose pathname will be displayed + * PARAMETERS: Type - Object type of the node + * obj_handle - Handle whose pathname will be displayed * Path - Additional path string to be appended. * (NULL if no extra path) * @@ -270,7 +317,8 @@ acpi_ut_display_init_pathname ( /* Print the object type and pathname */ - acpi_os_printf ("%-12s %s", acpi_ut_get_type_name (type), (char *) buffer.pointer); + acpi_os_printf ("%-12s %s", + acpi_ut_get_type_name (type), (char *) buffer.pointer); /* Extra path is used to append names like _STA, _INI, etc. */ @@ -288,9 +336,9 @@ acpi_ut_display_init_pathname ( * * FUNCTION: acpi_ut_valid_acpi_name * - * PARAMETERS: Character - The character to be examined + * PARAMETERS: Name - The name to be examined * - * RETURN: 1 if Character may appear in a name, else 0 + * RETURN: TRUE if the name is valid, FALSE otherwise * * DESCRIPTION: Check for a valid ACPI name. Each character must be one of: * 1) Upper case alpha @@ -493,40 +541,6 @@ error_exit: } -/******************************************************************************* - * - * FUNCTION: acpi_ut_strupr - * - * PARAMETERS: src_string - The source string to convert to - * - * RETURN: src_string - * - * DESCRIPTION: Convert string to uppercase - * - ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE -char * -acpi_ut_strupr ( - char *src_string) -{ - char *string; - - - ACPI_FUNCTION_ENTRY (); - - - /* Walk entire string, uppercasing the letters */ - - for (string = src_string; *string; ) { - *string = (char) ACPI_TOUPPER (*string); - string++; - } - - return (src_string); -} -#endif /* ACPI_FUTURE_USAGE */ - - /******************************************************************************* * * FUNCTION: acpi_ut_mutex_initialize @@ -611,7 +625,7 @@ acpi_ut_mutex_terminate ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_create_mutex ( acpi_mutex_handle mutex_id) { @@ -648,7 +662,7 @@ acpi_ut_create_mutex ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_delete_mutex ( acpi_mutex_handle mutex_id) { @@ -715,16 +729,16 @@ acpi_ut_acquire_mutex ( if (acpi_gbl_mutex_info[i].owner_id == this_thread_id) { if (i == mutex_id) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Mutex [%s] already acquired by this thread [%X]\n", - acpi_ut_get_mutex_name (mutex_id), this_thread_id)); + "Mutex [%s] already acquired by this thread [%X]\n", + acpi_ut_get_mutex_name (mutex_id), this_thread_id)); return (AE_ALREADY_ACQUIRED); } ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Invalid acquire order: Thread %X owns [%s], wants [%s]\n", - this_thread_id, acpi_ut_get_mutex_name (i), - acpi_ut_get_mutex_name (mutex_id))); + "Invalid acquire order: Thread %X owns [%s], wants [%s]\n", + this_thread_id, acpi_ut_get_mutex_name (i), + acpi_ut_get_mutex_name (mutex_id))); return (AE_ACQUIRE_DEADLOCK); } @@ -733,22 +747,23 @@ acpi_ut_acquire_mutex ( #endif ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, - "Thread %X attempting to acquire Mutex [%s]\n", - this_thread_id, acpi_ut_get_mutex_name (mutex_id))); + "Thread %X attempting to acquire Mutex [%s]\n", + this_thread_id, acpi_ut_get_mutex_name (mutex_id))); status = acpi_os_wait_semaphore (acpi_gbl_mutex_info[mutex_id].mutex, 1, ACPI_WAIT_FOREVER); if (ACPI_SUCCESS (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X acquired Mutex [%s]\n", - this_thread_id, acpi_ut_get_mutex_name (mutex_id))); + this_thread_id, acpi_ut_get_mutex_name (mutex_id))); acpi_gbl_mutex_info[mutex_id].use_count++; acpi_gbl_mutex_info[mutex_id].owner_id = this_thread_id; } else { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Thread %X could not acquire Mutex [%s] %s\n", - this_thread_id, acpi_ut_get_mutex_name (mutex_id), - acpi_format_exception (status))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Thread %X could not acquire Mutex [%s] %s\n", + this_thread_id, acpi_ut_get_mutex_name (mutex_id), + acpi_format_exception (status))); } return (status); @@ -793,8 +808,8 @@ acpi_ut_release_mutex ( */ if (acpi_gbl_mutex_info[mutex_id].owner_id == ACPI_MUTEX_NOT_ACQUIRED) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Mutex [%s] is not acquired, cannot release\n", - acpi_ut_get_mutex_name (mutex_id))); + "Mutex [%s] is not acquired, cannot release\n", + acpi_ut_get_mutex_name (mutex_id))); return (AE_NOT_ACQUIRED); } @@ -812,8 +827,8 @@ acpi_ut_release_mutex ( } ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Invalid release order: owns [%s], releasing [%s]\n", - acpi_ut_get_mutex_name (i), acpi_ut_get_mutex_name (mutex_id))); + "Invalid release order: owns [%s], releasing [%s]\n", + acpi_ut_get_mutex_name (i), acpi_ut_get_mutex_name (mutex_id))); return (AE_RELEASE_DEADLOCK); } @@ -826,13 +841,14 @@ acpi_ut_release_mutex ( status = acpi_os_signal_semaphore (acpi_gbl_mutex_info[mutex_id].mutex, 1); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Thread %X could not release Mutex [%s] %s\n", - this_thread_id, acpi_ut_get_mutex_name (mutex_id), - acpi_format_exception (status))); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Thread %X could not release Mutex [%s] %s\n", + this_thread_id, acpi_ut_get_mutex_name (mutex_id), + acpi_format_exception (status))); } else { ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X released Mutex [%s]\n", - this_thread_id, acpi_ut_get_mutex_name (mutex_id))); + this_thread_id, acpi_ut_get_mutex_name (mutex_id))); } return (status); @@ -843,11 +859,11 @@ acpi_ut_release_mutex ( * * FUNCTION: acpi_ut_create_update_state_and_push * - * PARAMETERS: *Object - Object to be added to the new state + * PARAMETERS: Object - Object to be added to the new state * Action - Increment/Decrement * state_list - List the state will be added to * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Create a new state and push it * @@ -885,15 +901,16 @@ acpi_ut_create_update_state_and_push ( * * FUNCTION: acpi_ut_create_pkg_state_and_push * - * PARAMETERS: *Object - Object to be added to the new state + * PARAMETERS: Object - Object to be added to the new state * Action - Increment/Decrement * state_list - List the state will be added to * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Create a new state and push it * ******************************************************************************/ + #ifdef ACPI_FUTURE_USAGE acpi_status acpi_ut_create_pkg_state_and_push ( @@ -925,7 +942,7 @@ acpi_ut_create_pkg_state_and_push ( * PARAMETERS: list_head - Head of the state stack * State - State object to push * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Push a state object onto a state stack * @@ -954,7 +971,7 @@ acpi_ut_push_generic_state ( * * PARAMETERS: list_head - Head of the state stack * - * RETURN: Status + * RETURN: The popped state object * * DESCRIPTION: Pop a state object from a state stack * @@ -989,7 +1006,7 @@ acpi_ut_pop_generic_state ( * * PARAMETERS: None * - * RETURN: Status + * RETURN: The new state object. NULL on failure. * * DESCRIPTION: Create a generic state object. Attempt to obtain one from * the global state cache; If none available, create a new one. @@ -997,7 +1014,8 @@ acpi_ut_pop_generic_state ( ******************************************************************************/ union acpi_generic_state * -acpi_ut_create_generic_state (void) +acpi_ut_create_generic_state ( + void) { union acpi_generic_state *state; @@ -1023,7 +1041,7 @@ acpi_ut_create_generic_state (void) * * PARAMETERS: None * - * RETURN: Thread State + * RETURN: New Thread State. NULL on failure * * DESCRIPTION: Create a "Thread State" - a flavor of the generic state used * to track per-thread info during method execution @@ -1060,11 +1078,10 @@ acpi_ut_create_thread_state ( * * FUNCTION: acpi_ut_create_update_state * - * PARAMETERS: Object - Initial Object to be installed in the - * state - * Action - Update action to be performed + * PARAMETERS: Object - Initial Object to be installed in the state + * Action - Update action to be performed * - * RETURN: Status + * RETURN: New state object, null on failure * * DESCRIPTION: Create an "Update State" - a flavor of the generic state used * to update reference counts and delete complex objects such @@ -1104,11 +1121,10 @@ acpi_ut_create_update_state ( * * FUNCTION: acpi_ut_create_pkg_state * - * PARAMETERS: Object - Initial Object to be installed in the - * state - * Action - Update action to be performed + * PARAMETERS: Object - Initial Object to be installed in the state + * Action - Update action to be performed * - * RETURN: Status + * RETURN: New state object, null on failure * * DESCRIPTION: Create a "Package State" * @@ -1151,7 +1167,7 @@ acpi_ut_create_pkg_state ( * * PARAMETERS: None * - * RETURN: Status + * RETURN: New state object, null on failure * * DESCRIPTION: Create a "Control State" - a flavor of the generic state used * to support nested IF/WHILE constructs in the AML. @@ -1190,7 +1206,7 @@ acpi_ut_create_control_state ( * * PARAMETERS: State - The state object to be deleted * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Put a state object back into the global state cache. The object * is not actually freed at this time. @@ -1216,7 +1232,7 @@ acpi_ut_delete_generic_state ( * * PARAMETERS: None * - * RETURN: Status + * RETURN: None * * DESCRIPTION: Purge the global state object cache. Used during subsystem * termination. @@ -1240,7 +1256,10 @@ acpi_ut_delete_generic_state_cache ( * * FUNCTION: acpi_ut_walk_package_tree * - * PARAMETERS: obj_desc - The Package object on which to resolve refs + * PARAMETERS: source_object - The package to walk + * target_object - Target object (if package is being copied) + * walk_callback - Called once for each package element + * Context - Passed to the callback function * * RETURN: Status * @@ -1359,7 +1378,7 @@ acpi_ut_walk_package_tree ( * PARAMETERS: Buffer - Buffer to be scanned * Length - number of bytes to examine * - * RETURN: checksum + * RETURN: The generated checksum * * DESCRIPTION: Generate a checksum on a raw buffer * @@ -1442,7 +1461,6 @@ acpi_ut_get_resource_end_tag ( * PARAMETERS: module_name - Caller's module name (for error output) * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) - * Message - Error message to use on failure * * RETURN: None * @@ -1457,7 +1475,6 @@ acpi_ut_report_error ( u32 component_id) { - acpi_os_printf ("%8s-%04d: *** Error: ", module_name, line_number); } @@ -1469,7 +1486,6 @@ acpi_ut_report_error ( * PARAMETERS: module_name - Caller's module name (for error output) * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) - * Message - Error message to use on failure * * RETURN: None * @@ -1495,7 +1511,6 @@ acpi_ut_report_warning ( * PARAMETERS: module_name - Caller's module name (for error output) * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) - * Message - Error message to use on failure * * RETURN: None * diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index 9ee40a484e0..cd3899b9cc5 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -50,6 +50,25 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utobject") +/* Local prototypes */ + +static acpi_status +acpi_ut_get_simple_object_size ( + union acpi_operand_object *obj, + acpi_size *obj_length); + +static acpi_status +acpi_ut_get_package_object_size ( + union acpi_operand_object *obj, + acpi_size *obj_length); + +static acpi_status +acpi_ut_get_element_length ( + u8 object_type, + union acpi_operand_object *source_object, + union acpi_generic_state *state, + void *context); + /******************************************************************************* * @@ -60,7 +79,7 @@ * component_id - Component type of caller * Type - ACPI Type of the new object * - * RETURN: Object - The new object. Null on failure + * RETURN: A new internal object, null on failure * * DESCRIPTION: Create and initialize a new internal object. * @@ -83,7 +102,8 @@ acpi_ut_create_internal_object_dbg ( union acpi_operand_object *second_object; - ACPI_FUNCTION_TRACE_STR ("ut_create_internal_object_dbg", acpi_ut_get_type_name (type)); + ACPI_FUNCTION_TRACE_STR ("ut_create_internal_object_dbg", + acpi_ut_get_type_name (type)); /* Allocate the raw object descriptor */ @@ -99,7 +119,8 @@ acpi_ut_create_internal_object_dbg ( /* These types require a secondary object */ - second_object = acpi_ut_allocate_object_desc_dbg (module_name, line_number, component_id); + second_object = acpi_ut_allocate_object_desc_dbg (module_name, + line_number, component_id); if (!second_object) { acpi_ut_delete_object_desc (object); return_PTR (NULL); @@ -138,7 +159,7 @@ acpi_ut_create_internal_object_dbg ( * * PARAMETERS: buffer_size - Size of buffer to be created * - * RETURN: Pointer to a new Buffer object + * RETURN: Pointer to a new Buffer object, null on failure * * DESCRIPTION: Create a fully initialized buffer object * @@ -192,9 +213,9 @@ acpi_ut_create_buffer_object ( * * FUNCTION: acpi_ut_create_string_object * - * PARAMETERS: string_size - Size of string to be created. Does not - * include NULL terminator, this is added - * automatically. + * PARAMETERS: string_size - Size of string to be created. Does not + * include NULL terminator, this is added + * automatically. * * RETURN: Pointer to a new String object * @@ -249,7 +270,9 @@ acpi_ut_create_string_object ( * * PARAMETERS: Object - Object to be validated * - * RETURN: Validate a pointer to be an union acpi_operand_object + * RETURN: TRUE if object is valid, FALSE otherwise + * + * DESCRIPTION: Validate a pointer to be an union acpi_operand_object * ******************************************************************************/ @@ -399,8 +422,8 @@ acpi_ut_delete_object_cache ( * * FUNCTION: acpi_ut_get_simple_object_size * - * PARAMETERS: *internal_object - Pointer to the object we are examining - * *obj_length - Where the length is returned + * PARAMETERS: internal_object - An ACPI operand object + * obj_length - Where the length is returned * * RETURN: Status * @@ -412,7 +435,7 @@ acpi_ut_delete_object_cache ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_get_simple_object_size ( union acpi_operand_object *internal_object, acpi_size *obj_length) @@ -424,8 +447,10 @@ acpi_ut_get_simple_object_size ( ACPI_FUNCTION_TRACE_PTR ("ut_get_simple_object_size", internal_object); - /* Handle a null object (Could be a uninitialized package element -- which is legal) */ - + /* + * Handle a null object (Could be a uninitialized package + * element -- which is legal) + */ if (!internal_object) { *obj_length = 0; return_ACPI_STATUS (AE_OK); @@ -480,7 +505,8 @@ acpi_ut_get_simple_object_size ( * Get the actual length of the full pathname to this object. * The reference will be converted to the pathname to the object */ - length += ACPI_ROUND_UP_TO_NATIVE_WORD (acpi_ns_get_pathname_length (internal_object->reference.node)); + length += ACPI_ROUND_UP_TO_NATIVE_WORD ( + acpi_ns_get_pathname_length (internal_object->reference.node)); break; default: @@ -530,7 +556,7 @@ acpi_ut_get_simple_object_size ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_get_element_length ( u8 object_type, union acpi_operand_object *source_object, @@ -582,8 +608,8 @@ acpi_ut_get_element_length ( * * FUNCTION: acpi_ut_get_package_object_size * - * PARAMETERS: *internal_object - Pointer to the object we are examining - * *obj_length - Where the length is returned + * PARAMETERS: internal_object - An ACPI internal object + * obj_length - Where the length is returned * * RETURN: Status * @@ -595,7 +621,7 @@ acpi_ut_get_element_length ( * ******************************************************************************/ -acpi_status +static acpi_status acpi_ut_get_package_object_size ( union acpi_operand_object *internal_object, acpi_size *obj_length) @@ -636,8 +662,8 @@ acpi_ut_get_package_object_size ( * * FUNCTION: acpi_ut_get_object_size * - * PARAMETERS: *internal_object - Pointer to the object we are examining - * *obj_length - Where the length will be returned + * PARAMETERS: internal_object - An ACPI internal object + * obj_length - Where the length will be returned * * RETURN: Status * @@ -647,7 +673,7 @@ acpi_ut_get_package_object_size ( ******************************************************************************/ acpi_status -acpi_ut_get_object_size( +acpi_ut_get_object_size ( union acpi_operand_object *internal_object, acpi_size *obj_length) { diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c index 97a91f3f06f..e8803d81065 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/utilities/utxface.c @@ -73,6 +73,7 @@ acpi_initialize_subsystem ( { acpi_status status; + ACPI_FUNCTION_TRACE ("acpi_initialize_subsystem"); @@ -105,7 +106,6 @@ acpi_initialize_subsystem ( * Initialize the namespace manager and * the root of the namespace tree */ - status = acpi_ns_root_initialize (); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("Namespace initialization failure, %s\n", @@ -113,7 +113,6 @@ acpi_initialize_subsystem ( return_ACPI_STATUS (status); } - /* If configured, initialize the AML debugger */ ACPI_DEBUGGER_EXEC (status = acpi_db_initialize ()); @@ -150,7 +149,8 @@ acpi_enable_subsystem ( * The values from the FADT are validated here. */ if (!(flags & ACPI_NO_HARDWARE_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI hardware\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Initializing ACPI hardware\n")); status = acpi_hw_initialize (); if (ACPI_FAILURE (status)) { @@ -178,7 +178,8 @@ acpi_enable_subsystem ( * install_address_space_handler interface. */ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing default address space handlers\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Installing default address space handlers\n")); status = acpi_ev_install_region_handlers (); if (ACPI_FAILURE (status)) { @@ -189,12 +190,14 @@ acpi_enable_subsystem ( /* * Initialize ACPI Event handling (Fixed and General Purpose) * - * NOTE: We must have the hardware AND events initialized before we can execute - * ANY control methods SAFELY. Any control method can require ACPI hardware - * support, so the hardware MUST be initialized before execution! + * NOTE: We must have the hardware AND events initialized before we can + * execute ANY control methods SAFELY. Any control method can require + * ACPI hardware support, so the hardware MUST be initialized before + * execution! */ if (!(flags & ACPI_NO_EVENT_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI events\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Initializing ACPI events\n")); status = acpi_ev_initialize_events (); if (ACPI_FAILURE (status)) { @@ -205,7 +208,8 @@ acpi_enable_subsystem ( /* Install the SCI handler and Global Lock handler */ if (!(flags & ACPI_NO_HANDLER_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL handlers\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Installing SCI/GL handlers\n")); status = acpi_ev_install_xrupt_handlers (); if (ACPI_FAILURE (status)) { @@ -247,7 +251,8 @@ acpi_initialize_objects ( * contain executable AML (see call to acpi_ns_initialize_objects below). */ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Executing _REG op_region methods\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Executing _REG op_region methods\n")); status = acpi_ev_initialize_op_regions (); if (ACPI_FAILURE (status)) { @@ -261,7 +266,8 @@ acpi_initialize_objects ( * objects: operation_regions, buffer_fields, Buffers, and Packages. */ if (!(flags & ACPI_NO_OBJECT_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Completing Initialization of ACPI Objects\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Completing Initialization of ACPI Objects\n")); status = acpi_ns_initialize_objects (); if (ACPI_FAILURE (status)) { @@ -274,7 +280,8 @@ acpi_initialize_objects ( * This runs the _STA and _INI methods. */ if (!(flags & ACPI_NO_DEVICE_INIT)) { - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI Devices\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[Init] Initializing ACPI Devices\n")); status = acpi_ns_initialize_devices (); if (ACPI_FAILURE (status)) { @@ -307,7 +314,8 @@ acpi_initialize_objects ( ******************************************************************************/ acpi_status -acpi_terminate (void) +acpi_terminate ( + void) { acpi_status status; @@ -344,8 +352,7 @@ acpi_terminate (void) #ifdef ACPI_FUTURE_USAGE - -/***************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_subsystem_status * @@ -354,14 +361,16 @@ acpi_terminate (void) * RETURN: Status of the ACPI subsystem * * DESCRIPTION: Other drivers that use the ACPI subsystem should call this - * before making any other calls, to ensure the subsystem initial- - * ized successfully. + * before making any other calls, to ensure the subsystem + * initialized successfully. * - ****************************************************************************/ + ******************************************************************************/ acpi_status -acpi_subsystem_status (void) +acpi_subsystem_status ( + void) { + if (acpi_gbl_startup_flags & ACPI_INITIALIZED_OK) { return (AE_OK); } @@ -371,13 +380,12 @@ acpi_subsystem_status (void) } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: acpi_get_system_info * - * PARAMETERS: out_buffer - a pointer to a buffer to receive the - * resources for the device - * buffer_length - the number of bytes available in the buffer + * PARAMETERS: out_buffer - A buffer to receive the resources for the + * device * * RETURN: Status - the status of the call * @@ -395,8 +403,8 @@ acpi_get_system_info ( struct acpi_buffer *out_buffer) { struct acpi_system_info *info_ptr; - u32 i; acpi_status status; + u32 i; ACPI_FUNCTION_TRACE ("acpi_get_system_info"); @@ -466,6 +474,7 @@ EXPORT_SYMBOL(acpi_get_system_info); * FUNCTION: acpi_install_initialization_handler * * PARAMETERS: Handler - Callback procedure + * Function - Not (currently) used, see below * * RETURN: Status * @@ -495,7 +504,6 @@ acpi_install_initialization_handler ( #endif /* ACPI_FUTURE_USAGE */ - /***************************************************************************** * * FUNCTION: acpi_purge_cached_objects @@ -509,7 +517,8 @@ acpi_install_initialization_handler ( ****************************************************************************/ acpi_status -acpi_purge_cached_objects (void) +acpi_purge_cached_objects ( + void) { ACPI_FUNCTION_TRACE ("acpi_purge_cached_objects"); -- cgit v1.2.3 From ef7b06cd905424aea7c31f27fef622e84e75e650 Mon Sep 17 00:00:00 2001 From: David Shaohua Li Date: Mon, 18 Apr 2005 22:59:23 -0400 Subject: [ACPI] quiet dmesg related to ACPI PM of PCI devices DBG("No ACPI bus support for %s\n", dev->bus_id); http://bugzilla.kernel.org/show_bug.cgi?id=4277 Signed-off-by: David Shaohua Li Signed-off-by: Len Brown --- drivers/acpi/glue.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index b6d2045caf3..770cfc8b17e 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -29,7 +29,7 @@ int register_acpi_bus_type(struct acpi_bus_type *type) down_write(&bus_type_sem); list_add_tail(&type->list, &bus_type_list); up_write(&bus_type_sem); - DBG("ACPI bus type %s registered\n", type->bus->name); + printk(KERN_INFO PREFIX "bus type %s registered\n", type->bus->name); return 0; } return -ENODEV; @@ -45,7 +45,7 @@ int unregister_acpi_bus_type(struct acpi_bus_type *type) down_write(&bus_type_sem); list_del_init(&type->list); up_write(&bus_type_sem); - DBG("ACPI bus type %s unregistered\n", type->bus->name); + printk(KERN_INFO PREFIX "ACPI bus type %s unregistered\n", type->bus->name); return 0; } return -ENODEV; @@ -314,14 +314,12 @@ static int acpi_platform_notify(struct device *dev) } type = acpi_get_bus_type(dev->bus); if (!type) { - printk(KERN_INFO PREFIX "No ACPI bus support for %s\n", - dev->bus_id); + DBG("No ACPI bus support for %s\n", dev->bus_id); ret = -EINVAL; goto end; } if ((ret = type->find_device(dev, &handle)) != 0) - printk(KERN_INFO PREFIX "Can't get handler for %s\n", - dev->bus_id); + DBG("Can't get handler for %s\n", dev->bus_id); end: if (!ret) acpi_bind_one(dev, handle); -- cgit v1.2.3 From 590275ce72c48fdbddea057bc9ee379c1fd851ef Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 18 Apr 2005 23:52:17 -0400 Subject: [ACPI] cleanup: delete !IA64_SGI_SN from acpi/Kconfig Signed-off-by: Jesse Barnes Signed-off-by: Len Brown --- drivers/acpi/Kconfig | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 8b6de146255..84bbcb051cb 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -49,7 +49,6 @@ config ACPI_BOOT config ACPI_INTERPRETER bool - depends on !IA64_SGI_SN default y if ACPI_INTERPRETER @@ -108,7 +107,6 @@ config ACPI_BATTERY config ACPI_BUTTON tristate "Button" - depends on !IA64_SGI_SN default m help This driver registers for events based on buttons, such as the @@ -120,7 +118,6 @@ config ACPI_BUTTON config ACPI_VIDEO tristate "Video" depends on EXPERIMENTAL - depends on !IA64_SGI_SN default m help This driver implement the ACPI Extensions For Display Adapters @@ -142,7 +139,6 @@ config ACPI_HOTKEY config ACPI_FAN tristate "Fan" - depends on !IA64_SGI_SN default m help This driver adds support for ACPI fan devices, allowing user-mode @@ -150,7 +146,6 @@ config ACPI_FAN config ACPI_PROCESSOR tristate "Processor" - depends on !IA64_SGI_SN default m help This driver installs ACPI as the idle handler for Linux, and uses @@ -160,7 +155,6 @@ config ACPI_PROCESSOR config ACPI_HOTPLUG_CPU bool "Processor Hotplug (EXPERIMENTAL)" depends on ACPI_PROCESSOR && HOTPLUG_CPU && EXPERIMENTAL - depends on !IA64_SGI_SN select ACPI_CONTAINER default n ---help--- @@ -280,7 +274,6 @@ config ACPI_BLACKLIST_YEAR config ACPI_DEBUG bool "Debug Statements" - depends on !IA64_SGI_SN default n help The ACPI driver can optionally report errors with a great deal @@ -289,7 +282,6 @@ config ACPI_DEBUG config ACPI_BUS bool - depends on !IA64_SGI_SN default y config ACPI_EC @@ -303,17 +295,14 @@ config ACPI_EC config ACPI_POWER bool - depends on !IA64_SGI_SN default y config ACPI_PCI bool - depends on !IA64_SGI_SN default PCI config ACPI_SYSTEM bool - depends on !IA64_SGI_SN default y help This driver will enable your system to shut down using ACPI, and -- cgit v1.2.3 From a27ac38efd6dc6dccebfc9bcc475ab4aa5fc4a56 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 5 Apr 2019 00:07:45 -0500 Subject: [ACPI] fix merge error that broke CONFIG_ACPI_DEBUG=y build Signed-off-by: Len Brown --- drivers/acpi/namespace/nsdump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c index 4550e6f9809..6c2aef0e0dd 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/namespace/nsdump.c @@ -612,6 +612,7 @@ acpi_ns_dump_objects ( ACPI_NS_WALK_NO_UNLOCK, acpi_ns_dump_one_object, (void *) &info, NULL); } +#endif /* ACPI_FUTURE_USAGE */ /******************************************************************************* @@ -694,5 +695,4 @@ acpi_ns_dump_tables ( return_VOID; } #endif /* _ACPI_ASL_COMPILER */ -#endif /* ACPI_FUTURE_USAGE */ #endif /* defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) */ -- cgit v1.2.3 From 17e9c78a75ce9eacd61200f9e1f1924012e28846 Mon Sep 17 00:00:00 2001 From: Luming Yu Date: Fri, 22 Apr 2005 23:07:10 -0400 Subject: [ACPI] EC GPE-disabled issue http://bugzilla.kernel.org/show_bug.cgi?id=3851 Signed-off-by: Luming Yu Signed-off-by: Len Brown --- drivers/acpi/ec.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index a4b70dfdcf0..8e665f2e313 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -282,7 +282,7 @@ end: if(atomic_read(&ec->leaving_burst) == 2){ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); - while(!atomic_read(&ec->pending_gpe)){ + while(atomic_read(&ec->pending_gpe)){ msleep(1); } acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); @@ -365,7 +365,7 @@ end: if(atomic_read(&ec->leaving_burst) == 2){ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); - while(!atomic_read(&ec->pending_gpe)){ + while(atomic_read(&ec->pending_gpe)){ msleep(1); } acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); @@ -431,7 +431,6 @@ acpi_ec_query ( if (!ec || !data) return_VALUE(-EINVAL); -retry: *data = 0; if (ec->global_lock) { @@ -469,13 +468,9 @@ end: if(atomic_read(&ec->leaving_burst) == 2){ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n")); - while(!atomic_read(&ec->pending_gpe)){ - msleep(1); - } acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); - goto retry; + status = -ENODATA; } - return_VALUE(status); } @@ -514,8 +509,8 @@ acpi_ec_gpe_query ( ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name)); acpi_evaluate_object(ec->handle, object_name, NULL, NULL); - atomic_dec(&ec->pending_gpe); end: + atomic_dec(&ec->pending_gpe); return; } @@ -553,7 +548,7 @@ acpi_ec_gpe_handler ( !(value & ACPI_EC_FLAG_IBF))) { ec->expect_event = 0; wake_up(&ec->wait); - + return ACPI_INTERRUPT_HANDLED; } } @@ -561,8 +556,10 @@ acpi_ec_gpe_handler ( atomic_add(1, &ec->pending_gpe) ; status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, acpi_ec_gpe_query, ec); + return status == AE_OK ? + ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } - + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR); return status == AE_OK ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; } @@ -688,6 +685,7 @@ acpi_ec_read_info (struct seq_file *seq, void *offset) (u32) ec->status_addr.address, (u32) ec->data_addr.address); seq_printf(seq, "use global lock: %s\n", ec->global_lock?"yes":"no"); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); end: return_VALUE(0); -- cgit v1.2.3 From 6a2e9b738cb5c929df73b6acabdd8f9a4e9a0416 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Mon, 11 Jul 2005 21:13:56 -0700 Subject: [NET]: move config options out to individual protocols Move the protocol specific config options out to the specific protocols. With this change net/Kconfig now starts to become readable and serve as a good basis for further re-structuring. The menu structure is left almost intact, except that indention is fixed in most cases. Most visible are the INET changes where several "depends on INET" are replaced with a single ifdef INET / endif pair. Several new files were created to accomplish this change - they are small but serve the purpose that config options are now distributed out where they belongs. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller --- drivers/net/appletalk/Kconfig | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig index 69c488d933a..b14e89004c3 100644 --- a/drivers/net/appletalk/Kconfig +++ b/drivers/net/appletalk/Kconfig @@ -1,6 +1,33 @@ # # Appletalk driver configuration # +config ATALK + tristate "Appletalk protocol support" + select LLC + ---help--- + AppleTalk is the protocol that Apple computers can use to communicate + on a network. If your Linux box is connected to such a network and you + wish to connect to it, say Y. You will need to use the netatalk package + so that your Linux box can act as a print and file server for Macs as + well as access AppleTalk printers. Check out + on the WWW for details. + EtherTalk is the name used for AppleTalk over Ethernet and the + cheaper and slower LocalTalk is AppleTalk over a proprietary Apple + network using serial links. EtherTalk and LocalTalk are fully + supported by Linux. + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at . The + NET-3-HOWTO, available from + , contains valuable + information as well. + + To compile this driver as a module, choose M here: the module will be + called appletalk. You almost certainly want to compile it as a + module so you can restart your AppleTalk stack without rebooting + your machine. I hear that the GNU boycott of Apple is over, so + even politically correct people are allowed to say Y here. + config DEV_APPLETALK bool "Appletalk interfaces support" depends on ATALK -- cgit v1.2.3 From 02df8b9385c21fdba165bd380f60eca1d3b0578b Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Fri, 15 Apr 2005 15:07:10 -0400 Subject: [ACPI] enable C2 and C3 idle power states on SMP http://bugzilla.kernel.org/show_bug.cgi?id=4401 Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 37 ++++++++++++++ drivers/acpi/processor_idle.c | 105 ++++++++++++++++++++++++++------------- drivers/acpi/processor_perflib.c | 33 +----------- 3 files changed, 109 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index f4778747e88..e421842888b 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -255,6 +255,43 @@ acpi_processor_errata ( } +/* -------------------------------------------------------------------------- + Common ACPI processor fucntions + -------------------------------------------------------------------------- */ + +/* + * _PDC is required for a BIOS-OS handshake for most of the newer + * ACPI processor features. + */ + +int acpi_processor_set_pdc(struct acpi_processor *pr, + struct acpi_object_list *pdc_in) +{ + acpi_status status = AE_OK; + u32 arg0_buf[3]; + union acpi_object arg0 = {ACPI_TYPE_BUFFER}; + struct acpi_object_list no_object = {1, &arg0}; + struct acpi_object_list *pdc; + + ACPI_FUNCTION_TRACE("acpi_processor_set_pdc"); + + arg0.buffer.length = 12; + arg0.buffer.pointer = (u8 *) arg0_buf; + arg0_buf[0] = ACPI_PDC_REVISION_ID; + arg0_buf[1] = 0; + arg0_buf[2] = 0; + + pdc = (pdc_in) ? pdc_in : &no_object; + + status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL); + + if ((ACPI_FAILURE(status)) && (pdc_in)) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PDC, using legacy perf. control...\n")); + + return_VALUE(status); +} + + /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 79d5ca3066c..8f038cd2947 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -6,6 +6,8 @@ * Copyright (C) 2004 Dominik Brodowski * Copyright (C) 2004 Anil S Keshavamurthy * - Added processor hotplug support + * Copyright (C) 2005 Venkatesh Pallipadi + * - Added support for C3 on SMP * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -142,7 +144,7 @@ acpi_processor_power_activate ( switch (old->type) { case ACPI_STATE_C3: /* Disable bus master reload */ - if (new->type != ACPI_STATE_C3) + if (new->type != ACPI_STATE_C3 && pr->flags.bm_check) acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, ACPI_MTX_DO_NOT_LOCK); break; } @@ -152,7 +154,7 @@ acpi_processor_power_activate ( switch (new->type) { case ACPI_STATE_C3: /* Enable bus master reload */ - if (old->type != ACPI_STATE_C3) + if (old->type != ACPI_STATE_C3 && pr->flags.bm_check) acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1, ACPI_MTX_DO_NOT_LOCK); break; } @@ -163,6 +165,9 @@ acpi_processor_power_activate ( } +static atomic_t c3_cpu_count; + + static void acpi_processor_idle (void) { struct acpi_processor *pr = NULL; @@ -297,8 +302,22 @@ static void acpi_processor_idle (void) break; case ACPI_STATE_C3: - /* Disable bus master arbitration */ - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK); + + if (pr->flags.bm_check) { + if (atomic_inc_return(&c3_cpu_count) == + num_online_cpus()) { + /* + * All CPUs are trying to go to C3 + * Disable bus master arbitration + */ + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, + ACPI_MTX_DO_NOT_LOCK); + } + } else { + /* SMP with no shared cache... Invalidate cache */ + ACPI_FLUSH_CPU_CACHE(); + } + /* Get start time (ticks) */ t1 = inl(acpi_fadt.xpm_tmr_blk.address); /* Invoke C3 */ @@ -307,8 +326,12 @@ static void acpi_processor_idle (void) t2 = inl(acpi_fadt.xpm_tmr_blk.address); /* Get end time (ticks) */ t2 = inl(acpi_fadt.xpm_tmr_blk.address); - /* Enable bus master arbitration */ - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK); + if (pr->flags.bm_check) { + /* Enable bus master arbitration */ + atomic_dec(&c3_cpu_count); + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK); + } + /* Re-enable interrupts */ local_irq_enable(); /* Compute time (ticks) that we were actually asleep */ @@ -552,9 +575,6 @@ static int acpi_processor_get_power_info_cst (struct acpi_processor *pr) ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_cst"); - if (errata.smp) - return_VALUE(-ENODEV); - if (nocst) return_VALUE(-ENODEV); @@ -687,13 +707,6 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx) return_VOID; } - /* We're (currently) only supporting C2 on UP */ - else if (errata.smp) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C2 not supported in SMP mode\n")); - return_VOID; - } - /* * Otherwise we've met all of our C2 requirements. * Normalize the C2 latency to expidite policy @@ -709,6 +722,8 @@ static void acpi_processor_power_verify_c3( struct acpi_processor *pr, struct acpi_processor_cx *cx) { + static int bm_check_flag; + ACPI_FUNCTION_TRACE("acpi_processor_get_power_verify_c3"); if (!cx->address) @@ -725,20 +740,6 @@ static void acpi_processor_power_verify_c3( return_VOID; } - /* bus mastering control is necessary */ - else if (!pr->flags.bm_control) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C3 support requires bus mastering control\n")); - return_VOID; - } - - /* We're (currently) only supporting C2 on UP */ - else if (errata.smp) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "C3 not supported in SMP mode\n")); - return_VOID; - } - /* * PIIX4 Erratum #18: We don't support C3 when Type-F (fast) * DMA transfers are used by any ISA device to avoid livelock. @@ -752,6 +753,39 @@ static void acpi_processor_power_verify_c3( return_VOID; } + /* All the logic here assumes flags.bm_check is same across all CPUs */ + if (!bm_check_flag) { + /* Determine whether bm_check is needed based on CPU */ + acpi_processor_power_init_bm_check(&(pr->flags), pr->id); + bm_check_flag = pr->flags.bm_check; + } else { + pr->flags.bm_check = bm_check_flag; + } + + if (pr->flags.bm_check) { + printk("Disabling BM access before entering C3\n"); + /* bus mastering control is necessary */ + if (!pr->flags.bm_control) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C3 support requires bus mastering control\n")); + return_VOID; + } + } else { + printk("Invalidating cache before entering C3\n"); + /* + * WBINVD should be set in fadt, for C3 state to be + * supported on when bm_check is not required. + */ + if (acpi_fadt.wb_invd != 1) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Cache invalidation should work properly" + " for C3 to be enabled on SMP systems\n")); + return_VOID; + } + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, + 0, ACPI_MTX_DO_NOT_LOCK); + } + /* * Otherwise we've met all of our C3 requirements. * Normalize the C3 latency to expidite policy. Enable @@ -760,7 +794,6 @@ static void acpi_processor_power_verify_c3( */ cx->valid = 1; cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency); - pr->flags.bm_check = 1; return_VOID; } @@ -848,7 +881,7 @@ int acpi_processor_cst_has_changed (struct acpi_processor *pr) if (!pr) return_VALUE(-EINVAL); - if (errata.smp || nocst) { + if ( nocst) { return_VALUE(-ENODEV); } @@ -948,7 +981,6 @@ static struct file_operations acpi_processor_power_fops = { .release = single_release, }; - int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device) { acpi_status status = 0; @@ -965,7 +997,10 @@ int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *dev first_run++; } - if (!errata.smp && (pr->id == 0) && acpi_fadt.cst_cnt && !nocst) { + if (!pr) + return_VALUE(-EINVAL); + + if (acpi_fadt.cst_cnt && !nocst) { status = acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, @@ -973,6 +1008,8 @@ int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *dev } } + acpi_processor_power_init_pdc(&(pr->power), pr->id); + acpi_processor_set_pdc(pr, pr->power.pdc); acpi_processor_get_power_info(pr); /* diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index a9a1a8fe319..1f0d6256302 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -165,37 +165,6 @@ void acpi_processor_ppc_exit(void) { acpi_processor_ppc_status &= ~PPC_REGISTERED; } -/* - * when registering a cpufreq driver with this ACPI processor driver, the - * _PCT and _PSS structures are read out and written into struct - * acpi_processor_performance. - */ -static int acpi_processor_set_pdc (struct acpi_processor *pr) -{ - acpi_status status = AE_OK; - u32 arg0_buf[3]; - union acpi_object arg0 = {ACPI_TYPE_BUFFER}; - struct acpi_object_list no_object = {1, &arg0}; - struct acpi_object_list *pdc; - - ACPI_FUNCTION_TRACE("acpi_processor_set_pdc"); - - arg0.buffer.length = 12; - arg0.buffer.pointer = (u8 *) arg0_buf; - arg0_buf[0] = ACPI_PDC_REVISION_ID; - arg0_buf[1] = 0; - arg0_buf[2] = 0; - - pdc = (pr->performance->pdc) ? pr->performance->pdc : &no_object; - - status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL); - - if ((ACPI_FAILURE(status)) && (pr->performance->pdc)) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PDC, using legacy perf. control...\n")); - - return_VALUE(status); -} - static int acpi_processor_get_performance_control ( @@ -357,7 +326,7 @@ acpi_processor_get_performance_info ( if (!pr || !pr->performance || !pr->handle) return_VALUE(-EINVAL); - acpi_processor_set_pdc(pr); + acpi_processor_set_pdc(pr, pr->performance->pdc); status = acpi_get_handle(pr->handle, "_PCT", &handle); if (ACPI_FAILURE(status)) { -- cgit v1.2.3 From cf5910bbae81b95bdf120e01fd365ad7b939b143 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: add bMaxPacketSize0 attribute to sysfs For some reason this was not there... Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 740cb4c668d..00297f11384 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -196,6 +196,7 @@ usb_descriptor_attr (bDeviceClass, "%02x\n") usb_descriptor_attr (bDeviceSubClass, "%02x\n") usb_descriptor_attr (bDeviceProtocol, "%02x\n") usb_descriptor_attr (bNumConfigurations, "%d\n") +usb_descriptor_attr (bMaxPacketSize0, "%d\n") static struct attribute *dev_attrs[] = { /* current configuration's attributes */ @@ -211,6 +212,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_bDeviceSubClass.attr, &dev_attr_bDeviceProtocol.attr, &dev_attr_bNumConfigurations.attr, + &dev_attr_bMaxPacketSize0.attr, &dev_attr_speed.attr, &dev_attr_devnum.attr, &dev_attr_version.attr, -- cgit v1.2.3 From e8116e84b56f8fa4f091b967a045f47c55095c68 Mon Sep 17 00:00:00 2001 From: Phil Dibowitz Date: Wed, 22 Jun 2005 22:47:13 -0700 Subject: [PATCH] USB Storage: Remove unneeded SC/P This patch removes an unneeded subclass and protocol from the 07af/0005/100 entry in unsual_devs.h as reported by Alfred Ganz . Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 9fcc7bd1fbe..bd0ab3039bd 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -697,7 +697,7 @@ UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133, UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100, "Microtech", "USB-SCSI-HD50", - US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, + US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG ), #ifdef CONFIG_USB_STORAGE_DPCM -- cgit v1.2.3 From 9c8d61783e5bb5e29744b6481a1c67c6e4e8e135 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Mon, 20 Jun 2005 14:29:58 -0700 Subject: [PATCH] USB: khubd: use kthread API Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 32ff3218185..c3e46d24a37 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -47,8 +48,7 @@ static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ /* Wakes up khubd */ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); -static pid_t khubd_pid = 0; /* PID of khubd */ -static DECLARE_COMPLETION(khubd_exited); +static struct task_struct *khubd_task; /* cycle leds on hubs that aren't blinking for attention */ static int blinkenlights = 0; @@ -2807,23 +2807,16 @@ loop: static int hub_thread(void *__unused) { - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources - */ - - daemonize("khubd"); - allow_signal(SIGKILL); - - /* Send me a signal to get me die (for debugging) */ do { hub_events(); - wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); + wait_event_interruptible(khubd_wait, + !list_empty(&hub_event_list) || + kthread_should_stop()); try_to_freeze(); - } while (!signal_pending(current)); + } while (!kthread_should_stop() || !list_empty(&hub_event_list)); - pr_debug ("%s: khubd exiting\n", usbcore_name); - complete_and_exit(&khubd_exited, 0); + pr_debug("%s: khubd exiting\n", usbcore_name); + return 0; } static struct usb_device_id hub_id_table [] = { @@ -2849,20 +2842,15 @@ static struct usb_driver hub_driver = { int usb_hub_init(void) { - pid_t pid; - if (usb_register(&hub_driver) < 0) { printk(KERN_ERR "%s: can't register hub driver\n", usbcore_name); return -1; } - pid = kernel_thread(hub_thread, NULL, CLONE_KERNEL); - if (pid >= 0) { - khubd_pid = pid; - + khubd_task = kthread_run(hub_thread, NULL, "khubd"); + if (!IS_ERR(khubd_task)) return 0; - } /* Fall through if kernel_thread failed */ usb_deregister(&hub_driver); @@ -2873,12 +2861,7 @@ int usb_hub_init(void) void usb_hub_cleanup(void) { - int ret; - - /* Kill the thread */ - ret = kill_proc(khubd_pid, SIGKILL, 1); - - wait_for_completion(&khubd_exited); + kthread_stop(khubd_task); /* * Hub resources are freed for us by usb_deregister. It calls @@ -2890,7 +2873,6 @@ void usb_hub_cleanup(void) usb_deregister(&hub_driver); } /* usb_hub_cleanup() */ - static int config_descriptors_changed(struct usb_device *udev) { unsigned index; -- cgit v1.2.3 From 8f977e4201fcc0bd512eb01e775894e0a9c34a39 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Mon, 20 Jun 2005 16:45:42 +0100 Subject: [PATCH] USB ftdi_sio: reduce device id table clutter ftdi_sio: Use a single usb_device_id table and detect the type of chip programatically. The table also flags devices requiring special initialization. The patch makes the driver about 10K smaller and makes it easier to add new device IDs. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 707 +++++++++--------------------------------- 1 file changed, 144 insertions(+), 563 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d882fa3ad19..f843f735886 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -264,16 +264,26 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.4.2" +#define DRIVER_VERSION "v1.4.3" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober " #define DRIVER_DESC "USB FTDI Serial Converters Driver" static int debug; -static struct usb_device_id id_table_sio [] = { - { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, - { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, - { } /* Terminating entry */ +/* struct ftdi_sio_quirk is used by devices requiring special attention. */ +struct ftdi_sio_quirk { + void (*setup)(struct usb_serial *); /* Special settings during startup. */ +}; + +static void ftdi_USB_UIRT_setup (struct usb_serial *serial); +static void ftdi_HE_TIRA1_setup (struct usb_serial *serial); + +static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { + .setup = ftdi_USB_UIRT_setup, +}; + +static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { + .setup = ftdi_HE_TIRA1_setup, }; /* @@ -288,237 +298,11 @@ static struct usb_device_id id_table_sio [] = { * the bcdDevice value is used to differentiate FT232BM and FT245BM from * the earlier FT8U232AM and FT8U232BM. For now, include all known VID/PID * combinations in both tables. - * FIXME: perhaps bcdDevice can also identify 12MHz devices, but I don't know - * if those ever went into mass production. [Ian Abbott] + * FIXME: perhaps bcdDevice can also identify 12MHz FT8U232AM devices, + * but I don't know if those ever went into mass production. [Ian Abbott] */ -static struct usb_device_id id_table_8U232AM [] = { - { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) }, - { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, - { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, - { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0, 0x3ff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0, 0x3ff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0, 0x3ff) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_FT232BM [] = { - { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_PIEGROUP_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, - { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0x400, 0xffff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_USB_UIRT [] = { - { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_HE_TIRA1 [] = { - { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) }, - { } /* Terminating entry */ -}; - - -static struct usb_device_id id_table_FT2232C[] = { - { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, - { } /* Terminating entry */ -}; - static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, @@ -540,14 +324,14 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, @@ -597,35 +381,37 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) }, { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) }, { USB_DEVICE(OCT_VID, OCT_US101_PID) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) }, - { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID), + .driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID), + .driver_info = (kernel_ulong_t)&ftdi_USB_UIRT_quirk }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) }, { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) }, - { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) }, - { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, + { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, @@ -642,7 +428,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, - { USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) }, + { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, { } /* Terminating entry */ }; @@ -705,12 +491,8 @@ struct ftdi_private { ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP ) /* function prototypes for a FTDI serial converter */ -static int ftdi_SIO_startup (struct usb_serial *serial); -static int ftdi_8U232AM_startup (struct usb_serial *serial); -static int ftdi_FT232BM_startup (struct usb_serial *serial); -static int ftdi_FT2232C_startup (struct usb_serial *serial); -static int ftdi_USB_UIRT_startup (struct usb_serial *serial); -static int ftdi_HE_TIRA1_startup (struct usb_serial *serial); +static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id); +static int ftdi_sio_attach (struct usb_serial *serial); static void ftdi_shutdown (struct usb_serial *serial); static int ftdi_open (struct usb_serial_port *port, struct file *filp); static void ftdi_close (struct usb_serial_port *port, struct file *filp); @@ -733,66 +515,16 @@ static unsigned short int ftdi_232am_baud_to_divisor (int baud); static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base); static __u32 ftdi_232bm_baud_to_divisor (int baud); -static struct usb_serial_device_type ftdi_SIO_device = { - .owner = THIS_MODULE, - .name = "FTDI SIO", - .id_table = id_table_sio, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_SIO_startup, - .shutdown = ftdi_shutdown, -}; - -static struct usb_serial_device_type ftdi_8U232AM_device = { - .owner = THIS_MODULE, - .name = "FTDI 8U232AM Compatible", - .id_table = id_table_8U232AM, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_8U232AM_startup, - .shutdown = ftdi_shutdown, -}; - -static struct usb_serial_device_type ftdi_FT232BM_device = { +static struct usb_serial_device_type ftdi_sio_device = { .owner = THIS_MODULE, - .name = "FTDI FT232BM Compatible", - .id_table = id_table_FT232BM, + .name = "FTDI USB Serial Device", + .short_name = "ftdi_sio", + .id_table = id_table_combined, .num_interrupt_in = 0, .num_bulk_in = 1, .num_bulk_out = 1, .num_ports = 1, + .probe = ftdi_sio_probe, .open = ftdi_open, .close = ftdi_close, .throttle = ftdi_throttle, @@ -807,91 +539,10 @@ static struct usb_serial_device_type ftdi_FT232BM_device = { .ioctl = ftdi_ioctl, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, - .attach = ftdi_FT232BM_startup, + .attach = ftdi_sio_attach, .shutdown = ftdi_shutdown, }; -static struct usb_serial_device_type ftdi_FT2232C_device = { - .owner = THIS_MODULE, - .name = "FTDI FT2232C Compatible", - .id_table = id_table_FT2232C, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_FT2232C_startup, - .shutdown = ftdi_shutdown, -}; - -static struct usb_serial_device_type ftdi_USB_UIRT_device = { - .owner = THIS_MODULE, - .name = "USB-UIRT Infrared Tranceiver", - .id_table = id_table_USB_UIRT, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_USB_UIRT_startup, - .shutdown = ftdi_shutdown, -}; - -/* The TIRA1 is based on a FT232BM which requires a fixed baud rate of 100000 - * and which requires RTS-CTS to be enabled. */ -static struct usb_serial_device_type ftdi_HE_TIRA1_device = { - .owner = THIS_MODULE, - .name = "Home-Electronics TIRA-1 IR Transceiver", - .id_table = id_table_HE_TIRA1, - .num_interrupt_in = 0, - .num_bulk_in = 1, - .num_bulk_out = 1, - .num_ports = 1, - .open = ftdi_open, - .close = ftdi_close, - .throttle = ftdi_throttle, - .unthrottle = ftdi_unthrottle, - .write = ftdi_write, - .write_room = ftdi_write_room, - .chars_in_buffer = ftdi_chars_in_buffer, - .read_bulk_callback = ftdi_read_bulk_callback, - .write_bulk_callback = ftdi_write_bulk_callback, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .attach = ftdi_HE_TIRA1_startup, - .shutdown = ftdi_shutdown, -}; - - #define WDR_TIMEOUT 5000 /* default urb timeout */ @@ -1212,6 +863,59 @@ check_and_exit: } /* set_serial_info */ +/* Determine type of FTDI chip based on USB config and descriptor. */ +static void ftdi_determine_type(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + struct usb_device *udev = serial->dev; + unsigned version; + unsigned interfaces; + + /* Assume it is not the original SIO device for now. */ + priv->baud_base = 48000000 / 16; + priv->write_offset = 0; + + version = le16_to_cpu(udev->descriptor.bcdDevice); + interfaces = udev->actconfig->desc.bNumInterfaces; + dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __FUNCTION__, + version, interfaces); + if (interfaces > 1) { + int inter; + + /* Multiple interfaces. Assume FT2232C. */ + priv->chip_type = FT2232C; + /* Determine interface code. */ + inter = serial->interface->altsetting->desc.bInterfaceNumber; + if (inter == 0) { + priv->interface = PIT_SIOA; + } else { + priv->interface = PIT_SIOB; + } + /* BM-type devices have a bug where bcdDevice gets set + * to 0x200 when iSerialNumber is 0. */ + if (version < 0x500) { + dbg("%s: something fishy - bcdDevice too low for multi-interface device", + __FUNCTION__); + } + } else if (version < 0x200) { + /* Old device. Assume its the original SIO. */ + priv->chip_type = SIO; + priv->baud_base = 12000000 / 16; + priv->write_offset = 1; + } else if (version < 0x400) { + /* Assume its an FT8U232AM (or FT8U245AM) */ + /* (It might be a BM because of the iSerialNumber bug, + * but it will still work as an AM device.) */ + priv->chip_type = FT8U232AM; + } else { + /* Assume its an FT232BM (or FT245BM) */ + priv->chip_type = FT232BM; + } + info("Detected %s", ftdi_chip_name[priv->chip_type]); +} + + /* * *************************************************************************** * Sysfs Attribute @@ -1355,12 +1059,20 @@ static void remove_sysfs_attrs(struct usb_serial *serial) * *************************************************************************** */ -/* Common startup subroutine */ -/* Called from ftdi_SIO_startup, etc. */ -static int ftdi_common_startup (struct usb_serial *serial) +/* Probe function to check for special devices */ +static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id) +{ + usb_set_serial_data(serial, (void *)id->driver_info); + + return (0); +} + +/* attach subroutine */ +static int ftdi_sio_attach (struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; struct ftdi_private *priv; + struct ftdi_sio_quirk *quirk; dbg("%s",__FUNCTION__); @@ -1400,150 +1112,49 @@ static int ftdi_common_startup (struct usb_serial *serial) port->bulk_out_buffer = NULL; usb_set_serial_port_data(serial->port[0], priv); - - return (0); -} - - -/* Startup for the SIO chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_SIO_startup (struct usb_serial *serial) -{ - struct ftdi_private *priv; - int err; - dbg("%s",__FUNCTION__); - - err = ftdi_common_startup(serial); - if (err){ - return (err); - } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = SIO; - priv->baud_base = 12000000 / 16; - priv->write_offset = 1; - - return (0); -} - -/* Startup for the 8U232AM chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_8U232AM_startup (struct usb_serial *serial) -{ /* ftdi_8U232AM_startup */ - struct ftdi_private *priv; - int err; - - dbg("%s",__FUNCTION__); - err = ftdi_common_startup(serial); - if (err){ - return (err); - } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = FT8U232AM; - priv->baud_base = 48000000 / 2; /* Would be / 16, but FTDI supports 0.125, 0.25 and 0.5 divisor fractions! */ - + ftdi_determine_type (serial->port[0]); create_sysfs_attrs(serial); - - return (0); -} /* ftdi_8U232AM_startup */ -/* Startup for the FT232BM chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_FT232BM_startup (struct usb_serial *serial) -{ /* ftdi_FT232BM_startup */ - struct ftdi_private *priv; - int err; - - dbg("%s",__FUNCTION__); - err = ftdi_common_startup(serial); - if (err){ - return (err); + /* Check for device requiring special set up. */ + quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial); + if (quirk && quirk->setup) { + quirk->setup(serial); } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = FT232BM; - priv->baud_base = 48000000 / 2; /* Would be / 16, but FT232BM supports multiple of 0.125 divisor fractions! */ - create_sysfs_attrs(serial); - return (0); -} /* ftdi_FT232BM_startup */ +} /* ftdi_sio_attach */ -/* Startup for the FT2232C chip */ -/* Called from usbserial:serial_probe */ -static int ftdi_FT2232C_startup (struct usb_serial *serial) -{ /* ftdi_FT2232C_startup */ - struct ftdi_private *priv; - int err; - int inter; - - dbg("%s",__FUNCTION__); - err = ftdi_common_startup(serial); - if (err){ - return (err); - } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chip_type = FT2232C; - inter = serial->interface->altsetting->desc.bInterfaceNumber; - - if (inter) { - priv->interface = PIT_SIOB; - } - else { - priv->interface = PIT_SIOA; - } - priv->baud_base = 48000000 / 2; /* Would be / 16, but FT2232C supports multiple of 0.125 divisor fractions! */ - - create_sysfs_attrs(serial); - - return (0); -} /* ftdi_FT2232C_startup */ -/* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */ +/* Setup for the USB-UIRT device, which requires hardwired + * baudrate (38400 gets mapped to 312500) */ /* Called from usbserial:serial_probe */ -static int ftdi_USB_UIRT_startup (struct usb_serial *serial) -{ /* ftdi_USB_UIRT_startup */ +static void ftdi_USB_UIRT_setup (struct usb_serial *serial) +{ struct ftdi_private *priv; - int err; dbg("%s",__FUNCTION__); - err = ftdi_8U232AM_startup(serial); - if (err){ - return (err); - } priv = usb_get_serial_port_data(serial->port[0]); priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 77; priv->force_baud = B38400; - - return (0); -} /* ftdi_USB_UIRT_startup */ +} /* ftdi_USB_UIRT_setup */ -/* Startup for the HE-TIRA1 device, which requires hardwired - * baudrate (38400 gets mapped to 100000) */ -static int ftdi_HE_TIRA1_startup (struct usb_serial *serial) -{ /* ftdi_HE_TIRA1_startup */ +/* Setup for the HE-TIRA1 device, which requires hardwired + * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */ +static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) +{ struct ftdi_private *priv; - int err; dbg("%s",__FUNCTION__); - err = ftdi_FT232BM_startup(serial); - if (err){ - return (err); - } priv = usb_get_serial_port_data(serial->port[0]); priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 240; priv->force_baud = B38400; priv->force_rtscts = 1; - - return (0); -} /* ftdi_HE_TIRA1_startup */ +} /* ftdi_HE_TIRA1_setup */ /* ftdi_shutdown is called from usbserial:usb_serial_disconnect @@ -2516,24 +2127,9 @@ static int __init ftdi_init (void) int retval; dbg("%s", __FUNCTION__); - retval = usb_serial_register(&ftdi_SIO_device); - if (retval) - goto failed_SIO_register; - retval = usb_serial_register(&ftdi_8U232AM_device); - if (retval) - goto failed_8U232AM_register; - retval = usb_serial_register(&ftdi_FT232BM_device); - if (retval) - goto failed_FT232BM_register; - retval = usb_serial_register(&ftdi_FT2232C_device); - if (retval) - goto failed_FT2232C_register; - retval = usb_serial_register(&ftdi_USB_UIRT_device); - if (retval) - goto failed_USB_UIRT_register; - retval = usb_serial_register(&ftdi_HE_TIRA1_device); + retval = usb_serial_register(&ftdi_sio_device); if (retval) - goto failed_HE_TIRA1_register; + goto failed_sio_register; retval = usb_register(&ftdi_driver); if (retval) goto failed_usb_register; @@ -2541,18 +2137,8 @@ static int __init ftdi_init (void) info(DRIVER_VERSION ":" DRIVER_DESC); return 0; failed_usb_register: - usb_serial_deregister(&ftdi_HE_TIRA1_device); -failed_HE_TIRA1_register: - usb_serial_deregister(&ftdi_USB_UIRT_device); -failed_USB_UIRT_register: - usb_serial_deregister(&ftdi_FT2232C_device); -failed_FT2232C_register: - usb_serial_deregister(&ftdi_FT232BM_device); -failed_FT232BM_register: - usb_serial_deregister(&ftdi_8U232AM_device); -failed_8U232AM_register: - usb_serial_deregister(&ftdi_SIO_device); -failed_SIO_register: + usb_serial_deregister(&ftdi_sio_device); +failed_sio_register: return retval; } @@ -2563,12 +2149,7 @@ static void __exit ftdi_exit (void) dbg("%s", __FUNCTION__); usb_deregister (&ftdi_driver); - usb_serial_deregister (&ftdi_HE_TIRA1_device); - usb_serial_deregister (&ftdi_USB_UIRT_device); - usb_serial_deregister (&ftdi_FT2232C_device); - usb_serial_deregister (&ftdi_FT232BM_device); - usb_serial_deregister (&ftdi_8U232AM_device); - usb_serial_deregister (&ftdi_SIO_device); + usb_serial_deregister (&ftdi_sio_device); } -- cgit v1.2.3 From 7e33ae67815372a93e8e77624fd47e39a986415d Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Mon, 20 Jun 2005 17:10:19 +0100 Subject: [PATCH] USB ftdi_sio: remove redundant TIOCMBIS and TIOCMBIC code ftdi_sio: Remove redundant handling of TIOCMBIS and TIOCMBIC ioctls as they are handled in the tty layer and never reach this driver. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 47 ------------------------------------------- 1 file changed, 47 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f843f735886..aad2f4d0e09 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1985,53 +1985,6 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne /* Based on code from acm.c and others */ switch (cmd) { - case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */ - dbg("%s TIOCMBIS", __FUNCTION__); - if (get_user(mask, (unsigned long __user *) arg)) - return -EFAULT; - if (mask & TIOCM_DTR){ - if ((ret = set_dtr(port, HIGH)) < 0) { - err("Urb to set DTR failed"); - return(ret); - } - } - if (mask & TIOCM_RTS) { - if ((ret = set_rts(port, HIGH)) < 0){ - err("Urb to set RTS failed"); - return(ret); - } - } - return(0); - break; - - case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */ - dbg("%s TIOCMBIC", __FUNCTION__); - if (get_user(mask, (unsigned long __user *) arg)) - return -EFAULT; - if (mask & TIOCM_DTR){ - if ((ret = set_dtr(port, LOW)) < 0){ - err("Urb to unset DTR failed"); - return(ret); - } - } - if (mask & TIOCM_RTS) { - if ((ret = set_rts(port, LOW)) < 0){ - err("Urb to unset RTS failed"); - return(ret); - } - } - return(0); - break; - - /* - * I had originally implemented TCSET{A,S}{,F,W} and - * TCGET{A,S} here separately, however when testing I - * found that the higher layers actually do the termios - * conversions themselves and pass the call onto - * ftdi_sio_set_termios. - * - */ - case TIOCGSERIAL: /* gets serial port data */ return get_serial_info(port, (struct serial_struct __user *) arg); -- cgit v1.2.3 From 16966f2ab7db7366855d1267071a3138ae127ff6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: fix ftdi_sio compiler warnings Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index aad2f4d0e09..0b03ddab53d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1978,8 +1978,6 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne { struct ftdi_private *priv = usb_get_serial_port_data(port); - int ret, mask; - dbg("%s cmd 0x%04x", __FUNCTION__, cmd); /* Based on code from acm.c and others */ -- cgit v1.2.3 From 322a95bc8eba889d2f9d7222936d682c9aad8294 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 23 Jun 2005 09:20:50 +0200 Subject: [PATCH] USB ATM: line speed measured in Kb not Kib Spotted by David Woodhouse. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 2 +- drivers/usb/atm/speedtch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index cbd4a7d25d0..8e184e2641c 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -427,7 +427,7 @@ static void cxacru_poll_status(struct cxacru_data *instance) atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424; atm_dev->signal = ATM_PHY_SIG_FOUND; - dev_info(dev, "ADSL line: up (%d Kib/s down | %d Kib/s up)\n", + dev_info(dev, "ADSL line: up (%d kb/s down | %d kb/s up)\n", buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]); break; diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 6a6eaa2a3b1..992db1c1683 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -480,7 +480,7 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) atm_dev->signal = ATM_PHY_SIG_FOUND; atm_info(usbatm, - "ADSL line is up (%d Kib/s down | %d Kib/s up)\n", + "ADSL line is up (%d kb/s down | %d kb/s up)\n", down_speed, up_speed); } break; -- cgit v1.2.3 From cd5c08fb7b0d960b7cd48bc977feee7b3bd8b046 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 23 Jun 2005 09:23:10 +0200 Subject: [PATCH] USB ATM: robustify poll throttling No functional change, but less likely to break in the future. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 992db1c1683..03a0e99a426 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -430,13 +430,11 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) ret = speedtch_read_status(instance); if (ret < 0) { atm_warn(usbatm, "error %d fetching device status\n", ret); - if (instance->poll_delay < MAX_POLL_DELAY) - instance->poll_delay *= 2; + instance->poll_delay = min(2 * instance->poll_delay, MAX_POLL_DELAY); return; } - if (instance->poll_delay > MIN_POLL_DELAY) - instance->poll_delay /= 2; + instance->poll_delay = max(instance->poll_delay / 2, MIN_POLL_DELAY); atm_dbg(usbatm, "%s: line state %02x\n", __func__, buf[OFFSET_7]); -- cgit v1.2.3 From 1a7aad15ff93be104c8e0851a43b94f8ccd92225 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Thu, 23 Jun 2005 09:37:56 +0200 Subject: [PATCH] USB ATM: fix line resync logic We map states 0x00 and 0x10 to the ATM_PHY_SIG_LOST flag. The current logic fails to resync the line if we get state 0x10 followed by 0x00, since we only resync the line when the state is 0x00 and the flag changed. Doubly fixed by (1) always resyncing the line when the state is 0x00 even if the state didn't change, and (2) keeping track of the last state, not just the flag. We do (2) as well as (1) in order to get better log messages. This is a tweaked version of the original patch by Aurelio Arroyo. Signed-off-by: Duncan Sands Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 55 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 03a0e99a426..d0cbbb7f038 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -100,6 +100,8 @@ struct speedtch_instance_data { struct work_struct status_checker; + unsigned char last_status; + int poll_delay; /* milliseconds */ struct timer_list resubmit_timer; @@ -423,7 +425,8 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) struct usbatm_data *usbatm = instance->usbatm; struct atm_dev *atm_dev = usbatm->atm_dev; unsigned char *buf = instance->scratch_buffer; - int ret; + int down_speed, up_speed, ret; + unsigned char status; atm_dbg(usbatm, "%s entered\n", __func__); @@ -436,37 +439,34 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) instance->poll_delay = max(instance->poll_delay / 2, MIN_POLL_DELAY); - atm_dbg(usbatm, "%s: line state %02x\n", __func__, buf[OFFSET_7]); + status = buf[OFFSET_7]; - switch (buf[OFFSET_7]) { - case 0: - if (atm_dev->signal != ATM_PHY_SIG_LOST) { + atm_dbg(usbatm, "%s: line state %02x\n", __func__, status); + + if ((status != instance->last_status) || !status) { + switch (status) { + case 0: atm_dev->signal = ATM_PHY_SIG_LOST; - atm_info(usbatm, "ADSL line is down\n"); - /* It'll never resync again unless we ask it to... */ + if (instance->last_status) + atm_info(usbatm, "ADSL line is down\n"); + /* It may never resync again unless we ask it to... */ ret = speedtch_start_synchro(instance); - } - break; + break; - case 0x08: - if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { + case 0x08: atm_dev->signal = ATM_PHY_SIG_UNKNOWN; atm_info(usbatm, "ADSL line is blocked?\n"); - } - break; + break; - case 0x10: - if (atm_dev->signal != ATM_PHY_SIG_LOST) { + case 0x10: atm_dev->signal = ATM_PHY_SIG_LOST; atm_info(usbatm, "ADSL line is synchronising\n"); - } - break; + break; - case 0x20: - if (atm_dev->signal != ATM_PHY_SIG_FOUND) { - int down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8) + case 0x20: + down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8) | (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24); - int up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8) + up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8) | (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24); if (!(down_speed & 0x0000ffff) && !(up_speed & 0x0000ffff)) { @@ -480,15 +480,15 @@ static void speedtch_check_status(struct speedtch_instance_data *instance) atm_info(usbatm, "ADSL line is up (%d kb/s down | %d kb/s up)\n", down_speed, up_speed); - } - break; + break; - default: - if (atm_dev->signal != ATM_PHY_SIG_UNKNOWN) { + default: atm_dev->signal = ATM_PHY_SIG_UNKNOWN; - atm_info(usbatm, "Unknown line state %02x\n", buf[OFFSET_7]); + atm_info(usbatm, "Unknown line state %02x\n", status); + break; } - break; + + instance->last_status = status; } } @@ -728,6 +728,7 @@ static int speedtch_bind(struct usbatm_data *usbatm, instance->status_checker.timer.function = speedtch_status_poll; instance->status_checker.timer.data = (unsigned long)instance; + instance->last_status = 0xff; instance->poll_delay = MIN_POLL_DELAY; init_timer(&instance->resubmit_timer); -- cgit v1.2.3 From ead99eb00190a274e3b3666ecd431be12c2b7888 Mon Sep 17 00:00:00 2001 From: Thomas Winischhofer Date: Fri, 24 Jun 2005 18:44:20 +0200 Subject: [PATCH] USB: SiS USB Makefile fixes although 2.6.12 now contains the sisusb driver, it failes to build this driver due to a missing patch of the Makefile. From: Thomas Winischhofer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index d79cd218a55..284f95723ee 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_USB_RIO500) += misc/ obj-$(CONFIG_USB_TEST) += misc/ obj-$(CONFIG_USB_USS720) += misc/ obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ +obj-$(CONFIG_USB_SISUSBVGA) += misc/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ -- cgit v1.2.3 From ae0d6cceb20eec57e7196c22999c62c465ffd5bf Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Sat, 25 Jun 2005 14:32:59 -0700 Subject: [PATCH] USB: Patch to make usbmon to print control setup packets Make usbmon to print Setup packets of Control transfers. This is useful when debugging enumeration issues. This is a change to the trace format which is not fully compatible. A parser has to look at the data length word now. If that word is a character like 's', read setup packet before proceeding with data. I decided not to bump the API tag for this because not many such parsers exist at this point. Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_text.c | 48 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 755a4570477..26266b30028 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -18,12 +18,17 @@ */ #define DATA_MAX 32 +/* + * Defined by USB 2.0 clause 9.3, table 9.2. + */ +#define SETUP_MAX 8 + /* * This limit exists to prevent OOMs when the user process stops reading. */ #define EVENT_MAX 25 -#define PRINTF_DFL 120 +#define PRINTF_DFL 130 struct mon_event_text { struct list_head e_link; @@ -33,7 +38,9 @@ struct mon_event_text { unsigned int tstamp; int length; /* Depends on type: xfer length or act length */ int status; + char setup_flag; char data_flag; + unsigned char setup[SETUP_MAX]; unsigned char data[DATA_MAX]; }; @@ -64,6 +71,22 @@ static void mon_text_dtor(void *, kmem_cache_t *, unsigned long); * This is called with the whole mon_bus locked, so no additional lock. */ +static inline char mon_text_get_setup(struct mon_event_text *ep, + struct urb *urb, char ev_type) +{ + + if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + return '-'; + + if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP) + return 'D'; + if (urb->setup_packet == NULL) + return 'Z'; /* '0' would be not as pretty. */ + + memcpy(ep->setup, urb->setup_packet, SETUP_MAX); + return 0; +} + static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, int len, char ev_type) { @@ -90,7 +113,6 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, /* * Bulk is easy to shortcut reliably. - * XXX Control needs setup packet taken. * XXX Other pipe types need consideration. Currently, we overdo it * and collect garbage for them: better more than less. */ @@ -144,6 +166,7 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, /* Collecting status makes debugging sense for submits, too */ ep->status = urb->status; + ep->setup_flag = mon_text_get_setup(ep, urb, ev_type); ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type); rp->nevents++; @@ -299,10 +322,25 @@ static ssize_t mon_text_read(struct file *file, char __user *buf, default: /* PIPE_BULK */ utype = 'B'; } cnt += snprintf(pbuf + cnt, limit - cnt, - "%lx %u %c %c%c:%03u:%02u %d %d", + "%lx %u %c %c%c:%03u:%02u", ep->id, ep->tstamp, ep->type, - utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe), - ep->status, ep->length); + utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe)); + + if (ep->setup_flag == 0) { /* Setup packet is present and captured */ + cnt += snprintf(pbuf + cnt, limit - cnt, + " s %02x %02x %04x %04x %04x", + ep->setup[0], + ep->setup[1], + (ep->setup[3] << 8) | ep->setup[2], + (ep->setup[5] << 8) | ep->setup[4], + (ep->setup[7] << 8) | ep->setup[6]); + } else if (ep->setup_flag != '-') { /* Unable to capture setup packet */ + cnt += snprintf(pbuf + cnt, limit - cnt, + " %c __ __ ____ ____ ____", ep->setup_flag); + } else { /* No setup for this kind of URB */ + cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->status); + } + cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->length); if ((data_len = ep->length) > 0) { if (ep->data_flag == 0) { -- cgit v1.2.3 From 17f8bb7312fa9b00f80c3c0f8d5a5d698eb97bbd Mon Sep 17 00:00:00 2001 From: Olav Kongas Date: Thu, 23 Jun 2005 20:12:24 +0300 Subject: [PATCH] USB: isp116x-hcd cleanup Sorry that it took so long. Here comes a cleanup patch that addresses the remarks by Alexey Dobriyan about gregkh-usb-usb-isp116x-hcd-add.patch EXCEPT the remark about the typecasting of mem_flags argument for kcalloc; this will be addressed in a later patch. OlavCleanup of isp116x-hcd. Signed off by: Olav Kongas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp116x-hcd.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index ff0a168e8ee..3f2cea21efc 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -17,7 +17,7 @@ * The driver basically works. A number of people have used it with a range * of devices. * - *The driver passes all usbtests 1-14. + * The driver passes all usbtests 1-14. * * Suspending/resuming of root hub via sysfs works. Remote wakeup works too. * And suspending/resuming of platform device works too. Suspend/resume @@ -229,7 +229,7 @@ static void preproc_atl_queue(struct isp116x *isp116x) struct isp116x_ep *ep; struct urb *urb; struct ptd *ptd; - u16 toggle, dir, len; + u16 toggle = 0, dir = PTD_DIR_SETUP, len; for (ep = isp116x->atl_active; ep; ep = ep->active) { BUG_ON(list_empty(&ep->hep->urb_list)); @@ -251,8 +251,6 @@ static void preproc_atl_queue(struct isp116x *isp116x) dir = PTD_DIR_OUT; break; case USB_PID_SETUP: - toggle = 0; - dir = PTD_DIR_SETUP; len = sizeof(struct usb_ctrlrequest); ep->data = urb->setup_packet; break; @@ -264,11 +262,9 @@ static void preproc_atl_queue(struct isp116x *isp116x) ? PTD_DIR_OUT : PTD_DIR_IN; break; default: - /* To please gcc */ - toggle = dir = 0; ERR("%s %d: ep->nextpid %d\n", __func__, __LINE__, ep->nextpid); - BUG_ON(1); + BUG(); } ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK | PTD_TOGGLE(toggle); @@ -1054,7 +1050,7 @@ static int isp116x_hub_control(struct usb_hcd *hcd, break; case GetHubStatus: DBG("GetHubStatus\n"); - *(__le32 *) buf = cpu_to_le32(0); + *(__le32 *) buf = 0; break; case GetPortStatus: DBG("GetPortStatus\n"); @@ -1810,9 +1806,9 @@ static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase) ret = usb_suspend_device(hcd->self.root_hub, state); if (!ret) { dev->power.power_state = state; - INFO("%s suspended\n", (char *)hcd_name); + INFO("%s suspended\n", hcd_name); } else - ERR("%s suspend failed\n", (char *)hcd_name); + ERR("%s suspend failed\n", hcd_name); return ret; } -- cgit v1.2.3 From 5db539e49fc7471e23bf3c94ca304f008cb7b7f3 Mon Sep 17 00:00:00 2001 From: Olav Kongas Date: Thu, 23 Jun 2005 20:25:36 +0300 Subject: [PATCH] USB: Fix kmalloc's flags type in USB Greg, This patch fixes the kmalloc() flags argument type in USB subsystem; hopefully all of its occurences. The patch was made against patch-2.6.12-git2 from Jun 20. Cleanup of flags for kmalloc() in USB subsystem. Signed-off-by: Olav Kongas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/buffer.c | 2 +- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/hcd.h | 8 ++++---- drivers/usb/core/message.c | 2 +- drivers/usb/core/urb.c | 4 ++-- drivers/usb/core/usb.c | 2 +- drivers/usb/gadget/dummy_hcd.c | 9 +++++---- drivers/usb/gadget/ether.c | 18 +++++++++--------- drivers/usb/gadget/goku_udc.c | 6 +++--- drivers/usb/gadget/lh7a40x_udc.c | 6 +++--- drivers/usb/gadget/net2280.c | 6 +++--- drivers/usb/gadget/omap_udc.c | 6 +++--- drivers/usb/gadget/pxa2xx_udc.c | 6 +++--- drivers/usb/gadget/zero.c | 8 ++++---- drivers/usb/host/ehci-hcd.c | 2 +- drivers/usb/host/ehci-q.c | 2 +- drivers/usb/host/ehci-sched.c | 19 +++++++++++-------- drivers/usb/host/hc_crisv10.c | 10 ++++++---- drivers/usb/host/isp116x-hcd.c | 4 ++-- drivers/usb/host/ohci-hcd.c | 2 +- drivers/usb/host/ohci-mem.c | 4 ++-- drivers/usb/host/sl811-hcd.c | 2 +- drivers/usb/host/uhci-q.c | 2 +- drivers/usb/net/kaweth.c | 4 ++-- 24 files changed, 71 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index b7827df21f4..fc15b4acc8a 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -106,7 +106,7 @@ void hcd_buffer_destroy (struct usb_hcd *hcd) void *hcd_buffer_alloc ( struct usb_bus *bus, size_t size, - int mem_flags, + unsigned mem_flags, dma_addr_t *dma ) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 83e732a0d64..8616356f55e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1112,7 +1112,7 @@ static void urb_unlink (struct urb *urb) * expects usb_submit_urb() to have sanity checked and conditioned all * inputs in the urb */ -static int hcd_submit_urb (struct urb *urb, int mem_flags) +static int hcd_submit_urb (struct urb *urb, unsigned mem_flags) { int status; struct usb_hcd *hcd = urb->dev->bus->hcpriv; diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 8dc13cde2f7..67db4a999b9 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -142,12 +142,12 @@ struct hcd_timeout { /* timeouts we allocate */ struct usb_operations { int (*get_frame_number) (struct usb_device *usb_dev); - int (*submit_urb) (struct urb *urb, int mem_flags); + int (*submit_urb) (struct urb *urb, unsigned mem_flags); int (*unlink_urb) (struct urb *urb, int status); /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */ void *(*buffer_alloc)(struct usb_bus *bus, size_t size, - int mem_flags, + unsigned mem_flags, dma_addr_t *dma); void (*buffer_free)(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); @@ -200,7 +200,7 @@ struct hc_driver { int (*urb_enqueue) (struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags); + unsigned mem_flags); int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb); /* hw synch, freeing endpoint resources that urb_dequeue can't */ @@ -247,7 +247,7 @@ int hcd_buffer_create (struct usb_hcd *hcd); void hcd_buffer_destroy (struct usb_hcd *hcd); void *hcd_buffer_alloc (struct usb_bus *bus, size_t size, - int mem_flags, dma_addr_t *dma); + unsigned mem_flags, dma_addr_t *dma); void hcd_buffer_free (struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index f50aaf25c98..a428ef479bd 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -320,7 +320,7 @@ int usb_sg_init ( struct scatterlist *sg, int nents, size_t length, - int mem_flags + unsigned mem_flags ) { int i; diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 0faf18d511d..c0feee25ff0 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -60,7 +60,7 @@ void usb_init_urb(struct urb *urb) * * The driver must call usb_free_urb() when it is finished with the urb. */ -struct urb *usb_alloc_urb(int iso_packets, int mem_flags) +struct urb *usb_alloc_urb(int iso_packets, unsigned mem_flags) { struct urb *urb; @@ -224,7 +224,7 @@ struct urb * usb_get_urb(struct urb *urb) * GFP_NOIO, unless b) or c) apply * */ -int usb_submit_urb(struct urb *urb, int mem_flags) +int usb_submit_urb(struct urb *urb, unsigned mem_flags) { int pipe, temp, max; struct usb_device *dev; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index a3c42203213..7713a605fce 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1129,7 +1129,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, void *usb_buffer_alloc ( struct usb_device *dev, size_t size, - int mem_flags, + unsigned mem_flags, dma_addr_t *dma ) { diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 4d692670f28..583db7c38cf 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -470,7 +470,7 @@ static int dummy_disable (struct usb_ep *_ep) } static struct usb_request * -dummy_alloc_request (struct usb_ep *_ep, int mem_flags) +dummy_alloc_request (struct usb_ep *_ep, unsigned mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -507,7 +507,7 @@ dummy_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - int mem_flags + unsigned mem_flags ) { char *retval; struct dummy_ep *ep; @@ -540,7 +540,8 @@ fifo_complete (struct usb_ep *ep, struct usb_request *req) } static int -dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags) +dummy_queue (struct usb_ep *_ep, struct usb_request *_req, + unsigned mem_flags) { struct dummy_ep *ep; struct dummy_request *req; @@ -998,7 +999,7 @@ static int dummy_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct dummy *dum; struct urbp *urbp; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 5bb53ae8896..00a5d256626 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -945,11 +945,11 @@ config_buf (enum usb_device_speed speed, /*-------------------------------------------------------------------------*/ -static void eth_start (struct eth_dev *dev, int gfp_flags); -static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags); +static void eth_start (struct eth_dev *dev, unsigned gfp_flags); +static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags); static int -set_ether_config (struct eth_dev *dev, int gfp_flags) +set_ether_config (struct eth_dev *dev, unsigned gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1079,7 +1079,7 @@ static void eth_reset_config (struct eth_dev *dev) * that returns config descriptors, and altsetting code. */ static int -eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) +eth_set_config (struct eth_dev *dev, unsigned number, unsigned gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -1596,7 +1596,7 @@ static void defer_kevent (struct eth_dev *dev, int flag) static void rx_complete (struct usb_ep *ep, struct usb_request *req); static int -rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) +rx_submit (struct eth_dev *dev, struct usb_request *req, unsigned gfp_flags) { struct sk_buff *skb; int retval = -ENOMEM; @@ -1722,7 +1722,7 @@ clean: } static int prealloc (struct list_head *list, struct usb_ep *ep, - unsigned n, int gfp_flags) + unsigned n, unsigned gfp_flags) { unsigned i; struct usb_request *req; @@ -1761,7 +1761,7 @@ extra: return 0; } -static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags) +static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags) { int status; @@ -1777,7 +1777,7 @@ fail: return status; } -static void rx_fill (struct eth_dev *dev, int gfp_flags) +static void rx_fill (struct eth_dev *dev, unsigned gfp_flags) { struct usb_request *req; unsigned long flags; @@ -2022,7 +2022,7 @@ static int rndis_control_ack (struct net_device *net) #endif /* RNDIS */ -static void eth_start (struct eth_dev *dev, int gfp_flags) +static void eth_start (struct eth_dev *dev, unsigned gfp_flags) { DEBUG (dev, "%s\n", __FUNCTION__); diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index ed773a9111d..eaab26f4ed3 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -269,7 +269,7 @@ static int goku_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -goku_alloc_request(struct usb_ep *_ep, int gfp_flags) +goku_alloc_request(struct usb_ep *_ep, unsigned gfp_flags) { struct goku_request *req; @@ -327,7 +327,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req) */ static void * goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, int gfp_flags) + dma_addr_t *dma, unsigned gfp_flags) { void *retval; struct goku_ep *ep; @@ -789,7 +789,7 @@ finished: /*-------------------------------------------------------------------------*/ static int -goku_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +goku_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct goku_request *req; struct goku_ep *ep; diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index df75ab65a5e..4842577789c 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -1106,7 +1106,7 @@ static int lh7a40x_ep_disable(struct usb_ep *_ep) } static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, - int gfp_flags) + unsigned gfp_flags) { struct lh7a40x_request *req; @@ -1134,7 +1134,7 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req) } static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes, - dma_addr_t * dma, int gfp_flags) + dma_addr_t * dma, unsigned gfp_flags) { char *retval; @@ -1158,7 +1158,7 @@ static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma, * NOTE: Sets INDEX register */ static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req, - int gfp_flags) + unsigned gfp_flags) { struct lh7a40x_request *req; struct lh7a40x_ep *ep; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 13a3dbc9949..234a1a97b84 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -376,7 +376,7 @@ static int net2280_disable (struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -net2280_alloc_request (struct usb_ep *_ep, int gfp_flags) +net2280_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) { struct net2280_ep *ep; struct net2280_request *req; @@ -463,7 +463,7 @@ net2280_alloc_buffer ( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - int gfp_flags + unsigned gfp_flags ) { void *retval; @@ -897,7 +897,7 @@ done (struct net2280_ep *ep, struct net2280_request *req, int status) /*-------------------------------------------------------------------------*/ static int -net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +net2280_queue (struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct net2280_request *req; struct net2280_ep *ep; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index a2b812af6e6..c906d675ef4 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -269,7 +269,7 @@ static int omap_ep_disable(struct usb_ep *_ep) /*-------------------------------------------------------------------------*/ static struct usb_request * -omap_alloc_request(struct usb_ep *ep, int gfp_flags) +omap_alloc_request(struct usb_ep *ep, unsigned gfp_flags) { struct omap_req *req; @@ -298,7 +298,7 @@ omap_alloc_buffer( struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, - int gfp_flags + unsigned gfp_flags ) { void *retval; @@ -937,7 +937,7 @@ static void dma_channel_release(struct omap_ep *ep) /*-------------------------------------------------------------------------*/ static int -omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); struct omap_req *req = container_of(_req, struct omap_req, req); diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 6a0b957af33..1507738337c 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -332,7 +332,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep) * pxa2xx_ep_alloc_request - allocate a request data structure */ static struct usb_request * -pxa2xx_ep_alloc_request (struct usb_ep *_ep, int gfp_flags) +pxa2xx_ep_alloc_request (struct usb_ep *_ep, unsigned gfp_flags) { struct pxa2xx_request *req; @@ -367,7 +367,7 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) */ static void * pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, - dma_addr_t *dma, int gfp_flags) + dma_addr_t *dma, unsigned gfp_flags) { char *retval; @@ -874,7 +874,7 @@ done: /*-------------------------------------------------------------------------*/ static int -pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags) { struct pxa2xx_request *req; struct pxa2xx_ep *ep; diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index a6e035e2447..bb9b2d94eed 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -612,7 +612,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, int gfp_flags) +source_sink_start_ep (struct usb_ep *ep, unsigned gfp_flags) { struct usb_request *req; int status; @@ -640,7 +640,7 @@ source_sink_start_ep (struct usb_ep *ep, int gfp_flags) } static int -set_source_sink_config (struct zero_dev *dev, int gfp_flags) +set_source_sink_config (struct zero_dev *dev, unsigned gfp_flags) { int result = 0; struct usb_ep *ep; @@ -744,7 +744,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } static int -set_loopback_config (struct zero_dev *dev, int gfp_flags) +set_loopback_config (struct zero_dev *dev, unsigned gfp_flags) { int result = 0; struct usb_ep *ep; @@ -845,7 +845,7 @@ static void zero_reset_config (struct zero_dev *dev) * by limiting configuration choices (like the pxa2xx). */ static int -zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags) +zero_set_config (struct zero_dev *dev, unsigned number, unsigned gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 35248a37b71..149b13fc0a7 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -960,7 +960,7 @@ static int ehci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct list_head qtd_list; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 45d89a7083b..d74b2d68a50 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -898,7 +898,7 @@ submit_async ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - int mem_flags + unsigned mem_flags ) { struct ehci_qtd *qtd; int epnum; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index c2104cad403..9af4f64532a 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -588,7 +588,7 @@ static int intr_submit ( struct usb_host_endpoint *ep, struct urb *urb, struct list_head *qtd_list, - int mem_flags + unsigned mem_flags ) { unsigned epnum; unsigned long flags; @@ -633,7 +633,7 @@ done: /* ehci_iso_stream ops work with both ITD and SITD */ static struct ehci_iso_stream * -iso_stream_alloc (int mem_flags) +iso_stream_alloc (unsigned mem_flags) { struct ehci_iso_stream *stream; @@ -846,7 +846,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) /* ehci_iso_sched ops can be ITD-only or SITD-only */ static struct ehci_iso_sched * -iso_sched_alloc (unsigned packets, int mem_flags) +iso_sched_alloc (unsigned packets, unsigned mem_flags) { struct ehci_iso_sched *iso_sched; int size = sizeof *iso_sched; @@ -919,7 +919,7 @@ itd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ehci_itd *itd; @@ -1412,7 +1412,8 @@ itd_complete ( /*-------------------------------------------------------------------------*/ -static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, + unsigned mem_flags) { int status = -EINVAL; unsigned long flags; @@ -1523,7 +1524,7 @@ sitd_urb_transaction ( struct ehci_iso_stream *stream, struct ehci_hcd *ehci, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ehci_sitd *sitd; @@ -1772,7 +1773,8 @@ sitd_complete ( } -static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, + unsigned mem_flags) { int status = -EINVAL; unsigned long flags; @@ -1822,7 +1824,8 @@ done: #else static inline int -sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) +sitd_submit (struct ehci_hcd *ehci, struct urb *urb, + unsigned mem_flags) { ehci_dbg (ehci, "split iso support is disabled\n"); return -ENOSYS; diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index d9883d774d3..81f8f6b7fdc 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -463,7 +463,8 @@ static void etrax_usb_free_epid(int epid); static int etrax_remove_from_sb_list(struct urb *urb); -static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma); +static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, + unsigned mem_flags, dma_addr_t *dma); static void etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid); @@ -476,7 +477,7 @@ static int etrax_usb_submit_ctrl_urb(struct urb *urb); static int etrax_usb_submit_intr_urb(struct urb *urb); static int etrax_usb_submit_isoc_urb(struct urb *urb); -static int etrax_usb_submit_urb(struct urb *urb, int mem_flags); +static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags); static int etrax_usb_unlink_urb(struct urb *urb, int status); static int etrax_usb_get_frame_number(struct usb_device *usb_dev); @@ -1262,7 +1263,7 @@ static int etrax_usb_allocate_epid(void) return -1; } -static int etrax_usb_submit_urb(struct urb *urb, int mem_flags) +static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags) { etrax_hc_t *hc; int ret = -EINVAL; @@ -4277,7 +4278,8 @@ etrax_usb_bulk_eot_timer_func(unsigned long dummy) } static void* -etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma) +etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, + unsigned mem_flags, dma_addr_t *dma) { return kmalloc(size, mem_flags); } diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 3f2cea21efc..50b1970fe6b 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -693,7 +693,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load) static int isp116x_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - int mem_flags) + unsigned mem_flags) { struct isp116x *isp116x = hcd_to_isp116x(hcd); struct usb_device *udev = urb->dev; @@ -715,7 +715,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, } /* avoid all allocations within spinlocks: request or endpoint */ if (!hep->hcpriv) { - ep = kcalloc(1, sizeof *ep, (__force unsigned)mem_flags); + ep = kcalloc(1, sizeof *ep, mem_flags); if (!ep) return -ENOMEM; } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 13cd2177b55..0375097850e 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -180,7 +180,7 @@ static int ohci_urb_enqueue ( struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ed *ed; diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 23735a36af0..fd3c4d3714b 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -84,7 +84,7 @@ dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) /* TDs ... */ static struct td * -td_alloc (struct ohci_hcd *hc, int mem_flags) +td_alloc (struct ohci_hcd *hc, unsigned mem_flags) { dma_addr_t dma; struct td *td; @@ -118,7 +118,7 @@ td_free (struct ohci_hcd *hc, struct td *td) /* EDs ... */ static struct ed * -ed_alloc (struct ohci_hcd *hc, int mem_flags) +ed_alloc (struct ohci_hcd *hc, unsigned mem_flags) { dma_addr_t dma; struct ed *ed; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 6c3f910bc30..7a890a65f55 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -815,7 +815,7 @@ static int sl811h_urb_enqueue( struct usb_hcd *hcd, struct usb_host_endpoint *hep, struct urb *urb, - int mem_flags + unsigned mem_flags ) { struct sl811 *sl811 = hcd_to_sl811(hcd); struct usb_device *udev = urb->dev; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 5f18084a116..bbb36cd6ed6 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1164,7 +1164,7 @@ static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) static int uhci_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, - struct urb *urb, int mem_flags) + struct urb *urb, unsigned mem_flags) { int ret; struct uhci_hcd *uhci = hcd_to_uhci(hcd); diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index fd6ff4cb2c6..7ffa99b9760 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -477,7 +477,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) } static void kaweth_usb_receive(struct urb *, struct pt_regs *regs); -static int kaweth_resubmit_rx_urb(struct kaweth_device *, int); +static int kaweth_resubmit_rx_urb(struct kaweth_device *, unsigned); /**************************************************************** int_callback @@ -550,7 +550,7 @@ static void kaweth_resubmit_tl(void *d) * kaweth_resubmit_rx_urb ****************************************************************/ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, - int mem_flags) + unsigned mem_flags) { int result; -- cgit v1.2.3 From 30e695986679ac2d2354fc1634e8cb931bb47785 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 26 Jun 2005 17:18:46 -0700 Subject: [PATCH] USB: net2280 warning fix drivers/usb/gadget/net2280.c: In function 'show_registers': drivers/usb/gadget/net2280.c:1501: warning: assignment discards qualifiers from pointer target type Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/net2280.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 234a1a97b84..477fab2e74d 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1490,7 +1490,7 @@ show_registers (struct device *_dev, struct device_attribute *attr, char *buf) unsigned long flags; int i; u32 t1, t2; - char *s; + const char *s; dev = dev_get_drvdata (_dev); next = buf; -- cgit v1.2.3 From 99f83c9c9ac994c844ecf3e64e848c2f8dd7dfe0 Mon Sep 17 00:00:00 2001 From: Michael Downey Date: Mon, 27 Jun 2005 11:48:26 -0600 Subject: [PATCH] USB: add driver for Keyspan Digital Remote This driver is a basic keypress input driver for the Keyspan Digital Remote with part number UIA-11. Currently there is an older remote with part number UIA-10 which isn't supported by this driver. Support for the older UIA-10 could be added but a binary file is required to be download to the device, and I don't have that file. I also don't have a UIA-10 device so I wouldn't be able to test any of the changes. Signed-off-by: Michael Downey Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/Kconfig | 13 + drivers/usb/input/Makefile | 1 + drivers/usb/input/keyspan_remote.c | 633 +++++++++++++++++++++++++++++++++++++ 3 files changed, 647 insertions(+) create mode 100644 drivers/usb/input/keyspan_remote.c (limited to 'drivers') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index fd59f6bdd67..298e4a25e3d 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -259,3 +259,16 @@ config USB_ATI_REMOTE To compile this driver as a module, choose M here: the module will be called ati_remote. +config USB_KEYSPAN_REMOTE + tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" + depends on USB && INPUT && EXPERIMENTAL + ---help--- + Say Y here if you want to use a Keyspan DMR USB remote control. + Currently only the UIA-11 type of receiver has been tested. The tag + on the receiver that connects to the USB port should have a P/N that + will tell you what type of DMR you have. The UIA-10 type is not + supported at this time. This driver maps all buttons to keypress + events. + + To compile this driver as a module, choose M here: the module will + be called keyspan_remote. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 831b2b0f1f0..f1547be632d 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_USB_HID) += usbhid.o obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_KBTAB) += kbtab.o +obj-$(CONFIG_USB_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c new file mode 100644 index 00000000000..67dc9368520 --- /dev/null +++ b/drivers/usb/input/keyspan_remote.c @@ -0,0 +1,633 @@ +/* + * keyspan_remote: USB driver for the Keyspan DMR + * + * Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + * This driver has been put together with the support of Innosys, Inc. + * and Keyspan, Inc the manufacturers of the Keyspan USB DMR product. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "v0.1" +#define DRIVER_AUTHOR "Michael Downey " +#define DRIVER_DESC "Driver for the USB Keyspan remote control." +#define DRIVER_LICENSE "GPL" + +/* Parameters that can be passed to the driver. */ +static int debug; +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); + +/* Vendor and product ids */ +#define USB_KEYSPAN_VENDOR_ID 0x06CD +#define USB_KEYSPAN_PRODUCT_UIA11 0x0202 + +/* Defines for converting the data from the remote. */ +#define ZERO 0x18 +#define ZERO_MASK 0x1F /* 5 bits for a 0 */ +#define ONE 0x3C +#define ONE_MASK 0x3F /* 6 bits for a 1 */ +#define SYNC 0x3F80 +#define SYNC_MASK 0x3FFF /* 14 bits for a SYNC sequence */ +#define STOP 0x00 +#define STOP_MASK 0x1F /* 5 bits for the STOP sequence */ +#define GAP 0xFF + +#define RECV_SIZE 8 /* The UIA-11 type have a 8 byte limit. */ + +/* table of devices that work with this driver */ +static struct usb_device_id keyspan_table[] = { + { USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) }, + { } /* Terminating entry */ +}; + +/* Structure to store all the real stuff that a remote sends to us. */ +struct keyspan_message { + u16 system; + u8 button; + u8 toggle; +}; + +/* Structure used for all the bit testing magic needed to be done. */ +struct bit_tester { + u32 tester; + int len; + int pos; + int bits_left; + u8 buffer[32]; +}; + +/* Structure to hold all of our driver specific stuff */ +struct usb_keyspan { + char name[128]; + char phys[64]; + struct usb_device* udev; + struct input_dev input; + struct usb_interface* interface; + struct usb_endpoint_descriptor* in_endpoint; + struct urb* irq_urb; + int open; + dma_addr_t in_dma; + unsigned char* in_buffer; + + /* variables used to parse messages from remote. */ + struct bit_tester data; + int stage; + int toggle; +}; + +/* + * Table that maps the 31 possible keycodes to input keys. + * Currently there are 15 and 17 button models so RESERVED codes + * are blank areas in the mapping. + */ +static int keyspan_key_table[] = { + KEY_RESERVED, /* 0 is just a place holder. */ + KEY_RESERVED, + KEY_STOP, + KEY_PLAYCD, + KEY_RESERVED, + KEY_PREVIOUSSONG, + KEY_REWIND, + KEY_FORWARD, + KEY_NEXTSONG, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_PAUSE, + KEY_VOLUMEUP, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_VOLUMEDOWN, + KEY_RESERVED, + KEY_UP, + KEY_RESERVED, + KEY_MUTE, + KEY_LEFT, + KEY_ENTER, + KEY_RIGHT, + KEY_RESERVED, + KEY_RESERVED, + KEY_DOWN, + KEY_RESERVED, + KEY_KPASTERISK, + KEY_RESERVED, + KEY_MENU +}; + +static struct usb_driver keyspan_driver; + +/* + * Debug routine that prints out what we've received from the remote. + */ +static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/ +{ + char codes[4*RECV_SIZE]; + int i; + + for (i = 0; i < RECV_SIZE; i++) { + snprintf(codes+i*3, 4, "%02x ", dev->in_buffer[i]); + } + + dev_info(&dev->udev->dev, "%s\n", codes); +} + +/* + * Routine that manages the bit_tester structure. It makes sure that there are + * at least bits_needed bits loaded into the tester. + */ +static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) +{ + if (dev->data.bits_left >= bits_needed) + return(0); + + /* + * Somehow we've missed the last message. The message will be repeated + * though so it's not too big a deal + */ + if (dev->data.pos >= dev->data.len) { + dev_dbg(&dev->udev, "%s - Error ran out of data. pos: %d, len: %d\n", + __FUNCTION__, dev->data.pos, dev->data.len); + return(-1); + } + + /* Load as much as we can into the tester. */ + while ((dev->data.bits_left + 7 < (sizeof(dev->data.tester) * 8)) && + (dev->data.pos < dev->data.len)) { + dev->data.tester += (dev->data.buffer[dev->data.pos++] << dev->data.bits_left); + dev->data.bits_left += 8; + } + + return(0); +} + +/* + * Routine that handles all the logic needed to parse out the message from the remote. + */ +static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs) +{ + int i; + int found = 0; + struct keyspan_message message; + + switch(remote->stage) { + case 0: + /* + * In stage 0 we want to find the start of a message. The remote sends a 0xFF as filler. + * So the first byte that isn't a FF should be the start of a new message. + */ + for (i = 0; i < RECV_SIZE && remote->in_buffer[i] == GAP; ++i); + + if (i < RECV_SIZE) { + memcpy(remote->data.buffer, remote->in_buffer, RECV_SIZE); + remote->data.len = RECV_SIZE; + remote->data.pos = 0; + remote->data.tester = 0; + remote->data.bits_left = 0; + remote->stage = 1; + } + break; + + case 1: + /* + * Stage 1 we should have 16 bytes and should be able to detect a + * SYNC. The SYNC is 14 bits, 7 0's and then 7 1's. + */ + memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE); + remote->data.len += RECV_SIZE; + + found = 0; + while ((remote->data.bits_left >= 14 || remote->data.pos < remote->data.len) && !found) { + for (i = 0; i < 8; ++i) { + if (keyspan_load_tester(remote, 14) != 0) { + remote->stage = 0; + return; + } + + if ((remote->data.tester & SYNC_MASK) == SYNC) { + remote->data.tester = remote->data.tester >> 14; + remote->data.bits_left -= 14; + found = 1; + break; + } else { + remote->data.tester = remote->data.tester >> 1; + --remote->data.bits_left; + } + } + } + + if (!found) { + remote->stage = 0; + remote->data.len = 0; + } else { + remote->stage = 2; + } + break; + + case 2: + /* + * Stage 2 we should have 24 bytes which will be enough for a full + * message. We need to parse out the system code, button code, + * toggle code, and stop. + */ + memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE); + remote->data.len += RECV_SIZE; + + message.system = 0; + for (i = 0; i < 9; i++) { + keyspan_load_tester(remote, 6); + + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.system = message.system << 1; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.system = (message.system << 1) + 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Unknown sequence found in system data.\n", __FUNCTION__); + remote->stage = 0; + return; + } + } + + message.button = 0; + for (i = 0; i < 5; i++) { + keyspan_load_tester(remote, 6); + + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.button = message.button << 1; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.button = (message.button << 1) + 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Unknown sequence found in button data.\n", __FUNCTION__); + remote->stage = 0; + return; + } + } + + keyspan_load_tester(remote, 6); + if ((remote->data.tester & ZERO_MASK) == ZERO) { + message.toggle = 0; + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else if ((remote->data.tester & ONE_MASK) == ONE) { + message.toggle = 1; + remote->data.tester = remote->data.tester >> 6; + remote->data.bits_left -= 6; + } else { + err("%s - Error in message, invalid toggle.\n", __FUNCTION__); + } + + keyspan_load_tester(remote, 5); + if ((remote->data.tester & STOP_MASK) == STOP) { + remote->data.tester = remote->data.tester >> 5; + remote->data.bits_left -= 5; + } else { + err("Bad message recieved, no stop bit found.\n"); + } + + dev_dbg(&remote->udev, + "%s found valid message: system: %d, button: %d, toggle: %d\n", + __FUNCTION__, message.system, message.button, message.toggle); + + if (message.toggle != remote->toggle) { + input_regs(&remote->input, regs); + input_report_key(&remote->input, keyspan_key_table[message.button], 1); + input_report_key(&remote->input, keyspan_key_table[message.button], 0); + input_sync(&remote->input); + remote->toggle = message.toggle; + } + + remote->stage = 0; + break; + } +} + +/* + * Routine for sending all the initialization messages to the remote. + */ +static int keyspan_setup(struct usb_device* dev) +{ + int retval = 0; + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x44, 0x40, 0x0, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x22, 0x40, 0x0, 0x0, NULL, 0, 0); + if (retval) { + dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n", + __FUNCTION__, retval); + return(retval); + } + + dev_dbg(&dev->dev, "%s - Setup complete.\n", __FUNCTION__); + return(retval); +} + +/* + * Routine used to handle a new message that has come in. + */ +static void keyspan_irq_recv(struct urb *urb, struct pt_regs *regs) +{ + struct usb_keyspan *dev = urb->context; + int retval; + + /* Check our status in case we need to bail out early. */ + switch (urb->status) { + case 0: + break; + + /* Device went away so don't keep trying to read from it. */ + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + + default: + goto resubmit; + break; + } + + if (debug) + keyspan_print(dev); + + keyspan_check_data(dev, regs); + +resubmit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result: %d", __FUNCTION__, retval); +} + +static int keyspan_open(struct input_dev *dev) +{ + struct usb_keyspan *remote = dev->private; + + if (remote->open++) + return 0; + + remote->irq_urb->dev = remote->udev; + if (usb_submit_urb(remote->irq_urb, GFP_KERNEL)) { + remote->open--; + return -EIO; + } + + return 0; +} + +static void keyspan_close(struct input_dev *dev) +{ + struct usb_keyspan *remote = dev->private; + + if (!--remote->open) + usb_kill_urb(remote->irq_urb); +} + +/* + * Routine that sets up the driver to handle a specific USB device detected on the bus. + */ +static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + int i; + int retval = -ENOMEM; + char path[64]; + char *buf; + struct usb_keyspan *remote = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface)); + + /* See if the offered device matches what we can accept */ + if ((udev->descriptor.idVendor != USB_KEYSPAN_VENDOR_ID) || + (udev->descriptor.idProduct != USB_KEYSPAN_PRODUCT_UIA11) ) + return -ENODEV; + + /* allocate memory for our device state and initialize it */ + remote = kmalloc(sizeof(*remote), GFP_KERNEL); + if (remote == NULL) { + err("Out of memory\n"); + goto error; + } + memset(remote, 0x00, sizeof(*remote)); + + remote->udev = udev; + remote->interface = interface; + remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */ + + /* set up the endpoint information */ + /* use only the first in interrupt endpoint */ + iface_desc = interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!remote->in_endpoint && + (endpoint->bEndpointAddress & USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + /* we found our interrupt in endpoint */ + remote->in_endpoint = endpoint; + + remote->in_buffer = usb_buffer_alloc(remote->udev, RECV_SIZE, SLAB_ATOMIC, &remote->in_dma); + if (!remote->in_buffer) { + retval = -ENOMEM; + goto error; + } + } + } + + if (!remote->in_endpoint) { + err("Could not find interrupt input endpoint.\n"); + retval = -ENODEV; + goto error; + } + + remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!remote->irq_urb) { + err("Failed to allocate urb.\n"); + retval = -ENOMEM; + goto error; + } + + retval = keyspan_setup(remote->udev); + if (retval) { + err("Failed to setup device.\n"); + retval = -ENODEV; + goto error; + } + + /* + * Setup the input system with the bits we are going to be reporting + */ + remote->input.evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */ + for (i = 0; i < 32; ++i) { + if (keyspan_key_table[i] != KEY_RESERVED) { + set_bit(keyspan_key_table[i], remote->input.keybit); + } + } + + remote->input.private = remote; + remote->input.open = keyspan_open; + remote->input.close = keyspan_close; + + usb_make_path(remote->udev, path, 64); + sprintf(remote->phys, "%s/input0", path); + + remote->input.name = remote->name; + remote->input.phys = remote->phys; + remote->input.id.bustype = BUS_USB; + remote->input.id.vendor = le16_to_cpu(remote->udev->descriptor.idVendor); + remote->input.id.product = le16_to_cpu(remote->udev->descriptor.idProduct); + remote->input.id.version = le16_to_cpu(remote->udev->descriptor.bcdDevice); + + if (!(buf = kmalloc(63, GFP_KERNEL))) { + usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + kfree(remote); + return -ENOMEM; + } + + if (remote->udev->descriptor.iManufacturer && + usb_string(remote->udev, remote->udev->descriptor.iManufacturer, buf, 63) > 0) + strcat(remote->name, buf); + + if (remote->udev->descriptor.iProduct && + usb_string(remote->udev, remote->udev->descriptor.iProduct, buf, 63) > 0) + sprintf(remote->name, "%s %s", remote->name, buf); + + if (!strlen(remote->name)) + sprintf(remote->name, "USB Keyspan Remote %04x:%04x", + remote->input.id.vendor, remote->input.id.product); + + kfree(buf); + + /* + * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open() + */ + usb_fill_int_urb(remote->irq_urb, + remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress), + remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote, + remote->in_endpoint->bInterval); + remote->irq_urb->transfer_dma = remote->in_dma; + remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* we can register the device now, as it is ready */ + input_register_device(&remote->input); + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, remote); + + /* let the user know what node this device is now attached to */ + info("connected: %s on %s", remote->name, path); + return 0; + +error: + /* + * In case of error we need to clean up any allocated buffers + */ + if (remote->irq_urb) + usb_free_urb(remote->irq_urb); + + if (remote->in_buffer) + usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + + if (remote) + kfree(remote); + + return retval; +} + +/* + * Routine called when a device is disconnected from the USB. + */ +static void keyspan_disconnect(struct usb_interface *interface) +{ + struct usb_keyspan *remote; + + /* prevent keyspan_open() from racing keyspan_disconnect() */ + lock_kernel(); + + remote = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + if (remote) { /* We have a valid driver structure so clean up everything we allocated. */ + input_unregister_device(&remote->input); + usb_kill_urb(remote->irq_urb); + usb_free_urb(remote->irq_urb); + usb_buffer_free(interface_to_usbdev(interface), RECV_SIZE, remote->in_buffer, remote->in_dma); + kfree(remote); + } + + unlock_kernel(); + + info("USB Keyspan now disconnected"); +} + +/* + * Standard driver set up sections + */ +static struct usb_driver keyspan_driver = +{ + .owner = THIS_MODULE, + .name = "keyspan_remote", + .probe = keyspan_probe, + .disconnect = keyspan_disconnect, + .id_table = keyspan_table +}; + +static int __init usb_keyspan_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&keyspan_driver); + if (result) + err("usb_register failed. Error number %d\n", result); + + return result; +} + +static void __exit usb_keyspan_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&keyspan_driver); +} + +module_init(usb_keyspan_init); +module_exit(usb_keyspan_exit); + +MODULE_DEVICE_TABLE(usb, keyspan_table); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); -- cgit v1.2.3 From b2134bcd2e1bf989e0566dd1b0e59a792722b671 Mon Sep 17 00:00:00 2001 From: "KAMBAROV, ZAUR" Date: Fri, 24 Jun 2005 22:20:35 -0700 Subject: [PATCH] USB: coverity: (desc->bitmap)[] overrun fix The length of the array desc->bitmap is 3, and not 4: Definitions involved: In drivers/usb/core/hcd.h 464 #define bitmap DeviceRemovable In drivers/usb/host/ohci-hub.c 395 struct usb_hub_descriptor *desc In drivers/usb/core/hub.h 130 struct usb_hub_descriptor { 131 __u8 bDescLength; 132 __u8 bDescriptorType; 133 __u8 bNbrPorts; 134 __u16 wHubCharacteristics; 135 __u8 bPwrOn2PwrGood; 136 __u8 bHubContrCurrent; 137 /* add 1 bit for hub status change; round to bytes */ 138 __u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8]; 139 __u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8]; 140 } __attribute__ ((packed)); In include/linux/usb.h 306 #define USB_MAXCHILDREN (16) This defect was found automatically by Coverity Prevent, a static analysis tool. (akpm: this code should be shot. Field `bitmap' doesn't exist in struct usb_hub_descriptor. And this .c file is #included in drivers/usb/host/ohci-hcd.c, and someone somewhere #defines `bitmap' to `DeviceRemovable'. >From a maintainability POV it would be better to memset the whole array beforehand - I changed the patch to do that) Signed-off-by: Zaur Kambarov Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index e2fc4129dfc..83ca4549a50 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -419,10 +419,11 @@ ohci_hub_descriptor ( /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ rh = roothub_b (ohci); + memset(desc->bitmap, 0xff, sizeof(desc->bitmap)); desc->bitmap [0] = rh & RH_B_DR; if (ports > 7) { desc->bitmap [1] = (rh & RH_B_DR) >> 8; - desc->bitmap [2] = desc->bitmap [3] = 0xff; + desc->bitmap [2] = 0xff; } else desc->bitmap [1] = 0xff; } -- cgit v1.2.3 From 8fd6db47b90c7ecac32e3211f771849e148bdb07 Mon Sep 17 00:00:00 2001 From: Michael Hund Date: Mon, 27 Jun 2005 22:44:22 +0200 Subject: [PATCH] USB: add LD devices to hid blacklist below you will find one patch to hid-core.c, which lets usbhid ignore our HID devices. It would be nice, if you can apply it. Signed-off-by: Michael Hund Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 100b49bd1d3..2350e7a5ad7 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1428,6 +1428,19 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_VERNIER_SKIP 0x0003 #define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 +#define USB_VENDOR_ID_LD 0x0f11 +#define USB_DEVICE_ID_CASSY 0x1000 +#define USB_DEVICE_ID_POCKETCASSY 0x1010 +#define USB_DEVICE_ID_MOBILECASSY 0x1020 +#define USB_DEVICE_ID_JWM 0x1080 +#define USB_DEVICE_ID_DMMP 0x1081 +#define USB_DEVICE_ID_UMIP 0x1090 +#define USB_DEVICE_ID_VIDEOCOM 0x1200 +#define USB_DEVICE_ID_COM3LAB 0x2000 +#define USB_DEVICE_ID_TELEPORT 0x2010 +#define USB_DEVICE_ID_NETWORKANALYSER 0x2020 +#define USB_DEVICE_ID_POWERCONTROL 0x2030 + /* * Alphabetically sorted blacklist by quirk type. @@ -1463,6 +1476,17 @@ static struct hid_blacklist { { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_CASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_POCKETCASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_MOBILECASSY, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_JWM, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_DMMP, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_UMIP, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_VIDEOCOM, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_COM3LAB, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_TELEPORT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_NETWORKANALYSER, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LD, USB_DEVICE_ID_POWERCONTROL, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, -- cgit v1.2.3 From b9df978f1974fea373741367b5d79a2ed3b7dcf9 Mon Sep 17 00:00:00 2001 From: Luca Risolia Date: Sat, 25 Jun 2005 16:30:24 +0200 Subject: [PATCH] USB: SN9C10x driver updates SN9C10x driver updates. Changes: + new, - removed, * cleanup, @ bugfix @ Remove bad get_ctrl()'s * Documentation updates + Add 0x0c45/0x602d to the list of SN9C10x based devices + Add support for OV7630 image sensors Signed-off-by: Luca Risolia Signed-off-by: Greg Kroah-Hartman --- drivers/usb/media/Makefile | 2 +- drivers/usb/media/sn9c102.h | 2 +- drivers/usb/media/sn9c102_core.c | 2 +- drivers/usb/media/sn9c102_ov7630.c | 394 +++++++++++++++++++++++++++++++++ drivers/usb/media/sn9c102_sensor.h | 16 +- drivers/usb/media/sn9c102_tas5110c1b.c | 21 +- drivers/usb/media/sn9c102_tas5130d1b.c | 27 +-- 7 files changed, 413 insertions(+), 51 deletions(-) create mode 100644 drivers/usb/media/sn9c102_ov7630.c (limited to 'drivers') diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile index 2b76df7005f..d83adffa925 100644 --- a/drivers/usb/media/Makefile +++ b/drivers/usb/media/Makefile @@ -2,7 +2,7 @@ # Makefile for USB Media drivers # -sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o +sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_DSBR) += dsbr100.o diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h index 8b8a4c8743f..e5cea0e2eb5 100644 --- a/drivers/usb/media/sn9c102.h +++ b/drivers/usb/media/sn9c102.h @@ -56,7 +56,7 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004-2005 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.24" +#define SN9C102_MODULE_VERSION "1:1.24a" #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 24) enum sn9c102_bridge { diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c index 31d57400d5b..cf8cfbabefd 100644 --- a/drivers/usb/media/sn9c102_core.c +++ b/drivers/usb/media/sn9c102_core.c @@ -429,7 +429,7 @@ sn9c102_i2c_try_read(struct sn9c102_device* cam, } -static int +int sn9c102_i2c_try_write(struct sn9c102_device* cam, struct sn9c102_sensor* sensor, u8 address, u8 value) { diff --git a/drivers/usb/media/sn9c102_ov7630.c b/drivers/usb/media/sn9c102_ov7630.c new file mode 100644 index 00000000000..d27c5aedeaf --- /dev/null +++ b/drivers/usb/media/sn9c102_ov7630.c @@ -0,0 +1,394 @@ +/*************************************************************************** + * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera * + * Controllers * + * * + * Copyright (C) 2005 by Luca Risolia * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include "sn9c102_sensor.h" + + +static struct sn9c102_sensor ov7630; + + +static int ov7630_init(struct sn9c102_device* cam) +{ + int err = 0; + + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x60, 0x17); + err += sn9c102_write_reg(cam, 0x0f, 0x18); + err += sn9c102_write_reg(cam, 0x50, 0x19); + + err += sn9c102_i2c_write(cam, 0x12, 0x8d); + err += sn9c102_i2c_write(cam, 0x11, 0x00); + err += sn9c102_i2c_write(cam, 0x15, 0x34); + err += sn9c102_i2c_write(cam, 0x16, 0x03); + err += sn9c102_i2c_write(cam, 0x17, 0x1c); + err += sn9c102_i2c_write(cam, 0x18, 0xbd); + err += sn9c102_i2c_write(cam, 0x19, 0x06); + err += sn9c102_i2c_write(cam, 0x1a, 0xf6); + err += sn9c102_i2c_write(cam, 0x1b, 0x04); + err += sn9c102_i2c_write(cam, 0x20, 0x44); + err += sn9c102_i2c_write(cam, 0x23, 0xee); + err += sn9c102_i2c_write(cam, 0x26, 0xa0); + err += sn9c102_i2c_write(cam, 0x27, 0x9a); + err += sn9c102_i2c_write(cam, 0x28, 0x20); + err += sn9c102_i2c_write(cam, 0x29, 0x30); + err += sn9c102_i2c_write(cam, 0x2f, 0x3d); + err += sn9c102_i2c_write(cam, 0x30, 0x24); + err += sn9c102_i2c_write(cam, 0x32, 0x86); + err += sn9c102_i2c_write(cam, 0x60, 0xa9); + err += sn9c102_i2c_write(cam, 0x61, 0x42); + err += sn9c102_i2c_write(cam, 0x65, 0x00); + err += sn9c102_i2c_write(cam, 0x69, 0x38); + err += sn9c102_i2c_write(cam, 0x6f, 0x88); + err += sn9c102_i2c_write(cam, 0x70, 0x0b); + err += sn9c102_i2c_write(cam, 0x71, 0x00); + err += sn9c102_i2c_write(cam, 0x74, 0x21); + err += sn9c102_i2c_write(cam, 0x7d, 0xf7); + + return err; +} + + +static int ov7630_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2); + err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03); + break; + case V4L2_CID_RED_BALANCE: + err += sn9c102_i2c_write(cam, 0x02, ctrl->value); + break; + case V4L2_CID_BLUE_BALANCE: + err += sn9c102_i2c_write(cam, 0x03, ctrl->value); + break; + case V4L2_CID_GAIN: + err += sn9c102_i2c_write(cam, 0x00, ctrl->value); + break; + case V4L2_CID_CONTRAST: + err += ctrl->value ? sn9c102_i2c_write(cam, 0x05, + (ctrl->value-1) | 0x20) + : sn9c102_i2c_write(cam, 0x05, 0x00); + break; + case V4L2_CID_BRIGHTNESS: + err += sn9c102_i2c_write(cam, 0x06, ctrl->value); + break; + case V4L2_CID_SATURATION: + err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4); + break; + case V4L2_CID_HUE: + err += ctrl->value ? sn9c102_i2c_write(cam, 0x04, + (ctrl->value-1) | 0x20) + : sn9c102_i2c_write(cam, 0x04, 0x00); + break; + case V4L2_CID_DO_WHITE_BALANCE: + err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); + break; + case V4L2_CID_WHITENESS: + err += sn9c102_i2c_write(cam, 0x0d, ctrl->value); + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x09); + break; + case V4L2_CID_AUTOGAIN: + err += sn9c102_i2c_write(cam, 0x13, ctrl->value); + break; + case V4L2_CID_VFLIP: + err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7)); + break; + case V4L2_CID_BLACK_LEVEL: + err += sn9c102_i2c_write(cam, 0x25, ctrl->value); + break; + case SN9C102_V4L2_CID_BRIGHT_LEVEL: + err += sn9c102_i2c_write(cam, 0x24, ctrl->value); + break; + case SN9C102_V4L2_CID_GAMMA: + err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80); + break; + case SN9C102_V4L2_CID_BAND_FILTER: + err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2); + break; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + + +static int ov7630_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = &ov7630; + int err = 0; + u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; + + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static int ov7630_set_pix_format(struct sn9c102_device* cam, + const struct v4l2_pix_format* pix) +{ + int err = 0; + + if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) + err += sn9c102_write_reg(cam, 0x20, 0x19); + else + err += sn9c102_write_reg(cam, 0x50, 0x19); + + return err; +} + + +static struct sn9c102_sensor ov7630 = { + .name = "OV7630", + .maintainer = "Luca Risolia ", + .sysfs_ops = SN9C102_I2C_WRITE, + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .i2c_slave_id = 0x21, + .init = &ov7630_init, + .qctrl = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x14, + .flags = 0, + }, + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "hue", + .minimum = 0x00, + .maximum = 0x1f+1, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "saturation", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x08, + .flags = 0, + }, + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "contrast", + .minimum = 0x00, + .maximum = 0x1f+1, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x000, + .maximum = 0x3ff, + .step = 0x001, + .default_value = 0x83<<2, + .flags = 0, + }, + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x3a, + .flags = 0, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0x77, + .flags = 0, + }, + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "brightness", + .minimum = 0x00, + .maximum = 0xff, + .step = 0x01, + .default_value = 0xa0, + .flags = 0, + }, + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "white balance background: blue", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x20, + .flags = 0, + }, + { + .id = V4L2_CID_WHITENESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "white balance background: red", + .minimum = 0x00, + .maximum = 0x3f, + .step = 0x01, + .default_value = 0x20, + .flags = 0, + }, + { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto white balance", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x01, + .flags = 0, + }, + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "gain & exposure mode", + .minimum = 0x00, + .maximum = 0x03, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical flip", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x01, + .flags = 0, + }, + { + .id = V4L2_CID_BLACK_LEVEL, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "black pixel ratio", + .minimum = 0x01, + .maximum = 0x9a, + .step = 0x01, + .default_value = 0x8a, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_BRIGHT_LEVEL, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "bright pixel ratio", + .minimum = 0x01, + .maximum = 0x9a, + .step = 0x01, + .default_value = 0x10, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_BAND_FILTER, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "band filter", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + { + .id = SN9C102_V4L2_CID_GAMMA, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "rgb gamma", + .minimum = 0x00, + .maximum = 0x01, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + }, + .set_ctrl = &ov7630_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &ov7630_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + }, + .set_pix_format = &ov7630_set_pix_format +}; + + +int sn9c102_probe_ov7630(struct sn9c102_device* cam) +{ + int err = 0; + + sn9c102_attach_sensor(cam, &ov7630); + + if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f && + le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c) + return -ENODEV; + + err += sn9c102_write_reg(cam, 0x01, 0x01); + err += sn9c102_write_reg(cam, 0x00, 0x01); + err += sn9c102_write_reg(cam, 0x28, 0x17); + + if (err) + return -EIO; + + err += sn9c102_i2c_write(cam, 0x0b, 0); + if (err) + return -ENODEV; + + return 0; +} diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h index 6a7adebcb4b..a45166c3488 100644 --- a/drivers/usb/media/sn9c102_sensor.h +++ b/drivers/usb/media/sn9c102_sensor.h @@ -64,6 +64,7 @@ struct sn9c102_sensor; */ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); +extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); @@ -80,6 +81,7 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \ &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \ + &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \ &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ NULL, \ @@ -103,7 +105,8 @@ static const struct usb_device_id sn9c102_id_table[] = { \ { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \ { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */ \ { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \ - { USB_DEVICE(0x0c45, 0x602c), }, /* OV7620 */ \ + { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */ \ + { USB_DEVICE(0x0c45, 0x602d), }, \ { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \ { USB_DEVICE(0x0c45, 0x6080), }, \ { USB_DEVICE(0x0c45, 0x6082), }, /* MI0343 and MI0360 */ \ @@ -145,6 +148,8 @@ static const struct usb_device_id sn9c102_id_table[] = { \ */ /* The "try" I2C I/O versions are used when probing the sensor */ +extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, + u8 address, u8 value); extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, u8 address); @@ -201,6 +206,8 @@ enum sn9c102_i2c_interface { SN9C102_I2C_3WIRES, }; +#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10 + struct sn9c102_sensor { char name[32], /* sensor name */ maintainer[64]; /* name of the mantainer */ @@ -243,7 +250,7 @@ struct sn9c102_sensor { sensor according to the default configuration structures below. */ - struct v4l2_queryctrl qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; + struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS]; /* Optional list of default controls, defined as indicated in the V4L2 API. Menu type controls are not handled by this interface. @@ -356,7 +363,7 @@ struct sn9c102_sensor { core module to store successfully updated values of the above settings, for rollbacks..etc..in case of errors during atomic I/O */ - struct v4l2_queryctrl _qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; + struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS]; struct v4l2_rect _rect; }; @@ -367,5 +374,8 @@ struct sn9c102_sensor { #define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1 #define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2 #define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3 +#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4 +#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5 +#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6 #endif /* _SN9C102_SENSOR_H_ */ diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c index 690d6219227..8775999b5af 100644 --- a/drivers/usb/media/sn9c102_tas5110c1b.c +++ b/drivers/usb/media/sn9c102_tas5110c1b.c @@ -24,8 +24,6 @@ static struct sn9c102_sensor tas5110c1b; -static struct v4l2_control tas5110c1b_gain; - static int tas5110c1b_init(struct sn9c102_device* cam) { @@ -46,21 +44,6 @@ static int tas5110c1b_init(struct sn9c102_device* cam) } -static int tas5110c1b_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_GAIN: - ctrl->value = tas5110c1b_gain.value; - break; - default: - return -EINVAL; - } - - return 0; -} - - static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, const struct v4l2_control* ctrl) { @@ -68,8 +51,7 @@ static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, switch (ctrl->id) { case V4L2_CID_GAIN: - if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value))) - tas5110c1b_gain.value = ctrl->value; + err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); break; default: return -EINVAL; @@ -147,7 +129,6 @@ static struct sn9c102_sensor tas5110c1b = { .height = 288, }, }, - .get_ctrl = &tas5110c1b_get_ctrl, .set_crop = &tas5110c1b_set_crop, .pix_format = { .width = 352, diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c index b378e941bbe..927eafdd8c7 100644 --- a/drivers/usb/media/sn9c102_tas5130d1b.c +++ b/drivers/usb/media/sn9c102_tas5130d1b.c @@ -24,8 +24,6 @@ static struct sn9c102_sensor tas5130d1b; -static struct v4l2_control tas5130d1b_gain, tas5130d1b_exposure; - static int tas5130d1b_init(struct sn9c102_device* cam) { @@ -44,24 +42,6 @@ static int tas5130d1b_init(struct sn9c102_device* cam) } -static int tas5130d1b_get_ctrl(struct sn9c102_device* cam, - struct v4l2_control* ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_GAIN: - ctrl->value = tas5130d1b_gain.value; - break; - case V4L2_CID_EXPOSURE: - ctrl->value = tas5130d1b_exposure.value; - break; - default: - return -EINVAL; - } - - return 0; -} - - static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, const struct v4l2_control* ctrl) { @@ -69,12 +49,10 @@ static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, switch (ctrl->id) { case V4L2_CID_GAIN: - if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value))) - tas5130d1b_gain.value = ctrl->value; + err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value); break; case V4L2_CID_EXPOSURE: - if (!(err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value))) - tas5130d1b_exposure.value = ctrl->value; + err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value); break; default: return -EINVAL; @@ -147,7 +125,6 @@ static struct sn9c102_sensor tas5130d1b = { .flags = 0, }, }, - .get_ctrl = &tas5130d1b_get_ctrl, .set_ctrl = &tas5130d1b_set_ctrl, .cropcap = { .bounds = { -- cgit v1.2.3 From 05f33400307cfe9d89dbeca659731b9055fefbf8 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 29 Jun 2005 10:15:32 +0100 Subject: [PATCH] USB: gadget/ether fixes Signed-off-by: Ian Campbell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 00a5d256626..b5647b50336 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2428,7 +2428,7 @@ autoconf_fail: dev->req->complete = eth_setup_complete; /* ... and maybe likewise for status transfer */ -#ifdef DEV_CONFIG_CDC +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) if (dev->status_ep) { dev->stat_req = eth_req_alloc (dev->status_ep, STATUS_BYTECOUNT, GFP_KERNEL); -- cgit v1.2.3 From e828264ee797d40b1df99fe88c6acfc0f36df639 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 29 Jun 2005 10:20:29 +0100 Subject: [PATCH] USB: gadget/ether build fixes. I also needed the following on 2.6.13-rc1 without CONFIG_USB_ETH_RNDIS, symbol fs_status_desc isn't available in that case on PXA255. This builds both with and without ETH_RNDIS, but I haven't actually tested either. Signed-off-by: Ian Campbell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/ether.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index b5647b50336..8509e955007 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -954,6 +954,7 @@ set_ether_config (struct eth_dev *dev, unsigned gfp_flags) int result = 0; struct usb_gadget *gadget = dev->gadget; +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) /* status endpoint used for RNDIS and (optionally) CDC */ if (!subset_active(dev) && dev->status_ep) { dev->status = ep_desc (gadget, &hs_status_desc, @@ -967,6 +968,7 @@ set_ether_config (struct eth_dev *dev, unsigned gfp_flags) goto done; } } +#endif dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); dev->in_ep->driver_data = dev; -- cgit v1.2.3 From 1d7beee3d4b4ae7faa881ef05ff5d94a125ed8a6 Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Wed, 29 Jun 2005 07:00:56 -0700 Subject: [PATCH] USB: omap_udc tweaks Minor OMAP updates that somehow got dropped from previous patches. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/omap_udc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index c906d675ef4..ff5533e6956 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2908,6 +2908,7 @@ static int __exit omap_udc_remove(struct device *dev) * make host resumes and VBUS detection trigger OMAP wakeup events; that * may involve talking to an external transceiver (e.g. isp1301). */ + static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level) { u32 devstat; @@ -2936,8 +2937,6 @@ static int omap_udc_resume(struct device *dev, u32 level) return 0; DBG("resume + wakeup/SRP\n"); - udc->gadget.dev.parent->power.power_state = PMSG_ON; - udc->gadget.dev.power.power_state = PMSG_ON; omap_pullup(&udc->gadget, 1); /* maybe the host would enumerate us if we nudged it */ -- cgit v1.2.3 From b404a5b02abf84812e5333bda201af464925d7a6 Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Wed, 29 Jun 2005 06:59:14 -0700 Subject: [PATCH] USB: ohci-omap pm updates The recent "pm_message_t" changes removed functionality from the Linux PM framework. This patch removes it from the OMAP OHCI too, removing the distinction between (previous) PM_SUSPEND_MEM and PM_SUSPEND_DISK state transitions ... now the only suspend semantics supportable are what was previously PM_SUSPEND_DISK (4) and is now "PMSG_SUSPEND" (3). From: Todd Poynor Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-omap.c | 53 +++++++++++++------------------------------- 1 file changed, 16 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index b62d6993769..5cde76faab9 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -456,34 +456,22 @@ static int ohci_hcd_omap_drv_remove(struct device *dev) #ifdef CONFIG_PM -/* states match PCI usage, always suspending the root hub except that - * 4 ~= D3cold (ACPI D3) with clock off (resume sees reset). - * - * FIXME: above comment is not right, and code is wrong, too :-(. - */ - -static int ohci_omap_suspend(struct device *dev, pm_message_t state, u32 level) +static int ohci_omap_suspend(struct device *dev, pm_message_t message, u32 level) { struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); int status = -EINVAL; if (level != SUSPEND_POWER_DOWN) return 0; - if (state <= dev->power.power_state) - return 0; - dev_dbg(dev, "suspend to %d\n", state); down(&ohci_to_hcd(ohci)->self.root_hub->serialize); status = ohci_hub_suspend(ohci_to_hcd(ohci)); if (status == 0) { - if (state >= 4) { - omap_ohci_clock_power(0); - ohci_to_hcd(ohci)->self.root_hub->state = - USB_STATE_SUSPENDED; - state = 4; - } + omap_ohci_clock_power(0); + ohci_to_hcd(ohci)->self.root_hub->state = + USB_STATE_SUSPENDED; ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; - dev->power.power_state = state; + dev->power.power_state = PMSG_SUSPEND; } up(&ohci_to_hcd(ohci)->self.root_hub->serialize); return status; @@ -497,29 +485,20 @@ static int ohci_omap_resume(struct device *dev, u32 level) if (level != RESUME_POWER_ON) return 0; - switch (dev->power.power_state) { - case 0: - break; - case 4: - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - omap_ohci_clock_power(1); - /* FALLTHROUGH */ - default: - dev_dbg(dev, "resume from %d\n", dev->power.power_state); + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + omap_ohci_clock_power(1); #ifdef CONFIG_USB_SUSPEND - /* get extra cleanup even if remote wakeup isn't in use */ - status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub); + /* get extra cleanup even if remote wakeup isn't in use */ + status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub); #else - down(&ohci_to_hcd(ohci)->self.root_hub->serialize); - status = ohci_hub_resume(ohci_to_hcd(ohci)); - up(&ohci_to_hcd(ohci)->self.root_hub->serialize); + down(&ohci_to_hcd(ohci)->self.root_hub->serialize); + status = ohci_hub_resume(ohci_to_hcd(ohci)); + up(&ohci_to_hcd(ohci)->self.root_hub->serialize); #endif - if (status == 0) - dev->power.power_state = 0; - break; - } + if (status == 0) + dev->power.power_state = PMSG_ON; return status; } -- cgit v1.2.3 From edfd6aee1f073ae645bd3e60ef96090fc9f0957b Mon Sep 17 00:00:00 2001 From: "david-b@pacbell.net" Date: Wed, 29 Jun 2005 07:03:10 -0700 Subject: [PATCH] USB: fix ohci merge glitch A patch re-organizing some parts of root hub initialization deleted the code initializing the bus-neutral reboot/shutdown notifier for OHCI. This patch just restores that deleted code. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 0375097850e..68decab280d 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -673,8 +673,10 @@ retry: ohci_dump (ohci, 1); - if (ohci_to_hcd(ohci)->self.root_hub == NULL) + if (ohci_to_hcd(ohci)->self.root_hub == NULL) { + register_reboot_notifier (&ohci->reboot_notifier); create_debug_files (ohci); + } return 0; } -- cgit v1.2.3 From a3fdf4ebe016ba756de3ca29a2a6117e9acd721c Mon Sep 17 00:00:00 2001 From: "brian@murphy.dk" Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: export usb_get_intf() and usb_put_intf() Export usb_get_intf and usb_put_intf so that modules can increase usb interface reference counts. Signed-off-by: brian@murphy.dk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/usb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7713a605fce..99c85d2f92d 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1532,6 +1532,9 @@ EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); EXPORT_SYMBOL(usb_disabled); +EXPORT_SYMBOL_GPL(usb_get_intf); +EXPORT_SYMBOL_GPL(usb_put_intf); + EXPORT_SYMBOL(usb_alloc_dev); EXPORT_SYMBOL(usb_put_dev); EXPORT_SYMBOL(usb_get_dev); -- cgit v1.2.3 From 83ef344a7539aa55a787790bc036f0bf3466e191 Mon Sep 17 00:00:00 2001 From: "brian@murphy.dk" Date: Wed, 29 Jun 2005 16:53:29 -0700 Subject: [PATCH] USB: fix usb reference count bug in cdc-acm driver This increases the reference count on the usb cdc acm control interface which is referred to by the tty interface provided by the driver. This allows the deferred removal of the tty after the physical device is disconnected if the tty is held open at the time of disconnection. Signed-off-by: brian@murphy.dk Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 69e859e0f51..adff5a77e31 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -422,6 +422,17 @@ bail_out: return -EIO; } +static void acm_tty_unregister(struct acm *acm) +{ + tty_unregister_device(acm_tty_driver, acm->minor); + usb_put_intf(acm->control); + acm_table[acm->minor] = NULL; + usb_free_urb(acm->ctrlurb); + usb_free_urb(acm->readurb); + usb_free_urb(acm->writeurb); + kfree(acm); +} + static void acm_tty_close(struct tty_struct *tty, struct file *filp) { struct acm *acm = tty->driver_data; @@ -436,14 +447,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) usb_kill_urb(acm->ctrlurb); usb_kill_urb(acm->writeurb); usb_kill_urb(acm->readurb); - } else { - tty_unregister_device(acm_tty_driver, acm->minor); - acm_table[acm->minor] = NULL; - usb_free_urb(acm->ctrlurb); - usb_free_urb(acm->readurb); - usb_free_urb(acm->writeurb); - kfree(acm); - } + } else + acm_tty_unregister(acm); } up(&open_sem); } @@ -905,7 +910,8 @@ skip_normal_probe: usb_driver_claim_interface(&acm_driver, data_interface, acm); - tty_register_device(acm_tty_driver, minor, &intf->dev); + usb_get_intf(control_interface); + tty_register_device(acm_tty_driver, minor, &control_interface->dev); acm_table[minor] = acm; usb_set_intfdata (intf, acm); @@ -954,12 +960,7 @@ static void acm_disconnect(struct usb_interface *intf) usb_driver_release_interface(&acm_driver, acm->data); if (!acm->used) { - tty_unregister_device(acm_tty_driver, acm->minor); - acm_table[acm->minor] = NULL; - usb_free_urb(acm->ctrlurb); - usb_free_urb(acm->readurb); - usb_free_urb(acm->writeurb); - kfree(acm); + acm_tty_unregister(acm); up(&open_sem); return; } -- cgit v1.2.3 From 2824bd250f0be1551747cc3ed5ae07facc285b57 Mon Sep 17 00:00:00 2001 From: Michael Hund Date: Mon, 27 Jun 2005 22:44:22 +0200 Subject: [PATCH] USB: add ldusb driver The following driver provides complete interrupt-in and interrupt-out reports (raw data) to a user program. Until now it uses the HIDIOCGDEVINFO ioctl call, because I don't know better :-(. Perhaps, it will be ok for you - and I will be happy, if you assign 8 minor numbers. I have tested it in several environments and it works very well for me. However, it has a problem with two or more devices at the same hub, if the two or more devices need 1 ms interrupt-in transfers. Unfortunately more than one interrupt-in transfer every ms isn't possible (ehci driver?). This is why the min_interrupt_in_interval and min_interrupt_out_interval are increased to 2 ms (see the corresponding module parameters). This way, I can use two devices simultaneously at the same hub. Signed-off-by: Michael Hund Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + drivers/usb/misc/Kconfig | 10 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/ldusb.c | 794 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 806 insertions(+) create mode 100644 drivers/usb/misc/ldusb.c (limited to 'drivers') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 284f95723ee..df014c2a7c5 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_USB_EMI26) += misc/ obj-$(CONFIG_USB_EMI62) += misc/ obj-$(CONFIG_USB_IDMOUSE) += misc/ obj-$(CONFIG_USB_LCD) += misc/ +obj-$(CONFIG_USB_LD) += misc/ obj-$(CONFIG_USB_LED) += misc/ obj-$(CONFIG_USB_LEGOTOWER) += misc/ obj-$(CONFIG_USB_RIO500) += misc/ diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 3a896954b3a..6649531fa82 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -139,6 +139,16 @@ config USB_IDMOUSE source "drivers/usb/misc/sisusbvga/Kconfig" +config USB_LD + tristate "USB LD driver" + depends on USB && EXPERIMENTAL + help + This driver is for generic USB devices that use interrupt transfers, + like LD Didactic's USB devices. + + To compile this driver as a module, choose M here: the + module will be called ldusb. + config USB_TEST tristate "USB testing driver (DEVELOPMENT)" depends on USB && USB_DEVICEFS && EXPERIMENTAL diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 4a3814cbd48..862e40a8368 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_LCD) += usblcd.o +obj-$(CONFIG_USB_LD) += ldusb.o obj-$(CONFIG_USB_LED) += usbled.o obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o obj-$(CONFIG_USB_PHIDGETKIT) += phidgetkit.o diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c new file mode 100644 index 00000000000..66ec88354b9 --- /dev/null +++ b/drivers/usb/misc/ldusb.c @@ -0,0 +1,794 @@ +/** + * Generic USB driver for report based interrupt in/out devices + * like LD Didactic's USB devices. LD Didactic's USB devices are + * HID devices which do not use HID report definitons (they use + * raw interrupt in and our reports only for communication). + * + * This driver uses a ring buffer for time critical reading of + * interrupt in reports and provides read and write methods for + * raw interrupt reports (similar to the Windows HID driver). + * Devices based on the book USB COMPLETE by Jan Axelson may need + * such a compatibility to the Windows HID driver. + * + * Copyright (C) 2005 Michael Hund + * + * 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. + * + * Derived from Lego USB Tower driver + * Copyright (C) 2003 David Glance + * 2001-2004 Juergen Stuber + * + * V0.1 (mh) Initial version + * V0.11 (mh) Added raw support for HID 1.0 devices (no interrupt out endpoint) + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Define these values to match your devices */ +#define USB_VENDOR_ID_LD 0x0f11 /* USB Vendor ID of LD Didactic GmbH */ +#define USB_DEVICE_ID_CASSY 0x1000 /* USB Product ID for all CASSY-S modules */ +#define USB_DEVICE_ID_POCKETCASSY 0x1010 /* USB Product ID for Pocket-CASSY */ +#define USB_DEVICE_ID_MOBILECASSY 0x1020 /* USB Product ID for Mobile-CASSY */ +#define USB_DEVICE_ID_JWM 0x1080 /* USB Product ID for Joule and Wattmeter */ +#define USB_DEVICE_ID_DMMP 0x1081 /* USB Product ID for Digital Multimeter P (reserved) */ +#define USB_DEVICE_ID_UMIP 0x1090 /* USB Product ID for UMI P */ +#define USB_DEVICE_ID_VIDEOCOM 0x1200 /* USB Product ID for VideoCom */ +#define USB_DEVICE_ID_COM3LAB 0x2000 /* USB Product ID for COM3LAB */ +#define USB_DEVICE_ID_TELEPORT 0x2010 /* USB Product ID for Terminal Adapter */ +#define USB_DEVICE_ID_NETWORKANALYSER 0x2020 /* USB Product ID for Network Analyser */ +#define USB_DEVICE_ID_POWERCONTROL 0x2030 /* USB Product ID for Controlling device for Power Electronics */ + +#define USB_VENDOR_ID_VERNIER 0x08f7 +#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 +#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 +#define USB_DEVICE_ID_VERNIER_SKIP 0x0003 +#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 + + +#ifdef CONFIG_USB_DYNAMIC_MINORS +#define USB_LD_MINOR_BASE 0 +#else +#define USB_LD_MINOR_BASE 176 +#endif + +/* table of devices that work with this driver */ +static struct usb_device_id ld_usb_table [] = { + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_CASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_POCKETCASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_MOBILECASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_JWM) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_DMMP) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_UMIP) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_VIDEOCOM) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_COM3LAB) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_TELEPORT) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_NETWORKANALYSER) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_POWERCONTROL) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, + { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, ld_usb_table); +MODULE_VERSION("V0.11"); +MODULE_AUTHOR("Michael Hund "); +MODULE_DESCRIPTION("LD USB Driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("LD USB Devices"); + +#ifdef CONFIG_USB_DEBUG + static int debug = 1; +#else + static int debug = 0; +#endif + +/* Use our own dbg macro */ +#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) + +/* Module parameters */ +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +/* All interrupt in transfers are collected in a ring buffer to + * avoid racing conditions and get better performance of the driver. + */ +static int ring_buffer_size = 128; +module_param(ring_buffer_size, int, 0); +MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size in reports"); + +/* The write_buffer can contain more than one interrupt out transfer. + */ +static int write_buffer_size = 10; +module_param(write_buffer_size, int, 0); +MODULE_PARM_DESC(write_buffer_size, "Write buffer size in reports"); + +/* As of kernel version 2.6.4 ehci-hcd uses an + * "only one interrupt transfer per frame" shortcut + * to simplify the scheduling of periodic transfers. + * This conflicts with our standard 1ms intervals for in and out URBs. + * We use default intervals of 2ms for in and 2ms for out transfers, + * which should be fast enough. + * Increase the interval to allow more devices that do interrupt transfers, + * or set to 1 to use the standard interval from the endpoint descriptors. + */ +static int min_interrupt_in_interval = 2; +module_param(min_interrupt_in_interval, int, 0); +MODULE_PARM_DESC(min_interrupt_in_interval, "Minimum interrupt in interval in ms"); + +static int min_interrupt_out_interval = 2; +module_param(min_interrupt_out_interval, int, 0); +MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in ms"); + +/* Structure to hold all of our device specific stuff */ +struct ld_usb { + struct semaphore sem; /* locks this structure */ + struct usb_interface* intf; /* save off the usb interface pointer */ + + int open_count; /* number of times this port has been opened */ + + char* ring_buffer; + unsigned int ring_head; + unsigned int ring_tail; + + wait_queue_head_t read_wait; + wait_queue_head_t write_wait; + + char* interrupt_in_buffer; + struct usb_endpoint_descriptor* interrupt_in_endpoint; + struct urb* interrupt_in_urb; + int interrupt_in_interval; + size_t interrupt_in_endpoint_size; + int interrupt_in_running; + int interrupt_in_done; + + char* interrupt_out_buffer; + struct usb_endpoint_descriptor* interrupt_out_endpoint; + struct urb* interrupt_out_urb; + int interrupt_out_interval; + size_t interrupt_out_endpoint_size; + int interrupt_out_busy; +}; + +/* prevent races between open() and disconnect() */ +static DECLARE_MUTEX(disconnect_sem); + +static struct usb_driver ld_usb_driver; + +/** + * ld_usb_abort_transfers + * aborts transfers and frees associated data structures + */ +static void ld_usb_abort_transfers(struct ld_usb *dev) +{ + /* shutdown transfer */ + if (dev->interrupt_in_running) { + dev->interrupt_in_running = 0; + if (dev->intf) + usb_kill_urb(dev->interrupt_in_urb); + } + if (dev->interrupt_out_busy) + if (dev->intf) + usb_kill_urb(dev->interrupt_out_urb); +} + +/** + * ld_usb_delete + */ +static void ld_usb_delete(struct ld_usb *dev) +{ + ld_usb_abort_transfers(dev); + + /* free data structures */ + usb_free_urb(dev->interrupt_in_urb); + usb_free_urb(dev->interrupt_out_urb); + kfree(dev->ring_buffer); + kfree(dev->interrupt_in_buffer); + kfree(dev->interrupt_out_buffer); + kfree(dev); +} + +/** + * ld_usb_interrupt_in_callback + */ +static void ld_usb_interrupt_in_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ld_usb *dev = urb->context; + size_t *actual_buffer; + unsigned int next_ring_head; + int retval; + + if (urb->status) { + if (urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN) { + goto exit; + } else { + dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n", + __FUNCTION__, urb->status); + goto resubmit; /* maybe we can recover */ + } + } + + if (urb->actual_length > 0) { + next_ring_head = (dev->ring_head+1) % ring_buffer_size; + if (next_ring_head != dev->ring_tail) { + actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_head*(sizeof(size_t)+dev->interrupt_in_endpoint_size)); + /* actual_buffer gets urb->actual_length + interrupt_in_buffer */ + *actual_buffer = urb->actual_length; + memcpy(actual_buffer+1, dev->interrupt_in_buffer, urb->actual_length); + dev->ring_head = next_ring_head; + dbg_info(&dev->intf->dev, "%s: received %d bytes\n", + __FUNCTION__, urb->actual_length); + } else + dev_warn(&dev->intf->dev, + "Ring buffer overflow, %d bytes dropped\n", + urb->actual_length); + } + +resubmit: + /* resubmit if we're still running */ + if (dev->interrupt_in_running && dev->intf) { + retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); + if (retval) + dev_err(&dev->intf->dev, + "usb_submit_urb failed (%d)\n", retval); + } + +exit: + dev->interrupt_in_done = 1; + wake_up_interruptible(&dev->read_wait); +} + +/** + * ld_usb_interrupt_out_callback + */ +static void ld_usb_interrupt_out_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ld_usb *dev = urb->context; + + /* sync/async unlink faults aren't errors */ + if (urb->status && !(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) + dbg_info(&dev->intf->dev, + "%s - nonzero write interrupt status received: %d\n", + __FUNCTION__, urb->status); + + dev->interrupt_out_busy = 0; + wake_up_interruptible(&dev->write_wait); +} + +/** + * ld_usb_open + */ +static int ld_usb_open(struct inode *inode, struct file *file) +{ + struct ld_usb *dev; + int subminor; + int retval = 0; + struct usb_interface *interface; + + nonseekable_open(inode, file); + subminor = iminor(inode); + + down(&disconnect_sem); + + interface = usb_find_interface(&ld_usb_driver, subminor); + + if (!interface) { + err("%s - error, can't find device for minor %d\n", + __FUNCTION__, subminor); + retval = -ENODEV; + goto unlock_disconnect_exit; + } + + dev = usb_get_intfdata(interface); + + if (!dev) { + retval = -ENODEV; + goto unlock_disconnect_exit; + } + + /* lock this device */ + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto unlock_disconnect_exit; + } + + /* allow opening only once */ + if (dev->open_count) { + retval = -EBUSY; + goto unlock_exit; + } + dev->open_count = 1; + + /* initialize in direction */ + dev->ring_head = 0; + dev->ring_tail = 0; + usb_fill_int_urb(dev->interrupt_in_urb, + interface_to_usbdev(interface), + usb_rcvintpipe(interface_to_usbdev(interface), + dev->interrupt_in_endpoint->bEndpointAddress), + dev->interrupt_in_buffer, + dev->interrupt_in_endpoint_size, + ld_usb_interrupt_in_callback, + dev, + dev->interrupt_in_interval); + + dev->interrupt_in_running = 1; + dev->interrupt_in_done = 0; + + retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); + if (retval) { + dev_err(&interface->dev, "Couldn't submit interrupt_in_urb %d\n", retval); + dev->interrupt_in_running = 0; + dev->open_count = 0; + goto unlock_exit; + } + + /* save device in the file's private structure */ + file->private_data = dev; + +unlock_exit: + up(&dev->sem); + +unlock_disconnect_exit: + up(&disconnect_sem); + + return retval; +} + +/** + * ld_usb_release + */ +static int ld_usb_release(struct inode *inode, struct file *file) +{ + struct ld_usb *dev; + int retval = 0; + + dev = file->private_data; + + if (dev == NULL) { + retval = -ENODEV; + goto exit; + } + + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto exit; + } + + if (dev->open_count != 1) { + retval = -ENODEV; + goto unlock_exit; + } + if (dev->intf == NULL) { + /* the device was unplugged before the file was released */ + up(&dev->sem); + /* unlock here as ld_usb_delete frees dev */ + ld_usb_delete(dev); + goto exit; + } + + /* wait until write transfer is finished */ + if (dev->interrupt_out_busy) + wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy, 2 * HZ); + ld_usb_abort_transfers(dev); + dev->open_count = 0; + +unlock_exit: + up(&dev->sem); + +exit: + return retval; +} + +/** + * ld_usb_poll + */ +static unsigned int ld_usb_poll(struct file *file, poll_table *wait) +{ + struct ld_usb *dev; + unsigned int mask = 0; + + dev = file->private_data; + + poll_wait(file, &dev->read_wait, wait); + poll_wait(file, &dev->write_wait, wait); + + if (dev->ring_head != dev->ring_tail) + mask |= POLLIN | POLLRDNORM; + if (!dev->interrupt_out_busy) + mask |= POLLOUT | POLLWRNORM; + + return mask; +} + +/** + * ld_usb_read + */ +static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, + loff_t *ppos) +{ + struct ld_usb *dev; + size_t *actual_buffer; + size_t bytes_to_read; + int retval = 0; + + dev = file->private_data; + + /* verify that we actually have some data to read */ + if (count == 0) + goto exit; + + /* lock this object */ + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto exit; + } + + /* verify that the device wasn't unplugged */ + if (dev->intf == NULL) { + retval = -ENODEV; + err("No device or device unplugged %d\n", retval); + goto unlock_exit; + } + + /* wait for data */ + if (dev->ring_head == dev->ring_tail) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto unlock_exit; + } + retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done); + if (retval < 0) + goto unlock_exit; + } + + /* actual_buffer contains actual_length + interrupt_in_buffer */ + actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_tail*(sizeof(size_t)+dev->interrupt_in_endpoint_size)); + bytes_to_read = min(count, *actual_buffer); + if (bytes_to_read < *actual_buffer) + dev_warn(&dev->intf->dev, "Read buffer overflow, %d bytes dropped\n", + *actual_buffer-bytes_to_read); + + /* copy one interrupt_in_buffer from ring_buffer into userspace */ + if (copy_to_user(buffer, actual_buffer+1, bytes_to_read)) { + retval = -EFAULT; + goto unlock_exit; + } + dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size; + + retval = bytes_to_read; + +unlock_exit: + /* unlock the device */ + up(&dev->sem); + +exit: + return retval; +} + +/** + * ld_usb_write + */ +static ssize_t ld_usb_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct ld_usb *dev; + size_t bytes_to_write; + int retval = 0; + + dev = file->private_data; + + /* verify that we actually have some data to write */ + if (count == 0) + goto exit; + + /* lock this object */ + if (down_interruptible(&dev->sem)) { + retval = -ERESTARTSYS; + goto exit; + } + + /* verify that the device wasn't unplugged */ + if (dev->intf == NULL) { + retval = -ENODEV; + err("No device or device unplugged %d\n", retval); + goto unlock_exit; + } + + /* wait until previous transfer is finished */ + if (dev->interrupt_out_busy) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto unlock_exit; + } + retval = wait_event_interruptible(dev->write_wait, !dev->interrupt_out_busy); + if (retval < 0) { + goto unlock_exit; + } + } + + /* write the data into interrupt_out_buffer from userspace */ + bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size); + if (bytes_to_write < count) + dev_warn(&dev->intf->dev, "Write buffer overflow, %d bytes dropped\n",count-bytes_to_write); + dbg_info(&dev->intf->dev, "%s: count = %d, bytes_to_write = %d\n", __FUNCTION__, count, bytes_to_write); + + if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) { + retval = -EFAULT; + goto unlock_exit; + } + + if (dev->interrupt_out_endpoint == NULL) { + /* try HID_REQ_SET_REPORT=9 on control_endpoint instead of interrupt_out_endpoint */ + retval = usb_control_msg(interface_to_usbdev(dev->intf), + usb_sndctrlpipe(interface_to_usbdev(dev->intf), 0), + 9, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + 1 << 8, 0, + dev->interrupt_out_buffer, + bytes_to_write, + USB_CTRL_SET_TIMEOUT * HZ); + if (retval < 0) + err("Couldn't submit HID_REQ_SET_REPORT %d\n", retval); + goto unlock_exit; + } + + /* send off the urb */ + usb_fill_int_urb(dev->interrupt_out_urb, + interface_to_usbdev(dev->intf), + usb_sndintpipe(interface_to_usbdev(dev->intf), + dev->interrupt_out_endpoint->bEndpointAddress), + dev->interrupt_out_buffer, + bytes_to_write, + ld_usb_interrupt_out_callback, + dev, + dev->interrupt_out_interval); + + dev->interrupt_out_busy = 1; + wmb(); + + retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); + if (retval) { + dev->interrupt_out_busy = 0; + err("Couldn't submit interrupt_out_urb %d\n", retval); + goto unlock_exit; + } + retval = bytes_to_write; + +unlock_exit: + /* unlock the device */ + up(&dev->sem); + +exit: + return retval; +} + +/* file operations needed when we register this driver */ +static struct file_operations ld_usb_fops = { + .owner = THIS_MODULE, + .read = ld_usb_read, + .write = ld_usb_write, + .open = ld_usb_open, + .release = ld_usb_release, + .poll = ld_usb_poll, +}; + +/* + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with devfs and the driver core + */ +static struct usb_class_driver ld_usb_class = { + .name = "ldusb%d", + .fops = &ld_usb_fops, + .minor_base = USB_LD_MINOR_BASE, +}; + +/** + * ld_usb_probe + * + * Called by the usb core when a new device is connected that it thinks + * this driver might be interested in. + */ +static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct ld_usb *dev = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + char *buffer; + int i; + int retval = -ENOMEM; + + /* allocate memory for our device state and intialize it */ + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + dev_err(&intf->dev, "Out of memory\n"); + goto exit; + } + memset(dev, 0x00, sizeof(*dev)); + init_MUTEX(&dev->sem); + dev->intf = intf; + init_waitqueue_head(&dev->read_wait); + init_waitqueue_head(&dev->write_wait); + + /* workaround for early firmware versions on fast computers */ + if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VENDOR_ID_LD) && + ((le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_CASSY) || + (le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_COM3LAB)) && + (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x103)) { + buffer = kmalloc(256, GFP_KERNEL); + /* usb_string makes SETUP+STALL to leave always ControlReadLoop */ + usb_string(udev, 255, buffer, 256); + kfree(buffer); + } + + iface_desc = intf->cur_altsetting; + + /* set up the endpoint information */ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + dev->interrupt_in_endpoint = endpoint; + } + + if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && + ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + dev->interrupt_out_endpoint = endpoint; + } + } + if (dev->interrupt_in_endpoint == NULL) { + dev_err(&intf->dev, "Interrupt in endpoint not found\n"); + goto error; + } + if (dev->interrupt_out_endpoint == NULL) + dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n"); + + dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize); + dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL); + if (!dev->ring_buffer) { + dev_err(&intf->dev, "Couldn't allocate ring_buffer\n"); + goto error; + } + dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); + if (!dev->interrupt_in_buffer) { + dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n"); + goto error; + } + dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->interrupt_in_urb) { + dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n"); + goto error; + } + dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) : + udev->descriptor.bMaxPacketSize0; + dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL); + if (!dev->interrupt_out_buffer) { + dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n"); + goto error; + } + dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->interrupt_out_urb) { + dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n"); + goto error; + } + dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; + if (dev->interrupt_out_endpoint) + dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; + + /* we can register the device now, as it is ready */ + usb_set_intfdata(intf, dev); + + retval = usb_register_dev(intf, &ld_usb_class); + if (retval) { + /* something prevented us from registering this driver */ + dev_err(&intf->dev, "Not able to get a minor for this device.\n"); + usb_set_intfdata(intf, NULL); + goto error; + } + + /* let the user know what node this device is now attached to */ + dev_info(&intf->dev, "LD USB Device #%d now attached to major %d minor %d\n", + (intf->minor - USB_LD_MINOR_BASE), USB_MAJOR, intf->minor); + +exit: + return retval; + +error: + ld_usb_delete(dev); + + return retval; +} + +/** + * ld_usb_disconnect + * + * Called by the usb core when the device is removed from the system. + */ +static void ld_usb_disconnect(struct usb_interface *intf) +{ + struct ld_usb *dev; + int minor; + + down(&disconnect_sem); + + dev = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + + down(&dev->sem); + + minor = intf->minor; + + /* give back our minor */ + usb_deregister_dev(intf, &ld_usb_class); + + /* if the device is not opened, then we clean up right now */ + if (!dev->open_count) { + up(&dev->sem); + ld_usb_delete(dev); + } else { + dev->intf = NULL; + up(&dev->sem); + } + + up(&disconnect_sem); + + dev_info(&intf->dev, "LD USB Device #%d now disconnected\n", + (minor - USB_LD_MINOR_BASE)); +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver ld_usb_driver = { + .owner = THIS_MODULE, + .name = "ldusb", + .probe = ld_usb_probe, + .disconnect = ld_usb_disconnect, + .id_table = ld_usb_table, +}; + +/** + * ld_usb_init + */ +static int __init ld_usb_init(void) +{ + int retval; + + /* register this driver with the USB subsystem */ + retval = usb_register(&ld_usb_driver); + if (retval) + err("usb_register failed for the "__FILE__" driver. Error number %d\n", retval); + + return retval; +} + +/** + * ld_usb_exit + */ +static void __exit ld_usb_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&ld_usb_driver); +} + +module_init(ld_usb_init); +module_exit(ld_usb_exit); + -- cgit v1.2.3 From ab611487d8ada506e511d2b8f22fb8e7be9939b9 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 12 Jul 2005 12:08:43 -0700 Subject: [NET]: __be'ify *_type_trans() tr_type_trans(), hippi_type_trans() left as-is. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- drivers/net/myri_sbus.c | 2 +- drivers/net/plip.c | 2 +- drivers/net/wan/farsync.c | 3 +-- drivers/net/wan/hdlc_cisco.c | 3 +-- drivers/net/wan/hdlc_ppp.c | 3 +-- drivers/net/wan/hdlc_raw.c | 3 +-- drivers/s390/net/qeth_main.c | 2 +- 7 files changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index aad5494c83c..f0996ce5c26 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -369,7 +369,7 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev) * assume 802.3 if the type field is short enough to be a length. * This is normal practice and works for any 'now in use' protocol. */ -static unsigned short myri_type_trans(struct sk_buff *skb, struct net_device *dev) +static __be16 myri_type_trans(struct sk_buff *skb, struct net_device *dev) { struct ethhdr *eth; unsigned char *rawp; diff --git a/drivers/net/plip.c b/drivers/net/plip.c index f4b62405d2e..21537ee3a6a 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -540,7 +540,7 @@ plip_receive(unsigned short nibble_timeout, struct net_device *dev, * in far too many old systems not all even running Linux. */ -static unsigned short plip_type_trans(struct sk_buff *skb, struct net_device *dev) +static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev) { struct ethhdr *eth; unsigned char *rawp; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 7217d44e885..2c83cca34b8 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -861,8 +861,7 @@ fst_tx_dma_complete(struct fst_card_info *card, struct fst_port_info *port, /* * Mark it for our own raw sockets interface */ -static unsigned short farsync_type_trans(struct sk_buff *skb, - struct net_device *dev) +static __be16 farsync_type_trans(struct sk_buff *skb, struct net_device *dev) { skb->dev = dev; skb->mac.raw = skb->data; diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 87496843681..48c03c11cd9 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -91,8 +91,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, -static unsigned short cisco_type_trans(struct sk_buff *skb, - struct net_device *dev) +static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev) { hdlc_header *data = (hdlc_header*)skb->data; diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 7cd6195a2e4..b81263eaede 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -66,8 +66,7 @@ static void ppp_close(struct net_device *dev) -static unsigned short ppp_type_trans(struct sk_buff *skb, - struct net_device *dev) +static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev) { return __constant_htons(ETH_P_WAN_PPP); } diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c index c41fb70b692..9456d31cb1c 100644 --- a/drivers/net/wan/hdlc_raw.c +++ b/drivers/net/wan/hdlc_raw.c @@ -24,8 +24,7 @@ #include -static unsigned short raw_type_trans(struct sk_buff *skb, - struct net_device *dev) +static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev) { return __constant_htons(ETH_P_IP); } diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 3cb88c77003..8f4d2999af8 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -2210,7 +2210,7 @@ no_mem: return NULL; } -static inline unsigned short +static inline __be16 qeth_type_trans(struct sk_buff *skb, struct net_device *dev) { struct qeth_card *card; -- cgit v1.2.3 From 4645df1035b34be2d431d6a10b08e1c06bcd3361 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 12 Jul 2005 13:58:08 -0700 Subject: [PATCH] aacraid: swapped kmalloc args. Signed-off-by: Dave Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/aacraid/commctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 1fef92d55de..390cd67c57c 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -469,7 +469,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) goto cleanup; } - user_srbcmd = kmalloc(GFP_KERNEL, fibsize); + user_srbcmd = kmalloc(fibsize, GFP_KERNEL); if (!user_srbcmd) { dprintk((KERN_DEBUG"aacraid: Could not make a copy of the srb\n")); rcode = -ENOMEM; -- cgit v1.2.3 From 70d1d47c47c4643af357cb44d0d891c1b765f2ab Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Tue, 12 Jul 2005 13:58:09 -0700 Subject: [PATCH] quiet ide-cd warning This shuts up a potential uninitialized variable warning. Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/ide/ide-cd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 0a31cfda08a..74af7e07486 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -431,7 +431,7 @@ void cdrom_analyze_sense_data(ide_drive_t *drive, #if VERBOSE_IDE_CD_ERRORS { int i; - const char *s; + const char *s = "bad sense key!"; char buf[80]; printk ("ATAPI device %s:\n", drive->name); @@ -446,8 +446,6 @@ void cdrom_analyze_sense_data(ide_drive_t *drive, if (sense->sense_key < ARY_LEN(sense_key_texts)) s = sense_key_texts[sense->sense_key]; - else - s = "bad sense key!"; printk("%s -- (Sense key=0x%02x)\n", s, sense->sense_key); -- cgit v1.2.3 From 862104e56329babf0b9571281e9516fe6259dd17 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 12 Jul 2005 13:58:15 -0700 Subject: [PATCH] yenta: fix parent resource determination If the CardBus windows were pre-configured and the CardBus bridge is behind a transparent PCI-PCI bridge, pci_find_parent_resource() might return a different resource than the real parent if it is called before the window is determined. Therefore, move that call around. Also fix return of value in void function. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/yenta_socket.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 0e7aa817669..5e0a9980d2f 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -551,7 +551,7 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; /* Already allocated? */ if (res->parent) - return 0; + return; /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */ mask = ~0xfff; @@ -562,25 +562,23 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ bus = socket->dev->subordinate; res->name = bus->name; res->flags = type; - res->start = 0; - res->end = 0; - root = pci_find_parent_resource(socket->dev, res); - - if (!root) - return; start = config_readl(socket, offset) & mask; end = config_readl(socket, offset+4) | ~mask; if (start && end > start && !override_bios) { res->start = start; res->end = end; - if (request_resource(root, res) == 0) + root = pci_find_parent_resource(socket->dev, res); + if (root && (request_resource(root, res) == 0)) return; - printk(KERN_INFO "yenta %s: Preassigned resource %d busy, reconfiguring...\n", + printk(KERN_INFO "yenta %s: Preassigned resource %d busy or not available, reconfiguring...\n", pci_name(socket->dev), nr); - res->start = res->end = 0; } + res->start = 0; + res->end = 0; + root = pci_find_parent_resource(socket->dev, res); + if (type & IORESOURCE_IO) { align = 1024; size = BRIDGE_IO_MAX; @@ -629,7 +627,7 @@ static void yenta_allocate_resources(struct yenta_socket *socket) yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH); yenta_allocate_res(socket, 1, IORESOURCE_MEM); yenta_allocate_res(socket, 2, IORESOURCE_IO); - yenta_allocate_res(socket, 3, IORESOURCE_IO); /* PCI isn't clever enough to use this one yet */ + yenta_allocate_res(socket, 3, IORESOURCE_IO); } -- cgit v1.2.3 From 278798357d4a8658067dc9ac399d8ffba8389f03 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 12 Jul 2005 13:58:16 -0700 Subject: [PATCH] yenta: same resources in same structs drivers/pci/setup-bus.c enumerates the CardBus windows (bus->resources[]) Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/yenta_socket.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 5e0a9980d2f..d3807e22fe0 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -539,13 +539,12 @@ static int yenta_sock_suspend(struct pcmcia_socket *sock) #define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO #endif -static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type) +static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end) { struct pci_bus *bus; struct resource *root, *res; u32 start, end; u32 align, size, min; - unsigned offset; unsigned mask; res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; @@ -558,13 +557,12 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ if (type & IORESOURCE_IO) mask = ~3; - offset = 0x1c + 8*nr; bus = socket->dev->subordinate; res->name = bus->name; res->flags = type; - start = config_readl(socket, offset) & mask; - end = config_readl(socket, offset+4) | ~mask; + start = config_readl(socket, addr_start) & mask; + end = config_readl(socket, addr_end) | ~mask; if (start && end > start && !override_bios) { res->start = start; res->end = end; @@ -607,8 +605,8 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ do { if (allocate_resource(root, res, size, start, end, align, NULL, NULL)==0) { - config_writel(socket, offset, res->start); - config_writel(socket, offset+4, res->end); + config_writel(socket, addr_start, res->start); + config_writel(socket, addr_end, res->end); return; } size = size/2; @@ -624,10 +622,14 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ */ static void yenta_allocate_resources(struct yenta_socket *socket) { - yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH); - yenta_allocate_res(socket, 1, IORESOURCE_MEM); - yenta_allocate_res(socket, 2, IORESOURCE_IO); - yenta_allocate_res(socket, 3, IORESOURCE_IO); + yenta_allocate_res(socket, 0, IORESOURCE_IO, + PCI_CB_IO_BASE_0, PCI_CB_IO_LIMIT_0); + yenta_allocate_res(socket, 1, IORESOURCE_IO, + PCI_CB_IO_BASE_1, PCI_CB_IO_LIMIT_1); + yenta_allocate_res(socket, 2, IORESOURCE_MEM|IORESOURCE_PREFETCH, + PCI_CB_MEMORY_BASE_0, PCI_CB_MEMORY_LIMIT_0); + yenta_allocate_res(socket, 3, IORESOURCE_MEM, + PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1); } -- cgit v1.2.3 From eb0a90b4970d667e9ae9df538710f12b8e78e442 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 12 Jul 2005 13:58:17 -0700 Subject: [PATCH] yenta: allocate resource fixes The current CardBus window allocation code in yenta_socket is unable to handle the transparent PCI-bridge handling update in 2.6.13. We need to check _all_ resources of a given type to find the best one suitable for CardBus windows, not just the first one. Signed-off-by: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pcmcia/yenta_socket.c | 126 +++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index d3807e22fe0..f9d2367b6bd 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -527,24 +527,87 @@ static int yenta_sock_suspend(struct pcmcia_socket *sock) * Use an adaptive allocation for the memory resource, * sometimes the memory behind pci bridges is limited: * 1/8 of the size of the io window of the parent. - * max 4 MB, min 16 kB. + * max 4 MB, min 16 kB. We try very hard to not get below + * the "ACC" values, though. */ #define BRIDGE_MEM_MAX 4*1024*1024 +#define BRIDGE_MEM_ACC 128*1024 #define BRIDGE_MEM_MIN 16*1024 -#define BRIDGE_IO_MAX 256 +#define BRIDGE_IO_MAX 512 +#define BRIDGE_IO_ACC 256 #define BRIDGE_IO_MIN 32 #ifndef PCIBIOS_MIN_CARDBUS_IO #define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO #endif +static int yenta_search_one_res(struct resource *root, struct resource *res, + u32 min) +{ + u32 align, size, start, end; + + if (res->flags & IORESOURCE_IO) { + align = 1024; + size = BRIDGE_IO_MAX; + start = PCIBIOS_MIN_CARDBUS_IO; + end = ~0U; + } else { + unsigned long avail = root->end - root->start; + int i; + size = BRIDGE_MEM_MAX; + if (size > avail/8) { + size=(avail+1)/8; + /* round size down to next power of 2 */ + i = 0; + while ((size /= 2) != 0) + i++; + size = 1 << i; + } + if (size < min) + size = min; + align = size; + start = PCIBIOS_MIN_MEM; + end = ~0U; + } + + do { + if (allocate_resource(root, res, size, start, end, align, + NULL, NULL)==0) { + return 1; + } + size = size/2; + align = size; + } while (size >= min); + + return 0; +} + + +static int yenta_search_res(struct yenta_socket *socket, struct resource *res, + u32 min) +{ + int i; + for (i=0; idev->bus->resource[i]; + if (!root) + continue; + + if ((res->flags ^ root->flags) & + (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH)) + continue; /* Wrong type */ + + if (yenta_search_one_res(root, res, min)) + return 1; + } + return 0; +} + static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end) { struct pci_bus *bus; struct resource *root, *res; u32 start, end; - u32 align, size, min; unsigned mask; res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; @@ -573,48 +636,35 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ pci_name(socket->dev), nr); } - res->start = 0; - res->end = 0; - root = pci_find_parent_resource(socket->dev, res); - if (type & IORESOURCE_IO) { - align = 1024; - size = BRIDGE_IO_MAX; - min = BRIDGE_IO_MIN; - start = PCIBIOS_MIN_CARDBUS_IO; - end = ~0U; + if ((yenta_search_res(socket, res, BRIDGE_IO_MAX)) || + (yenta_search_res(socket, res, BRIDGE_IO_ACC)) || + (yenta_search_res(socket, res, BRIDGE_IO_MIN))) { + config_writel(socket, addr_start, res->start); + config_writel(socket, addr_end, res->end); + } } else { - unsigned long avail = root->end - root->start; - int i; - size = BRIDGE_MEM_MAX; - if (size > avail/8) { - size=(avail+1)/8; - /* round size down to next power of 2 */ - i = 0; - while ((size /= 2) != 0) - i++; - size = 1 << i; + if (type & IORESOURCE_PREFETCH) { + if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || + (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || + (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { + config_writel(socket, addr_start, res->start); + config_writel(socket, addr_end, res->end); + } + /* Approximating prefetchable by non-prefetchable */ + res->flags = IORESOURCE_MEM; } - if (size < BRIDGE_MEM_MIN) - size = BRIDGE_MEM_MIN; - min = BRIDGE_MEM_MIN; - align = size; - start = PCIBIOS_MIN_MEM; - end = ~0U; - } - - do { - if (allocate_resource(root, res, size, start, end, align, NULL, NULL)==0) { + if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || + (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || + (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { config_writel(socket, addr_start, res->start); config_writel(socket, addr_end, res->end); - return; } - size = size/2; - align = size; - } while (size >= min); + } + printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n", - pci_name(socket->dev), type); - res->start = res->end = 0; + pci_name(socket->dev), type); + res->start = res->end = res->flags = 0; } /* -- cgit v1.2.3 From 01e77d31d11a767c9da665f46e075756aef4fc4f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 12 Jul 2005 13:58:32 -0700 Subject: [PATCH] IBM_ASM Kconfig corrections This patch contains the following fixes: - IBM_ASM must depend on PCI - remove useless "default n" - correct the URL to further information Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/Kconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 4cecdafeb87..7fc692a8f5b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -6,8 +6,7 @@ menu "Misc devices" config IBM_ASM tristate "Device driver for IBM RSA service processor" - depends on X86 && EXPERIMENTAL - default n + depends on X86 && PCI && EXPERIMENTAL ---help--- This option enables device driver support for in-band access to the IBM RSA (Condor) service processor in eServer xSeries systems. @@ -22,7 +21,7 @@ config IBM_ASM WARNING: This software may not be supported or function correctly on your IBM server. Please consult the IBM ServerProven - website for + website for information on the specific driver level and support statement for your IBM server. -- cgit v1.2.3 From 6e498c1080ae794a8dc788152002fb39994ae78b Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Tue, 12 Jul 2005 13:58:32 -0700 Subject: [PATCH] TB0219: add PCI IRQ initialization This patch adds PCI IRQ initialization to TB0219 driver. Signed-off-by: Yoichi Yuasa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tb0219.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index 5413f290885..eb7058cbf01 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c @@ -24,6 +24,8 @@ #include #include +#include +#include MODULE_AUTHOR("Yoichi Yuasa "); MODULE_DESCRIPTION("TANBAC TB0219 base board driver"); @@ -266,6 +268,21 @@ static void tb0219_restart(char *command) tb0219_write(TB0219_RESET, 0); } +static void tb0219_pci_irq_init(void) +{ + /* PCI Slot 1 */ + vr41xx_set_irq_trigger(TB0219_PCI_SLOT1_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH); + vr41xx_set_irq_level(TB0219_PCI_SLOT1_PIN, IRQ_LEVEL_LOW); + + /* PCI Slot 2 */ + vr41xx_set_irq_trigger(TB0219_PCI_SLOT2_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH); + vr41xx_set_irq_level(TB0219_PCI_SLOT2_PIN, IRQ_LEVEL_LOW); + + /* PCI Slot 3 */ + vr41xx_set_irq_trigger(TB0219_PCI_SLOT3_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH); + vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW); +} + static int tb0219_probe(struct device *dev) { int retval; @@ -292,6 +309,8 @@ static int tb0219_probe(struct device *dev) old_machine_restart = _machine_restart; _machine_restart = tb0219_restart; + tb0219_pci_irq_init(); + if (major == 0) { major = retval; printk(KERN_INFO "TB0219: major number %d\n", major); -- cgit v1.2.3 From 58ba006be9b5a8f14f32c530d19fcd4e633aadf8 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 12 Jul 2005 13:58:37 -0700 Subject: [PATCH] dvb: LGDT3302 QAM256 initialization fix - Initialize all non mutually exclusive variables without regard to the mode selected. - Do a software reset each time the parameters are set, regardless of whether anything changes. This may allow an application to recover from a hung condition. - Improved error reporting. - Removed $Id:$ Signed-off-by: Mac Michaels Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/frontends/lgdt3302.c | 64 ++++++++++++++++------------------ 1 file changed, 31 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c index 09c914256e4..2eea03d218c 100644 --- a/drivers/media/dvb/frontends/lgdt3302.c +++ b/drivers/media/dvb/frontends/lgdt3302.c @@ -1,6 +1,4 @@ /* - * $Id: lgdt3302.c,v 1.5 2005/07/07 03:47:15 mkrufky Exp $ - * * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM * * Copyright (C) 2005 Wilson Michaels @@ -83,7 +81,10 @@ static int i2c_writebytes (struct lgdt3302_state* state, if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); - return -EREMOTEIO; + if (err < 0) + return err; + else + return -EREMOTEIO; } } else { u8 tmp[] = { buf[0], buf[1] }; @@ -96,7 +97,10 @@ static int i2c_writebytes (struct lgdt3302_state* state, tmp[1] = buf[i]; if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); - return -EREMOTEIO; + if (err < 0) + return err; + else + return -EREMOTEIO; } tmp[0]++; } @@ -218,6 +222,8 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, /* Change only if we are actually changing the modulation */ if (state->current_modulation != param->u.vsb.modulation) { + int value; + switch(param->u.vsb.modulation) { case VSB_8: dprintk("%s: VSB_8 MODE\n", __FUNCTION__); @@ -266,36 +272,29 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, i2c_writebytes(state, state->config->demod_address, demux_ctrl_cfg, sizeof(demux_ctrl_cfg)); - if (param->u.vsb.modulation == VSB_8) { - /* Initialization for VSB modes only */ - /* Change the value of NCOCTFV[25:0]of carrier - recovery center frequency register for VSB */ - i2c_writebytes(state, state->config->demod_address, + /* Change the value of NCOCTFV[25:0] of carrier + recovery center frequency register */ + i2c_writebytes(state, state->config->demod_address, vsb_freq_cfg, sizeof(vsb_freq_cfg)); - } else { - /* Initialization for QAM modes only */ - /* Set the value of 'INLVTHD' register 0x2a/0x2c - to value from 'IFACC' register 0x39/0x3b -1 */ - int value; - i2c_selectreadbytes(state, AGC_RFIF_ACC0, - &agc_delay_cfg[1], 3); - value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3]; - value = value -1; - dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value); - agc_delay_cfg[1] = (value >> 8) & 0x0f; - agc_delay_cfg[2] = 0x00; - agc_delay_cfg[3] = value & 0xff; - i2c_writebytes(state, state->config->demod_address, - agc_delay_cfg, sizeof(agc_delay_cfg)); - - /* Change the value of IAGCBW[15:8] - of inner AGC loop filter bandwith */ - i2c_writebytes(state, state->config->demod_address, - agc_loop_cfg, sizeof(agc_loop_cfg)); - } + /* Set the value of 'INLVTHD' register 0x2a/0x2c + to value from 'IFACC' register 0x39/0x3b -1 */ + i2c_selectreadbytes(state, AGC_RFIF_ACC0, + &agc_delay_cfg[1], 3); + value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3]; + value = value -1; + dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value); + agc_delay_cfg[1] = (value >> 8) & 0x0f; + agc_delay_cfg[2] = 0x00; + agc_delay_cfg[3] = value & 0xff; + i2c_writebytes(state, state->config->demod_address, + agc_delay_cfg, sizeof(agc_delay_cfg)); + + /* Change the value of IAGCBW[15:8] + of inner AGC loop filter bandwith */ + i2c_writebytes(state, state->config->demod_address, + agc_loop_cfg, sizeof(agc_loop_cfg)); state->config->set_ts_params(fe, 0); - lgdt3302_SwReset(state); state->current_modulation = param->u.vsb.modulation; } @@ -311,11 +310,10 @@ static int lgdt3302_set_parameters(struct dvb_frontend* fe, i2c_readbytes(state, state->config->pll_address, buf, 1); dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]); - lgdt3302_SwReset(state); - /* Update current frequency */ state->current_frequency = param->frequency; } + lgdt3302_SwReset(state); return 0; } -- cgit v1.2.3 From 8df3d46077e63ab87f954eb6e827689cdfe97155 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Tue, 12 Jul 2005 13:58:38 -0700 Subject: [PATCH] dvb: usb: fix some typos corrected some typos. Signed-off-by: Patrick Boettcher Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/dvb-usb/dvb-usb-dvb.c | 2 +- drivers/media/dvb/dvb-usb/dvb-usb-init.c | 6 +++--- drivers/media/dvb/dvb-usb/vp7045.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index bdd72f77970..3491ff40885 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -175,7 +175,7 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) int dvb_usb_fe_init(struct dvb_usb_device* d) { if (d->props.frontend_attach == NULL) { - err("strange '%s' don't want to attach a frontend.",d->desc->name); + err("strange '%s' doesn't want to attach a frontend.",d->desc->name); 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 c3b3ae4f3ec..65f0c095abc 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -51,17 +51,17 @@ static int dvb_usb_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 && !(d->props.caps & DVB_USB_HAS_PID_FILTER)) { - err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a HW 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 && d->props.caps & DVB_USB_HAS_PID_FILTER) || (d->props.caps & DVB_USB_NEED_PID_FILTERING)) { - info("will use the device's hw PID filter."); + info("will use the device's hardware PID filter (table count: %d).",d->props.pid_filter_count); d->pid_filtering = 1; d->max_feed_count = d->props.pid_filter_count; } else { - info("will pass the complete MPEG2 transport stream to the demuxer."); + info("will pass the complete MPEG2 transport stream to the software demuxer."); d->pid_filtering = 0; d->max_feed_count = 255; } diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 5adc5d69ec8..9ac95f54f9f 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -128,7 +128,7 @@ static struct dvb_usb_rc_key vp7045_rc_keys[] = { { 0x00, 0x0f, KEY_TEXT } /* Teletext */ }; -static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state) +static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key; int i; @@ -144,7 +144,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state) for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++) if (vp7045_rc_keys[i].data == key) { *state = REMOTE_KEY_PRESSED; - *key_buf = vp7045_rc_keys[i].event; + *event = vp7045_rc_keys[i].event; break; } return 0; -- cgit v1.2.3 From 27b05fd22f8a1f9afd0377817b1811cfc95f8b7b Mon Sep 17 00:00:00 2001 From: Julian Scheel Date: Tue, 12 Jul 2005 13:58:39 -0700 Subject: [PATCH] dvb: fix kobject names (no slashes) The / in the driver name (budget dvb /w video in) is not a valid character for device names - removed it, now it works! Same for ttusb-budget. Signed-off-by: Patrick Boettcher Signed-off-by: Julian Scheel Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/ttpci/budget-av.c | 2 +- drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index b65f4b0a481..9746d2bb916 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -1022,7 +1022,7 @@ static struct pci_device_id pci_tbl[] = { MODULE_DEVICE_TABLE(pci, pci_tbl); static struct saa7146_extension budget_extension = { - .name = "budget dvb /w video in\0", + .name = "budget_av", .pci_tbl = pci_tbl, .module = THIS_MODULE, diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 2c17a5f5834..aa43b5fcb8e 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1626,7 +1626,7 @@ static struct usb_device_id ttusb_table[] = { MODULE_DEVICE_TABLE(usb, ttusb_table); static struct usb_driver ttusb_driver = { - .name = "Technotrend/Hauppauge USB-Nova", + .name = "ttusb", .probe = ttusb_probe, .disconnect = ttusb_disconnect, .id_table = ttusb_table, -- cgit v1.2.3 From a6dfa37888298e8369f197883ae5f058fbd98a70 Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Tue, 12 Jul 2005 13:58:40 -0700 Subject: [PATCH] dvb: dst: printk -> dprintk - stop log spamming when running femon (printk -> dprintk) Signed-off-by: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 9bd12832e3d..07a0b0a968a 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -928,7 +928,7 @@ static int dst_get_signal(struct dst_state* state) { int retval; u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; - printk("%s: Getting Signal strength and other parameters !!!!!!!!\n", __FUNCTION__); + dprintk("%s: Getting Signal strength and other parameters\n", __FUNCTION__); if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { state->decode_lock = state->decode_strength = state->decode_snr = 0; return 0; -- cgit v1.2.3 From de9c634270df3e27675a3c0e95545d2b3f754e3f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:41 -0700 Subject: [PATCH] v4l: BTTV input Changes to comply with CodingStyle: // comments converted to /* */ Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/ir-kbd-i2c.c | 51 +++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 92664f75d32..9fc5055e001 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -1,5 +1,5 @@ /* - * $Id: ir-kbd-i2c.c,v 1.10 2004/12/09 12:51:35 kraxel Exp $ + * $Id: ir-kbd-i2c.c,v 1.11 2005/07/07 16:42:11 mchehab Exp $ * * keyboard input driver for i2c IR remote controls * @@ -66,26 +66,26 @@ static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = { [ 29 ] = KEY_PAGEDOWN, [ 19 ] = KEY_SOUND, - [ 24 ] = KEY_KPPLUSMINUS, // CH +/- - [ 22 ] = KEY_SUBTITLE, // CC - [ 13 ] = KEY_TEXT, // TTX - [ 11 ] = KEY_TV, // AIR/CBL - [ 17 ] = KEY_PC, // PC/TV - [ 23 ] = KEY_OK, // CH RTN - [ 25 ] = KEY_MODE, // FUNC - [ 12 ] = KEY_SEARCH, // AUTOSCAN + [ 24 ] = KEY_KPPLUSMINUS, /* CH +/- */ + [ 22 ] = KEY_SUBTITLE, /* CC */ + [ 13 ] = KEY_TEXT, /* TTX */ + [ 11 ] = KEY_TV, /* AIR/CBL */ + [ 17 ] = KEY_PC, /* PC/TV */ + [ 23 ] = KEY_OK, /* CH RTN */ + [ 25 ] = KEY_MODE, /* FUNC */ + [ 12 ] = KEY_SEARCH, /* AUTOSCAN */ /* Not sure what to do with these ones! */ - [ 15 ] = KEY_SELECT, // SOURCE - [ 10 ] = KEY_KPPLUS, // +100 - [ 20 ] = KEY_KPEQUAL, // SYNC - [ 28 ] = KEY_MEDIA, // PC/TV + [ 15 ] = KEY_SELECT, /* SOURCE */ + [ 10 ] = KEY_KPPLUS, /* +100 */ + [ 20 ] = KEY_KPEQUAL, /* SYNC */ + [ 28 ] = KEY_MEDIA, /* PC/TV */ }; static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = { [ 0x3 ] = KEY_POWER, [ 0x6f ] = KEY_MUTE, - [ 0x10 ] = KEY_BACKSPACE, // Recall + [ 0x10 ] = KEY_BACKSPACE, /* Recall */ [ 0x11 ] = KEY_KP0, [ 0x4 ] = KEY_KP1, @@ -97,7 +97,7 @@ static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = { [ 0xc ] = KEY_KP7, [ 0xd ] = KEY_KP8, [ 0xe ] = KEY_KP9, - [ 0x12 ] = KEY_KPDOT, // 100+ + [ 0x12 ] = KEY_KPDOT, /* 100+ */ [ 0x7 ] = KEY_VOLUMEUP, [ 0xb ] = KEY_VOLUMEDOWN, @@ -109,25 +109,16 @@ static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = { [ 0x13 ] = KEY_CHANNELDOWN, [ 0x48 ] = KEY_ZOOM, - [ 0x1b ] = KEY_VIDEO, // Video source -#if 0 - [ 0x1f ] = KEY_S, // Snapshot -#endif - [ 0x49 ] = KEY_LANGUAGE, // MTS Select - [ 0x19 ] = KEY_SEARCH, // Auto Scan + [ 0x1b ] = KEY_VIDEO, /* Video source */ + [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */ + [ 0x19 ] = KEY_SEARCH, /* Auto Scan */ [ 0x4b ] = KEY_RECORD, [ 0x46 ] = KEY_PLAY, - [ 0x45 ] = KEY_PAUSE, // Pause + [ 0x45 ] = KEY_PAUSE, /* Pause */ [ 0x44 ] = KEY_STOP, -#if 0 - [ 0x43 ] = KEY_T, // Time Shift - [ 0x47 ] = KEY_Y, // Time Shift OFF - [ 0x4a ] = KEY_O, // TOP - [ 0x17 ] = KEY_F, // SURF CH -#endif - [ 0x40 ] = KEY_FORWARD, // Forward ? - [ 0x42 ] = KEY_REWIND, // Backward ? + [ 0x40 ] = KEY_FORWARD, /* Forward ? */ + [ 0x42 ] = KEY_REWIND, /* Backward ? */ }; -- cgit v1.2.3 From fa9846a8c5965636fbade8655ae0ce1f9a655bd4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:42 -0700 Subject: [PATCH] v4l: BTTV update - use DMA_32BIT_MASK. - Rename tuner structures fields. - Tail spaces removed. - I2C cleanups and converged to a basic reference structure. - Removed unused structures. - Removed BTTV version check. Signed-off-by: Signed-off-by: Michael Krufky Signed-Off-By: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/bttv-cards.c | 110 +++++--------------------------------- drivers/media/video/bttv-driver.c | 19 ++----- drivers/media/video/bttv-i2c.c | 26 ++++++--- drivers/media/video/bttv-risc.c | 9 ---- 4 files changed, 35 insertions(+), 129 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 251092e7f19..2dbf5ec43ab 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -1,5 +1,5 @@ /* - $Id: bttv-cards.c,v 1.49 2005/06/10 17:20:24 mchehab Exp $ + $Id: bttv-cards.c,v 1.53 2005/07/05 17:37:35 nsh Exp $ bttv-cards.c @@ -39,9 +39,6 @@ #include #include "bttvp.h" -#if 0 /* not working yet */ -#include "bt832.h" -#endif /* fwd decl */ static void boot_msp34xx(struct bttv *btv, int pin); @@ -513,13 +510,8 @@ struct tvcard bttv_tvcards[] = { .svhs = 2, .gpiomask = 0x01fe00, .muxsel = { 2, 3, 1, 1}, -#if 0 - // old - .audiomux = { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }, -#else // 2003-10-20 by "Anton A. Arapov" .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 }, -#endif .needs_tvaudio = 1, .pll = PLL_28, .tuner_type = -1, @@ -766,14 +758,9 @@ struct tvcard bttv_tvcards[] = { .tuner = 0, .svhs = 2, .muxsel = { 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector -#if 0 - .gpiomask = 0xc33000, - .audiomux = { 0x422000,0x1000,0x0000,0x620000,0x800000 }, -#else /* Alexander Varakin [stereo version] */ .gpiomask = 0xb33000, .audiomux = { 0x122000,0x1000,0x0000,0x620000,0x800000 }, -#endif /* Audio Routing for "WinFast 2000 XP" (no tv stereo !) gpio23 -- hef4052:nEnable (0x800000) gpio12 -- hef4052:A1 @@ -1603,20 +1590,11 @@ struct tvcard bttv_tvcards[] = { .video_inputs = 4, .audio_inputs = 1, .tuner = -1, -#if 0 /* TODO ... */ - .svhs = OSPREY540_SVID_ANALOG, - .muxsel = { [OSPREY540_COMP_ANALOG] = 2, - [OSPREY540_SVID_ANALOG] = 3, }, -#endif .pll = PLL_28, .tuner_type = -1, .no_msp34xx = 1, .no_tda9875 = 1, .no_tda7432 = 1, -#if 0 /* TODO ... */ - .muxsel_hook = osprey_540_muxsel, - .picture_hook = osprey_540_set_picture, -#endif },{ /* ---- card 0x5C ---------------------------------- */ @@ -2546,21 +2524,12 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input) btaor((2)<<5, ~(3<<5), BT848_IFORM); gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]); -#if 0 - /* svhs */ - /* wake chroma ADC */ - btand(~BT848_ADC_C_SLEEP, BT848_ADC); - /* set to YC video */ - btor(BT848_CONTROL_COMP, BT848_E_CONTROL); - btor(BT848_CONTROL_COMP, BT848_O_CONTROL); -#else /* composite */ /* set chroma ADC to sleep */ btor(BT848_ADC_C_SLEEP, BT848_ADC); /* set to composite video */ btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); -#endif /* switch sync drive off */ gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); @@ -2813,10 +2782,18 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->tuner_type = tuner[btv->c.nr]; printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type); if (btv->pinnacle_id != UNSET) - bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, + bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE, &btv->pinnacle_id); - if (btv->tuner_type != UNSET) - bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + if (btv->tuner_type != UNSET) { + struct tuner_setup tun_setup; + + tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; + tun_setup.type = btv->tuner_type; + tun_setup.addr = ADDR_UNSET; + + bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup); + } + btv->svhs = bttv_tvcards[btv->c.type].svhs; if (svhs[btv->c.nr] != UNSET) btv->svhs = svhs[btv->c.nr]; @@ -3125,14 +3102,6 @@ static int tuner_0_table[] = { TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL, TUNER_PHILIPS_FM1216ME_MK3 }; -#if 0 -int tuner_0_fm_table[] = { - PHILIPS_FR1236_NTSC, PHILIPS_FR1216_PAL, - PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, - PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL, - PHILIPS_FR1236_SECAM, PHILIPS_FR1236_SECAM, - PHILIPS_FR1236_SECAM, PHILIPS_FR1216_PAL}; -#endif static int tuner_1_table[] = { TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL, @@ -3218,36 +3187,6 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin) static void __devinit boot_bt832(struct bttv *btv) { -#if 0 /* not working yet */ - int resetbit=0; - - switch (btv->c.type) { - case BTTV_PXELVWPLTVPAK: - resetbit = 0x400000; - break; - case BTTV_MODTEC_205: - resetbit = 1<<9; - break; - default: - BUG(); - } - - request_module("bt832"); - bttv_call_i2c_clients(btv, BT832_HEXDUMP, NULL); - - printk("bttv%d: Reset Bt832 [line=0x%x]\n",btv->c.nr,resetbit); - gpio_write(0); - gpio_inout(resetbit, resetbit); - udelay(5); - gpio_bits(resetbit, resetbit); - udelay(5); - gpio_bits(resetbit, 0); - udelay(5); - - // bt832 on pixelview changes from i2c 0x8a to 0x88 after - // being reset as above. So we must follow by this: - bttv_call_i2c_clients(btv, BT832_REATTACH, NULL); -#endif } /* ----------------------------------------------------------------------- */ @@ -3572,11 +3511,6 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq) { dprintk("tea5757_set_freq %d\n",freq); tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ -#if 0 - /* breaks Miro PCTV */ - value = tea5757_read(btv); - dprintk("bttv%d: tea5757 readback=0x%x\n",btv->c.nr,value); -#endif } @@ -3656,13 +3590,8 @@ gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int val, con; -#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0) if (btv->radio_user) return; -#else - if (btv->radio) - return; -#endif val = gpio_read(); if (set) { @@ -3851,13 +3780,8 @@ pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int val = 0; -#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0) if (btv->radio_user) return; -#else - if (btv->radio) - return; -#endif if (set) { if (v->mode & VIDEO_SOUND_MONO) { @@ -3888,13 +3812,8 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) { unsigned int val = 0xffff; -#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0) if (btv->radio_user) return; -#else - if (btv->radio) - return; -#endif if (set) { if (v->mode & VIDEO_SOUND_MONO) { val = 0x0000; @@ -4371,11 +4290,6 @@ void __devinit bttv_check_chipset(void) latency = 0x0A; #endif -#if 0 - /* print which chipset we have */ - while ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8,dev))) - printk(KERN_INFO "bttv: Host bridge is %s\n",pci_name(dev)); -#endif /* print warnings about any quirks found */ if (triton1) diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 7d62b394c50..51a0f6d68e7 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -1,5 +1,5 @@ /* - $Id: bttv-driver.c,v 1.40 2005/06/16 21:38:45 nsh Exp $ + $Id: bttv-driver.c,v 1.42 2005/07/05 17:37:35 nsh Exp $ bttv - Bt848 frame grabber driver @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -698,12 +699,10 @@ int locked_btres(struct bttv *btv, int bit) static void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits) { -#if 1 /* DEBUG */ if ((fh->resources & bits) != bits) { /* trying to free ressources not allocated by us ... */ printk("bttv: BUG! (btres)\n"); } -#endif down(&btv->reslock); fh->resources &= ~bits; btv->resources &= ~bits; @@ -943,11 +942,6 @@ audio_mux(struct bttv *btv, int mode) i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio; if (btv->opt_automute && !signal && !btv->radio_user) mux = AUDIO_OFF; -#if 0 - printk("bttv%d: amux: mode=%d audio=%d signal=%s mux=%d/%d irq=%s\n", - btv->c.nr, mode, btv->audio, signal ? "yes" : "no", - mux, i2c_mux, in_interrupt() ? "yes" : "no"); -#endif val = bttv_tvcards[btv->c.type].audiomux[mux]; gpio_bits(bttv_tvcards[btv->c.type].gpiomask,val); @@ -994,11 +988,6 @@ set_tvnorm(struct bttv *btv, unsigned int norm) case BTTV_VOODOOTV_FM: bttv_tda9880_setnorm(btv,norm); break; -#if 0 - case BTTV_OSPREY540: - osprey_540_set_norm(btv,norm); - break; -#endif } return 0; } @@ -1849,7 +1838,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) if (unlikely(f->tuner != 0)) return -EINVAL; - if (unlikely(f->type != V4L2_TUNER_ANALOG_TV)) + if (unlikely (f->type != V4L2_TUNER_ANALOG_TV)) return -EINVAL; down(&btv->lock); btv->freq = f->frequency; @@ -3865,7 +3854,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->c.nr); return -EIO; } - if (pci_set_dma_mask(dev, 0xffffffff)) { + if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) { printk(KERN_WARNING "bttv%d: No suitable DMA available.\n", btv->c.nr); return -EIO; diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c index da448a5f9e9..234a8556376 100644 --- a/drivers/media/video/bttv-i2c.c +++ b/drivers/media/video/bttv-i2c.c @@ -1,5 +1,5 @@ /* - $Id: bttv-i2c.c,v 1.21 2005/06/10 17:20:24 mchehab Exp $ + $Id: bttv-i2c.c,v 1.25 2005/07/05 17:37:35 nsh Exp $ bttv-i2c.c -- all the i2c code is here @@ -295,14 +295,26 @@ static int attach_inform(struct i2c_client *client) { struct bttv *btv = i2c_get_adapdata(client->adapter); - if (btv->tuner_type != UNSET) - bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + if (bttv_debug) + printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n", + btv->c.nr,client->driver->name,client->addr, + i2c_clientname(client)); + if (!client->driver->command) + return 0; + + if (btv->tuner_type != UNSET) { + struct tuner_setup tun_setup; + + tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; + tun_setup.type = btv->tuner_type; + tun_setup.addr = ADDR_UNSET; + + client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); + } + if (btv->pinnacle_id != UNSET) - bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, + client->driver->command(client,AUDC_CONFIG_PINNACLE, &btv->pinnacle_id); - if (bttv_debug) - printk("bttv%d: i2c attach [client=%s]\n", - btv->c.nr, i2c_clientname(client)); return 0; } diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c index bdc5ce6c43b..9ed21fd190c 100644 --- a/drivers/media/video/bttv-risc.c +++ b/drivers/media/video/bttv-risc.c @@ -334,10 +334,6 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo, } vdelay = tvnorm->vdelay; -#if 0 /* FIXME */ - if (vdelay < btv->vbi.lines*2) - vdelay = btv->vbi.lines*2; -#endif xsf = (width*scaledtwidth)/swidth; geo->hscale = ((totalwidth*4096UL)/xsf-4096); @@ -776,13 +772,8 @@ bttv_overlay_risc(struct bttv *btv, bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0); break; case V4L2_FIELD_INTERLACED: -#if 0 - bttv_risc_overlay(btv, &buf->top, fmt, ov, 1, 0); - bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 1); -#else bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1); bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0); -#endif break; default: BUG(); -- cgit v1.2.3 From 41ef7c1ed48cb273c7b7a9ffd48a262a22f84483 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:44 -0700 Subject: [PATCH] v4l: CX88 Update - Removed unused structures. - Removed BTTV version check. - Some debug structs moved to their own .c file and converted to static - Comment changed to express better when attach_inform is running - set_freq removed from set_mode at tuner-core.c. - I2C cleanups and converged to a basic reference structure. - Rename tuner structures fields. - It calls VIDIOC_G_FREQUENCY to get tuner freq from tuner. - added missing contrast offset value, set to 0. - Let Kconfig decide whether to include frontend-specific code. Signed-Off-By: Nickolay V. Shmyrev Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/cx88/cx88-blackbird.c | 5 - drivers/media/video/cx88/cx88-core.c | 48 +--- drivers/media/video/cx88/cx88-dvb.c | 36 +-- drivers/media/video/cx88/cx88-i2c.c | 31 ++- drivers/media/video/cx88/cx88-input.c | 448 +++++++++++++++--------------- drivers/media/video/cx88/cx88-mpeg.c | 26 +- drivers/media/video/cx88/cx88-reg.h | 11 +- drivers/media/video/cx88/cx88-tvaudio.c | 76 +---- drivers/media/video/cx88/cx88-video.c | 303 +------------------- drivers/media/video/cx88/cx88.h | 12 +- 10 files changed, 296 insertions(+), 700 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 91f8afeded8..4f39688f780 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -690,11 +690,9 @@ static void blackbird_codec_settings(struct cx8802_dev *dev) int bitrate_mode = 1; int bitrate = 7500000; int bitrate_peak = 7500000; -#if 1 bitrate_mode = BLACKBIRD_VIDEO_CBR; bitrate = 4000*1024; bitrate_peak = 4000*1024; -#endif /* assign stream type */ blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_PROGRAM); @@ -810,9 +808,6 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) cx_write(MO_VBOS_CONTROL, 0x84A00); /* no 656 mode, 8-bit pixels, disable VBI */ cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */ -#if 0 /* FIXME */ - set_scale(dev, 720, 480, V4L2_FIELD_INTERLACED); -#endif blackbird_codec_settings(dev); msleep(1); diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 96cb0ff33bb..5e868f5cd0c 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-core.c,v 1.31 2005/06/22 22:58:04 mchehab Exp $ + * $Id: cx88-core.c,v 1.33 2005/07/07 14:17:47 mchehab Exp $ * * device driver for Conexant 2388x based TV cards * driver core @@ -470,25 +470,6 @@ int cx88_risc_decode(u32 risc) return incr[risc >> 28] ? incr[risc >> 28] : 1; } -#if 0 /* currently unused, but useful for debugging */ -void cx88_risc_disasm(struct cx88_core *core, - struct btcx_riscmem *risc) -{ - unsigned int i,j,n; - - printk("%s: risc disasm: %p [dma=0x%08lx]\n", - core->name, risc->cpu, (unsigned long)risc->dma); - for (i = 0; i < (risc->size >> 2); i += n) { - printk("%s: %04d: ", core->name, i); - n = cx88_risc_decode(risc->cpu[i]); - for (j = 1; j < n; j++) - printk("%s: %04d: 0x%08x [ arg #%d ]\n", - core->name, i+j, risc->cpu[i+j], j); - if (risc->cpu[i] == RISC_JUMP) - break; - } -} -#endif void cx88_sram_channel_dump(struct cx88_core *core, struct sram_channel *ch) @@ -545,30 +526,12 @@ void cx88_sram_channel_dump(struct cx88_core *core, core->name,cx_read(ch->cnt2_reg)); } -/* Used only on cx88-core */ static char *cx88_pci_irqs[32] = { "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1", "src_dma", "dst_dma", "risc_rd_err", "risc_wr_err", "brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err", "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1" }; -/* Used only on cx88-video */ -char *cx88_vid_irqs[32] = { - "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", - "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", - "y_oflow", "u_oflow", "v_oflow", "vbi_oflow", - "y_sync", "u_sync", "v_sync", "vbi_sync", - "opc_err", "par_err", "rip_err", "pci_abort", -}; -/* Used only on cx88-mpeg */ -char *cx88_mpeg_irqs[32] = { - "ts_risci1", NULL, NULL, NULL, - "ts_risci2", NULL, NULL, NULL, - "ts_oflow", NULL, NULL, NULL, - "ts_sync", NULL, NULL, NULL, - "opc_err", "par_err", "rip_err", "pci_abort", - "ts_err?", -}; void cx88_print_irqbits(char *name, char *tag, char **strings, u32 bits, u32 mask) @@ -618,16 +581,11 @@ void cx88_wakeup(struct cx88_core *core, break; buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); -#if 0 - if (buf->count > count) - break; -#else /* count comes from the hw and is is 16bit wide -- * this trick handles wrap-arounds correctly for * up to 32767 buffers in flight... */ if ((s16) (count - buf->count) < 0) break; -#endif do_gettimeofday(&buf->vb.ts); dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, count, buf->count); @@ -955,12 +913,10 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm) norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f); cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat); -#if 1 // FIXME: as-is from DScaler dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n", norm->cxoformat, cx_read(MO_OUTPUT_FORMAT)); cx_write(MO_OUTPUT_FORMAT, norm->cxoformat); -#endif // MO_SCONV_REG = adc clock / video dec clock * 2^17 tmp64 = adc_clock * (u64)(1 << 17); @@ -1219,8 +1175,6 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) /* ------------------------------------------------------------------ */ EXPORT_SYMBOL(cx88_print_ioctl); -EXPORT_SYMBOL(cx88_vid_irqs); -EXPORT_SYMBOL(cx88_mpeg_irqs); EXPORT_SYMBOL(cx88_print_irqbits); EXPORT_SYMBOL(cx88_core_irq); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 690477a6791..5544e1d6a34 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-dvb.c,v 1.39 2005/07/02 20:00:46 mkrufky Exp $ + * $Id: cx88-dvb.c,v 1.41 2005/07/04 19:35:05 mkrufky Exp $ * * device driver for Conexant 2388x based TV cards * MPEG Transport Stream (DVB) routines @@ -30,22 +30,20 @@ #include #include -/* these three frontends need merging via linuxtv cvs ... */ -#define HAVE_CX22702 1 -#define HAVE_OR51132 1 -#define HAVE_LGDT3302 1 - #include "cx88.h" #include "dvb-pll.h" -#include "mt352.h" -#include "mt352_priv.h" -#if HAVE_CX22702 + +#if CONFIG_DVB_MT352 +# include "mt352.h" +# include "mt352_priv.h" +#endif +#if CONFIG_DVB_CX22702 # include "cx22702.h" #endif -#if HAVE_OR51132 +#if CONFIG_DVB_OR51132 # include "or51132.h" #endif -#if HAVE_LGDT3302 +#if CONFIG_DVB_LGDT3302 # include "lgdt3302.h" #endif @@ -104,6 +102,7 @@ static struct videobuf_queue_ops dvb_qops = { /* ------------------------------------------------------------------ */ +#if CONFIG_DVB_MT352 static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 }; @@ -171,8 +170,9 @@ static struct mt352_config dntv_live_dvbt_config = { .demod_init = dntv_live_dvbt_demod_init, .pll_set = mt352_pll_set, }; +#endif -#if HAVE_CX22702 +#if CONFIG_DVB_CX22702 static struct cx22702_config connexant_refboard_config = { .demod_address = 0x43, .pll_address = 0x60, @@ -186,7 +186,7 @@ static struct cx22702_config hauppauge_novat_config = { }; #endif -#if HAVE_OR51132 +#if CONFIG_DVB_OR51132 static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured) { @@ -203,7 +203,7 @@ static struct or51132_config pchdtv_hd3000 = { }; #endif -#if HAVE_LGDT3302 +#if CONFIG_DVB_LGDT3302 static int lgdt3302_set_ts_param(struct dvb_frontend* fe, int is_punctured) { struct cx8802_dev *dev= fe->dvb->priv; @@ -237,7 +237,7 @@ static int dvb_register(struct cx8802_dev *dev) /* init frontend */ switch (dev->core->board) { -#if HAVE_CX22702 +#if CONFIG_DVB_CX22702 case CX88_BOARD_HAUPPAUGE_DVB_T1: dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config, &dev->core->i2c_adap); @@ -248,6 +248,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); break; #endif +#if CONFIG_DVB_MT352 case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: dev->core->pll_addr = 0x61; dev->core->pll_desc = &dvb_pll_lg_z201; @@ -268,13 +269,14 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config, &dev->core->i2c_adap); break; -#if HAVE_OR51132 +#endif +#if CONFIG_DVB_OR51132 case CX88_BOARD_PCHDTV_HD3000: dev->dvb.frontend = or51132_attach(&pchdtv_hd3000, &dev->core->i2c_adap); break; #endif -#if HAVE_LGDT3302 +#if CONFIG_DVB_LGDT3302 case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: dev->ts_gen_cntrl = 0x08; { diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index b5342234b30..8403c4e9505 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -1,5 +1,5 @@ /* - $Id: cx88-i2c.c,v 1.24 2005/06/17 18:46:23 mkrufky Exp $ + $Id: cx88-i2c.c,v 1.28 2005/07/05 17:37:35 nsh Exp $ cx88-i2c.c -- all the i2c code is here @@ -91,25 +91,32 @@ static int cx8800_bit_getsda(void *data) static int attach_inform(struct i2c_client *client) { - struct tuner_addr tun_addr; + struct tuner_setup tun_setup; struct cx88_core *core = i2c_get_adapdata(client->adapter); - dprintk(1, "i2c attach [addr=0x%x,client=%s]\n", - client->addr, i2c_clientname(client)); + dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", + client->driver->name,client->addr,i2c_clientname(client)); if (!client->driver->command) return 0; if (core->radio_type != UNSET) { - tun_addr.v4l2_tuner = V4L2_TUNER_RADIO; - tun_addr.type = core->radio_type; - tun_addr.addr = core->radio_addr; - client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr); + if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) { + tun_setup.mode_mask = T_RADIO; + tun_setup.type = core->radio_type; + tun_setup.addr = core->radio_addr; + + client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); + } } if (core->tuner_type != UNSET) { - tun_addr.v4l2_tuner = V4L2_TUNER_ANALOG_TV; - tun_addr.type = core->tuner_type; - tun_addr.addr = core->tuner_addr; - client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr); + if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) { + + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.type = core->tuner_type; + tun_setup.addr = core->tuner_addr; + + client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); + } } if (core->tda9887_conf) diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index bdc26e75ab5..21488779819 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-input.c,v 1.13 2005/06/13 16:07:46 nsh Exp $ + * $Id: cx88-input.c,v 1.15 2005/07/07 13:58:38 mchehab Exp $ * * Device driver for GPIO attached remote control interfaces * on Conexant 2388x based TV/DVB cards. @@ -38,199 +38,206 @@ /* DigitalNow DNTV Live DVB-T Remote */ static IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = { - [ 0x00 ] = KEY_ESC, // 'go up a level?' - [ 0x01 ] = KEY_KP1, // '1' - [ 0x02 ] = KEY_KP2, // '2' - [ 0x03 ] = KEY_KP3, // '3' - [ 0x04 ] = KEY_KP4, // '4' - [ 0x05 ] = KEY_KP5, // '5' - [ 0x06 ] = KEY_KP6, // '6' - [ 0x07 ] = KEY_KP7, // '7' - [ 0x08 ] = KEY_KP8, // '8' - [ 0x09 ] = KEY_KP9, // '9' - [ 0x0a ] = KEY_KP0, // '0' - [ 0x0b ] = KEY_TUNER, // 'tv/fm' - [ 0x0c ] = KEY_SEARCH, // 'scan' - [ 0x0d ] = KEY_STOP, // 'stop' - [ 0x0e ] = KEY_PAUSE, // 'pause' - [ 0x0f ] = KEY_LIST, // 'source' - - [ 0x10 ] = KEY_MUTE, // 'mute' - [ 0x11 ] = KEY_REWIND, // 'backward <<' - [ 0x12 ] = KEY_POWER, // 'power' - [ 0x13 ] = KEY_S, // 'snap' - [ 0x14 ] = KEY_AUDIO, // 'stereo' - [ 0x15 ] = KEY_CLEAR, // 'reset' - [ 0x16 ] = KEY_PLAY, // 'play' - [ 0x17 ] = KEY_ENTER, // 'enter' - [ 0x18 ] = KEY_ZOOM, // 'full screen' - [ 0x19 ] = KEY_FASTFORWARD, // 'forward >>' - [ 0x1a ] = KEY_CHANNELUP, // 'channel +' - [ 0x1b ] = KEY_VOLUMEUP, // 'volume +' - [ 0x1c ] = KEY_INFO, // 'preview' - [ 0x1d ] = KEY_RECORD, // 'record' - [ 0x1e ] = KEY_CHANNELDOWN, // 'channel -' - [ 0x1f ] = KEY_VOLUMEDOWN, // 'volume -' + [0x00] = KEY_ESC, /* 'go up a level?' */ + /* Keys 0 to 9 */ + [0x0a] = KEY_KP0, + [0x01] = KEY_KP1, + [0x02] = KEY_KP2, + [0x03] = KEY_KP3, + [0x04] = KEY_KP4, + [0x05] = KEY_KP5, + [0x06] = KEY_KP6, + [0x07] = KEY_KP7, + [0x08] = KEY_KP8, + [0x09] = KEY_KP9, + + [0x0b] = KEY_TUNER, /* tv/fm */ + [0x0c] = KEY_SEARCH, /* scan */ + [0x0d] = KEY_STOP, + [0x0e] = KEY_PAUSE, + [0x0f] = KEY_LIST, /* source */ + + [0x10] = KEY_MUTE, + [0x11] = KEY_REWIND, /* backward << */ + [0x12] = KEY_POWER, + [0x13] = KEY_S, /* snap */ + [0x14] = KEY_AUDIO, /* stereo */ + [0x15] = KEY_CLEAR, /* reset */ + [0x16] = KEY_PLAY, + [0x17] = KEY_ENTER, + [0x18] = KEY_ZOOM, /* full screen */ + [0x19] = KEY_FASTFORWARD, /* forward >> */ + [0x1a] = KEY_CHANNELUP, + [0x1b] = KEY_VOLUMEUP, + [0x1c] = KEY_INFO, /* preview */ + [0x1d] = KEY_RECORD, /* record */ + [0x1e] = KEY_CHANNELDOWN, + [0x1f] = KEY_VOLUMEDOWN, }; /* ---------------------------------------------------------------------- */ /* IO-DATA BCTV7E Remote */ static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = { - [ 0x40 ] = KEY_TV, // TV - [ 0x20 ] = KEY_RADIO, // FM - [ 0x60 ] = KEY_EPG, // EPG - [ 0x00 ] = KEY_POWER, // power - - [ 0x50 ] = KEY_KP1, // 1 - [ 0x30 ] = KEY_KP2, // 2 - [ 0x70 ] = KEY_KP3, // 3 - [ 0x10 ] = KEY_L, // Live - - [ 0x48 ] = KEY_KP4, // 4 - [ 0x28 ] = KEY_KP5, // 5 - [ 0x68 ] = KEY_KP6, // 6 - [ 0x08 ] = KEY_T, // Time Shift - - [ 0x58 ] = KEY_KP7, // 7 - [ 0x38 ] = KEY_KP8, // 8 - [ 0x78 ] = KEY_KP9, // 9 - [ 0x18 ] = KEY_PLAYPAUSE, // Play - - [ 0x44 ] = KEY_KP0, // 10 - [ 0x24 ] = KEY_ENTER, // 11 - [ 0x64 ] = KEY_ESC, // 12 - [ 0x04 ] = KEY_M, // Multi - - [ 0x54 ] = KEY_VIDEO, // VIDEO - [ 0x34 ] = KEY_CHANNELUP, // channel + - [ 0x74 ] = KEY_VOLUMEUP, // volume + - [ 0x14 ] = KEY_MUTE, // Mute - - [ 0x4c ] = KEY_S, // SVIDEO - [ 0x2c ] = KEY_CHANNELDOWN, // channel - - [ 0x6c ] = KEY_VOLUMEDOWN, // volume - - [ 0x0c ] = KEY_ZOOM, // Zoom - - [ 0x5c ] = KEY_PAUSE, // pause - [ 0x3c ] = KEY_C, // || (red) - [ 0x7c ] = KEY_RECORD, // recording - [ 0x1c ] = KEY_STOP, // stop - - [ 0x41 ] = KEY_REWIND, // backward << - [ 0x21 ] = KEY_PLAY, // play - [ 0x61 ] = KEY_FASTFORWARD, // forward >> - [ 0x01 ] = KEY_NEXT, // skip >| + [0x40] = KEY_TV, + [0x20] = KEY_RADIO, /* FM */ + [0x60] = KEY_EPG, + [0x00] = KEY_POWER, + + /* Keys 0 to 9 */ + [0x44] = KEY_KP0, /* 10 */ + [0x50] = KEY_KP1, + [0x30] = KEY_KP2, + [0x70] = KEY_KP3, + [0x48] = KEY_KP4, + [0x28] = KEY_KP5, + [0x68] = KEY_KP6, + [0x58] = KEY_KP7, + [0x38] = KEY_KP8, + [0x78] = KEY_KP9, + + [0x10] = KEY_L, /* Live */ + [0x08] = KEY_T, /* Time Shift */ + + [0x18] = KEY_PLAYPAUSE, /* Play */ + + [0x24] = KEY_ENTER, /* 11 */ + [0x64] = KEY_ESC, /* 12 */ + [0x04] = KEY_M, /* Multi */ + + [0x54] = KEY_VIDEO, + [0x34] = KEY_CHANNELUP, + [0x74] = KEY_VOLUMEUP, + [0x14] = KEY_MUTE, + + [0x4c] = KEY_S, /* SVIDEO */ + [0x2c] = KEY_CHANNELDOWN, + [0x6c] = KEY_VOLUMEDOWN, + [0x0c] = KEY_ZOOM, + + [0x5c] = KEY_PAUSE, + [0x3c] = KEY_C, /* || (red) */ + [0x7c] = KEY_RECORD, /* recording */ + [0x1c] = KEY_STOP, + + [0x41] = KEY_REWIND, /* backward << */ + [0x21] = KEY_PLAY, + [0x61] = KEY_FASTFORWARD, /* forward >> */ + [0x01] = KEY_NEXT, /* skip >| */ }; /* ---------------------------------------------------------------------- */ /* ADS Tech Instant TV DVB-T PCI Remote */ static IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = { - [ 0x5b ] = KEY_POWER, - [ 0x5f ] = KEY_MUTE, - [ 0x57 ] = KEY_1, - [ 0x4f ] = KEY_2, - [ 0x53 ] = KEY_3, - [ 0x56 ] = KEY_4, - [ 0x4e ] = KEY_5, - [ 0x5e ] = KEY_6, - [ 0x54 ] = KEY_7, - [ 0x4c ] = KEY_8, - [ 0x5c ] = KEY_9, - [ 0x4d ] = KEY_0, - [ 0x55 ] = KEY_GOTO, - [ 0x5d ] = KEY_SEARCH, - [ 0x17 ] = KEY_EPG, // Guide - [ 0x1f ] = KEY_MENU, - [ 0x0f ] = KEY_UP, - [ 0x46 ] = KEY_DOWN, - [ 0x16 ] = KEY_LEFT, - [ 0x1e ] = KEY_RIGHT, - [ 0x0e ] = KEY_SELECT, // Enter - [ 0x5a ] = KEY_INFO, - [ 0x52 ] = KEY_EXIT, - [ 0x59 ] = KEY_PREVIOUS, - [ 0x51 ] = KEY_NEXT, - [ 0x58 ] = KEY_REWIND, - [ 0x50 ] = KEY_FORWARD, - [ 0x44 ] = KEY_PLAYPAUSE, - [ 0x07 ] = KEY_STOP, - [ 0x1b ] = KEY_RECORD, - [ 0x13 ] = KEY_TUNER, // Live - [ 0x0a ] = KEY_A, - [ 0x12 ] = KEY_B, - [ 0x03 ] = KEY_PROG1, // 1 - [ 0x01 ] = KEY_PROG2, // 2 - [ 0x00 ] = KEY_PROG3, // 3 - [ 0x06 ] = KEY_DVD, - [ 0x48 ] = KEY_AUX, // Photo - [ 0x40 ] = KEY_VIDEO, - [ 0x19 ] = KEY_AUDIO, // Music - [ 0x0b ] = KEY_CHANNELUP, - [ 0x08 ] = KEY_CHANNELDOWN, - [ 0x15 ] = KEY_VOLUMEUP, - [ 0x1c ] = KEY_VOLUMEDOWN, + /* Keys 0 to 9 */ + [0x4d] = KEY_0, + [0x57] = KEY_1, + [0x4f] = KEY_2, + [0x53] = KEY_3, + [0x56] = KEY_4, + [0x4e] = KEY_5, + [0x5e] = KEY_6, + [0x54] = KEY_7, + [0x4c] = KEY_8, + [0x5c] = KEY_9, + + [0x5b] = KEY_POWER, + [0x5f] = KEY_MUTE, + [0x55] = KEY_GOTO, + [0x5d] = KEY_SEARCH, + [0x17] = KEY_EPG, /* Guide */ + [0x1f] = KEY_MENU, + [0x0f] = KEY_UP, + [0x46] = KEY_DOWN, + [0x16] = KEY_LEFT, + [0x1e] = KEY_RIGHT, + [0x0e] = KEY_SELECT, /* Enter */ + [0x5a] = KEY_INFO, + [0x52] = KEY_EXIT, + [0x59] = KEY_PREVIOUS, + [0x51] = KEY_NEXT, + [0x58] = KEY_REWIND, + [0x50] = KEY_FORWARD, + [0x44] = KEY_PLAYPAUSE, + [0x07] = KEY_STOP, + [0x1b] = KEY_RECORD, + [0x13] = KEY_TUNER, /* Live */ + [0x0a] = KEY_A, + [0x12] = KEY_B, + [0x03] = KEY_PROG1, /* 1 */ + [0x01] = KEY_PROG2, /* 2 */ + [0x00] = KEY_PROG3, /* 3 */ + [0x06] = KEY_DVD, + [0x48] = KEY_AUX, /* Photo */ + [0x40] = KEY_VIDEO, + [0x19] = KEY_AUDIO, /* Music */ + [0x0b] = KEY_CHANNELUP, + [0x08] = KEY_CHANNELDOWN, + [0x15] = KEY_VOLUMEUP, + [0x1c] = KEY_VOLUMEDOWN, }; /* ---------------------------------------------------------------------- */ /* MSI TV@nywhere remote */ static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = { - [ 0x00 ] = KEY_0, /* '0' */ - [ 0x01 ] = KEY_1, /* '1' */ - [ 0x02 ] = KEY_2, /* '2' */ - [ 0x03 ] = KEY_3, /* '3' */ - [ 0x04 ] = KEY_4, /* '4' */ - [ 0x05 ] = KEY_5, /* '5' */ - [ 0x06 ] = KEY_6, /* '6' */ - [ 0x07 ] = KEY_7, /* '7' */ - [ 0x08 ] = KEY_8, /* '8' */ - [ 0x09 ] = KEY_9, /* '9' */ - [ 0x0c ] = KEY_MUTE, /* 'Mute' */ - [ 0x0f ] = KEY_SCREEN, /* 'Full Screen' */ - [ 0x10 ] = KEY_F, /* 'Funtion' */ - [ 0x11 ] = KEY_T, /* 'Time shift' */ - [ 0x12 ] = KEY_POWER, /* 'Power' */ - [ 0x13 ] = KEY_MEDIA, /* 'MTS' */ - [ 0x14 ] = KEY_SLOW, /* 'Slow' */ - [ 0x16 ] = KEY_REWIND, /* 'backward <<' */ - [ 0x17 ] = KEY_ENTER, /* 'Return' */ - [ 0x18 ] = KEY_FASTFORWARD, /* 'forward >>' */ - [ 0x1a ] = KEY_CHANNELUP, /* 'Channel+' */ - [ 0x1b ] = KEY_VOLUMEUP, /* 'Volume+' */ - [ 0x1e ] = KEY_CHANNELDOWN, /* 'Channel-' */ - [ 0x1f ] = KEY_VOLUMEDOWN, /* 'Volume-' */ + /* Keys 0 to 9 */ + [0x00] = KEY_0, + [0x01] = KEY_1, + [0x02] = KEY_2, + [0x03] = KEY_3, + [0x04] = KEY_4, + [0x05] = KEY_5, + [0x06] = KEY_6, + [0x07] = KEY_7, + [0x08] = KEY_8, + [0x09] = KEY_9, + + [0x0c] = KEY_MUTE, + [0x0f] = KEY_SCREEN, /* Full Screen */ + [0x10] = KEY_F, /* Funtion */ + [0x11] = KEY_T, /* Time shift */ + [0x12] = KEY_POWER, + [0x13] = KEY_MEDIA, /* MTS */ + [0x14] = KEY_SLOW, + [0x16] = KEY_REWIND, /* backward << */ + [0x17] = KEY_ENTER, /* Return */ + [0x18] = KEY_FASTFORWARD, /* forward >> */ + [0x1a] = KEY_CHANNELUP, + [0x1b] = KEY_VOLUMEUP, + [0x1e] = KEY_CHANNELDOWN, + [0x1f] = KEY_VOLUMEDOWN, }; /* ---------------------------------------------------------------------- */ struct cx88_IR { - struct cx88_core *core; - struct input_dev input; - struct ir_input_state ir; - char name[32]; - char phys[32]; + struct cx88_core *core; + struct input_dev input; + struct ir_input_state ir; + char name[32]; + char phys[32]; /* sample from gpio pin 16 */ - int sampling; - u32 samples[16]; - int scount; - unsigned long release; + int sampling; + u32 samples[16]; + int scount; + unsigned long release; /* poll external decoder */ - int polling; - struct work_struct work; - struct timer_list timer; - u32 gpio_addr; - u32 last_gpio; - u32 mask_keycode; - u32 mask_keydown; - u32 mask_keyup; + int polling; + struct work_struct work; + struct timer_list timer; + u32 gpio_addr; + u32 last_gpio; + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; }; static int ir_debug = 0; -module_param(ir_debug, int, 0644); /* debug level [IR] */ +module_param(ir_debug, int, 0644); /* debug level [IR] */ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define ir_dprintk(fmt, arg...) if (ir_debug) \ @@ -254,37 +261,37 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) /* extract data */ data = ir_extract_bits(gpio, ir->mask_keycode); ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n", - gpio, data, - ir->polling ? "poll" : "irq", - (gpio & ir->mask_keydown) ? " down" : "", - (gpio & ir->mask_keyup) ? " up" : ""); + gpio, data, + ir->polling ? "poll" : "irq", + (gpio & ir->mask_keydown) ? " down" : "", + (gpio & ir->mask_keyup) ? " up" : ""); if (ir->mask_keydown) { /* bit set on keydown */ if (gpio & ir->mask_keydown) { - ir_input_keydown(&ir->input,&ir->ir,data,data); + ir_input_keydown(&ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input,&ir->ir); + ir_input_nokey(&ir->input, &ir->ir); } } else if (ir->mask_keyup) { /* bit cleared on keydown */ if (0 == (gpio & ir->mask_keyup)) { - ir_input_keydown(&ir->input,&ir->ir,data,data); + ir_input_keydown(&ir->input, &ir->ir, data, data); } else { - ir_input_nokey(&ir->input,&ir->ir); + ir_input_nokey(&ir->input, &ir->ir); } } else { /* can't distinguish keydown/up :-/ */ - ir_input_keydown(&ir->input,&ir->ir,data,data); - ir_input_nokey(&ir->input,&ir->ir); + ir_input_keydown(&ir->input, &ir->ir, data, data); + ir_input_nokey(&ir->input, &ir->ir); } } static void ir_timer(unsigned long data) { - struct cx88_IR *ir = (struct cx88_IR*)data; + struct cx88_IR *ir = (struct cx88_IR *)data; schedule_work(&ir->work); } @@ -307,62 +314,62 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) IR_KEYTAB_TYPE *ir_codes = NULL; int ir_type = IR_TYPE_OTHER; - ir = kmalloc(sizeof(*ir),GFP_KERNEL); + ir = kmalloc(sizeof(*ir), GFP_KERNEL); if (NULL == ir) return -ENOMEM; - memset(ir,0,sizeof(*ir)); + memset(ir, 0, sizeof(*ir)); /* detect & configure */ switch (core->board) { case CX88_BOARD_DNTV_LIVE_DVB_T: case CX88_BOARD_KWORLD_DVB_T: - ir_codes = ir_codes_dntv_live_dvb_t; - ir->gpio_addr = MO_GP1_IO; + ir_codes = ir_codes_dntv_live_dvb_t; + ir->gpio_addr = MO_GP1_IO; ir->mask_keycode = 0x1f; - ir->mask_keyup = 0x60; - ir->polling = 50; // ms + ir->mask_keyup = 0x60; + ir->polling = 50; /* ms */ break; case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_DVB_T1: - ir_codes = ir_codes_hauppauge_new; - ir_type = IR_TYPE_RC5; - ir->sampling = 1; + ir_codes = ir_codes_hauppauge_new; + ir_type = IR_TYPE_RC5; + ir->sampling = 1; break; case CX88_BOARD_WINFAST2000XP_EXPERT: - ir_codes = ir_codes_winfast; - ir->gpio_addr = MO_GP0_IO; + ir_codes = ir_codes_winfast; + ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; - ir->mask_keyup = 0x100; - ir->polling = 1; // ms + ir->mask_keyup = 0x100; + ir->polling = 1; /* ms */ break; case CX88_BOARD_IODATA_GVBCTV7E: - ir_codes = ir_codes_iodata_bctv7e; - ir->gpio_addr = MO_GP0_IO; + ir_codes = ir_codes_iodata_bctv7e; + ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0xfd; ir->mask_keydown = 0x02; - ir->polling = 5; // ms + ir->polling = 5; /* ms */ break; case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO: - ir_codes = ir_codes_pixelview; - ir->gpio_addr = MO_GP1_IO; + ir_codes = ir_codes_pixelview; + ir->gpio_addr = MO_GP1_IO; ir->mask_keycode = 0x1f; - ir->mask_keyup = 0x80; - ir->polling = 1; // ms + ir->mask_keyup = 0x80; + ir->polling = 1; /* ms */ break; case CX88_BOARD_ADSTECH_DVB_T_PCI: - ir_codes = ir_codes_adstech_dvb_t_pci; - ir->gpio_addr = MO_GP1_IO; + ir_codes = ir_codes_adstech_dvb_t_pci; + ir->gpio_addr = MO_GP1_IO; ir->mask_keycode = 0xbf; - ir->mask_keyup = 0x40; - ir->polling = 50; // ms + ir->mask_keyup = 0x40; + ir->polling = 50; /* ms */ + break; + case CX88_BOARD_MSI_TVANYWHERE_MASTER: + ir_codes = ir_codes_msi_tvanywhere; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0x1f; + ir->mask_keyup = 0x40; + ir->polling = 1; /* ms */ break; - case CX88_BOARD_MSI_TVANYWHERE_MASTER: - ir_codes = ir_codes_msi_tvanywhere; - ir->gpio_addr = MO_GP1_IO; - ir->mask_keycode = 0x1f; - ir->mask_keyup = 0x40; - ir->polling = 1; - break; } if (NULL == ir_codes) { @@ -373,8 +380,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) /* init input device */ snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", cx88_boards[core->board].name); - snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", - pci_name(pci)); + snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes); ir->input.name = ir->name; @@ -382,10 +388,10 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->input.id.bustype = BUS_PCI; ir->input.id.version = 1; if (pci->subsystem_vendor) { - ir->input.id.vendor = pci->subsystem_vendor; + ir->input.id.vendor = pci->subsystem_vendor; ir->input.id.product = pci->subsystem_device; } else { - ir->input.id.vendor = pci->vendor; + ir->input.id.vendor = pci->vendor; ir->input.id.product = pci->device; } @@ -397,13 +403,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) INIT_WORK(&ir->work, cx88_ir_work, ir); init_timer(&ir->timer); ir->timer.function = ir_timer; - ir->timer.data = (unsigned long)ir; + ir->timer.data = (unsigned long)ir; schedule_work(&ir->work); } if (ir->sampling) { - core->pci_irqmask |= (1<<18); // IR_SMP_INT - cx_write(MO_DDS_IO, 0xa80a80); // 4 kHz sample rate - cx_write(MO_DDSCFG_IO, 0x5); // enable + core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */ + cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */ + cx_write(MO_DDSCFG_IO, 0x5); /* enable */ } /* all done */ @@ -439,7 +445,7 @@ int cx88_ir_fini(struct cx88_core *core) void cx88_ir_irq(struct cx88_core *core) { struct cx88_IR *ir = core->ir; - u32 samples,rc5; + u32 samples, rc5; int i; if (NULL == ir) @@ -448,7 +454,7 @@ void cx88_ir_irq(struct cx88_core *core) return; samples = cx_read(MO_SAMPLE_IO); - if (0 != samples && 0xffffffff != samples) { + if (0 != samples && 0xffffffff != samples) { /* record sample data */ if (ir->scount < ARRAY_SIZE(ir->samples)) ir->samples[ir->scount++] = samples; @@ -456,8 +462,8 @@ void cx88_ir_irq(struct cx88_core *core) } if (!ir->scount) { /* nothing to sample */ - if (ir->ir.keypressed && time_after(jiffies,ir->release)) - ir_input_nokey(&ir->input,&ir->ir); + if (ir->ir.keypressed && time_after(jiffies, ir->release)) + ir_input_nokey(&ir->input, &ir->ir); return; } @@ -467,14 +473,14 @@ void cx88_ir_irq(struct cx88_core *core) for (i = 0; i < ir->scount; i++) ir->samples[i] = ~ir->samples[i]; if (ir_debug) - ir_dump_samples(ir->samples,ir->scount); + ir_dump_samples(ir->samples, ir->scount); /* decode it */ switch (core->board) { case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_DVB_T1: - rc5 = ir_decode_biphase(ir->samples,ir->scount,5,7); - ir_dprintk("biphase decoded: %x\n",rc5); + rc5 = ir_decode_biphase(ir->samples, ir->scount, 5, 7); + ir_dprintk("biphase decoded: %x\n", rc5); if ((rc5 & 0xfffff000) != 0x3000) break; ir_input_keydown(&ir->input, &ir->ir, rc5 & 0x3f, rc5); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 85da6dc8d0e..fe2767c0ff9 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-mpeg.c,v 1.30 2005/07/05 19:44:40 mkrufky Exp $ + * $Id: cx88-mpeg.c,v 1.31 2005/07/07 14:17:47 mchehab Exp $ * * Support for the mpeg transport stream transfers * PCI function #2 of the cx2388x. @@ -64,7 +64,6 @@ static int cx8802_start_dma(struct cx8802_dev *dev, /* write TS length to chip */ cx_write(MO_TS_LNGTH, buf->vb.width); -#if 1 /* FIXME: this needs a review. * also: move to cx88-blackbird + cx88-dvb source files? */ @@ -76,9 +75,9 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); if ((core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q) || (core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T)) { - cx_write(TS_SOP_STAT, 0<<16 | 0<<14 | 1<<13 | 0<<12); + cx_write(TS_SOP_STAT, 1<<13); } else { - cx_write(TS_SOP_STAT,0x00); + cx_write(TS_SOP_STAT, 0x00); } cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); udelay(100); @@ -98,7 +97,6 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ udelay(100); } -#endif /* reset counter */ cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET); @@ -270,6 +268,15 @@ static void cx8802_timeout(unsigned long data) do_cancel_buffers(dev,"timeout",1); } +static char *cx88_mpeg_irqs[32] = { + "ts_risci1", NULL, NULL, NULL, + "ts_risci2", NULL, NULL, NULL, + "ts_oflow", NULL, NULL, NULL, + "ts_sync", NULL, NULL, NULL, + "opc_err", "par_err", "rip_err", "pci_abort", + "ts_err?", +}; + static void cx8802_mpeg_irq(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; @@ -282,10 +289,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev) return; cx_write(MO_TS_INTSTAT, status); -#if 0 - cx88_print_irqbits(core->name, "irq mpeg ", - cx88_mpeg_irqs, status, mask); -#endif + if (debug || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq mpeg ", cx88_mpeg_irqs, status, mask); @@ -441,10 +445,8 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) } spin_unlock(&dev->slock); -#if 1 /* FIXME -- shutdown device */ cx88_shutdown(dev->core); -#endif pci_save_state(pci_dev); if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { @@ -466,10 +468,8 @@ int cx8802_resume_common(struct pci_dev *pci_dev) pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); -#if 1 /* FIXME: re-initialize hardware */ cx88_reset(dev->core); -#endif /* restart video+vbi capture */ spin_lock(&dev->slock); diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h index 63ad33f5818..37f82662d26 100644 --- a/drivers/media/video/cx88/cx88-reg.h +++ b/drivers/media/video/cx88/cx88-reg.h @@ -1,5 +1,5 @@ /* - $Id: cx88-reg.h,v 1.7 2005/06/03 13:31:51 mchehab Exp $ + $Id: cx88-reg.h,v 1.8 2005/07/07 13:58:38 mchehab Exp $ cx88x-hw.h - CX2388x register offsets @@ -604,20 +604,11 @@ #define EN_I2SIN_STR2DAC 0x00004000 #define EN_I2SIN_ENABLE 0x00008000 -#if 0 -/* old */ -#define EN_DMTRX_SUMDIFF 0x00000800 -#define EN_DMTRX_SUMR 0x00000880 -#define EN_DMTRX_LR 0x00000900 -#define EN_DMTRX_MONO 0x00000980 -#else -/* dscaler cvs */ #define EN_DMTRX_SUMDIFF (0 << 7) #define EN_DMTRX_SUMR (1 << 7) #define EN_DMTRX_LR (2 << 7) #define EN_DMTRX_MONO (3 << 7) #define EN_DMTRX_BYPASS (1 << 11) -#endif // Video #define VID_CAPTURE_CONTROL 0x310180 diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 46d78b1dc9b..91207f10bae 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -1,5 +1,5 @@ /* - $Id: cx88-tvaudio.c,v 1.36 2005/06/05 05:53:45 mchehab Exp $ + $Id: cx88-tvaudio.c,v 1.37 2005/07/07 13:58:38 mchehab Exp $ cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver @@ -278,80 +278,6 @@ static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap) set_audio_finish(core); } -#if 0 -static void set_audio_standard_NICAM(struct cx88_core *core) -{ - static const struct rlist nicam_common[] = { - /* from dscaler */ - { AUD_RATE_ADJ1, 0x00000010 }, - { AUD_RATE_ADJ2, 0x00000040 }, - { AUD_RATE_ADJ3, 0x00000100 }, - { AUD_RATE_ADJ4, 0x00000400 }, - { AUD_RATE_ADJ5, 0x00001000 }, - // { AUD_DMD_RA_DDS, 0x00c0d5ce }, - - // Deemphasis 1: - { AUD_DEEMPHGAIN_R, 0x000023c2 }, - { AUD_DEEMPHNUMER1_R, 0x0002a7bc }, - { AUD_DEEMPHNUMER2_R, 0x0003023e }, - { AUD_DEEMPHDENOM1_R, 0x0000f3d0 }, - { AUD_DEEMPHDENOM2_R, 0x00000000 }, - -#if 0 - // Deemphasis 2: (other tv norm?) - { AUD_DEEMPHGAIN_R, 0x0000c600 }, - { AUD_DEEMPHNUMER1_R, 0x00066738 }, - { AUD_DEEMPHNUMER2_R, 0x00066739 }, - { AUD_DEEMPHDENOM1_R, 0x0001e88c }, - { AUD_DEEMPHDENOM2_R, 0x0001e88c }, -#endif - - { AUD_DEEMPHDENOM2_R, 0x00000000 }, - { AUD_ERRLOGPERIOD_R, 0x00000fff }, - { AUD_ERRINTRPTTHSHLD1_R, 0x000003ff }, - { AUD_ERRINTRPTTHSHLD2_R, 0x000000ff }, - { AUD_ERRINTRPTTHSHLD3_R, 0x0000003f }, - { AUD_POLYPH80SCALEFAC, 0x00000003 }, - - // setup QAM registers - { AUD_PDF_DDS_CNST_BYTE2, 0x06 }, - { AUD_PDF_DDS_CNST_BYTE1, 0x82 }, - { AUD_PDF_DDS_CNST_BYTE0, 0x16 }, - { AUD_QAM_MODE, 0x05 }, - - { /* end of list */ }, - }; - static const struct rlist nicam_pal_i[] = { - { AUD_PDF_DDS_CNST_BYTE0, 0x12 }, - { AUD_PHACC_FREQ_8MSB, 0x3a }, - { AUD_PHACC_FREQ_8LSB, 0x93 }, - - { /* end of list */ }, - }; - static const struct rlist nicam_default[] = { - { AUD_PDF_DDS_CNST_BYTE0, 0x16 }, - { AUD_PHACC_FREQ_8MSB, 0x34 }, - { AUD_PHACC_FREQ_8LSB, 0x4c }, - - { /* end of list */ }, - }; - - set_audio_start(core, 0x0010, - EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO); - set_audio_registers(core, nicam_common); - switch (core->tvaudio) { - case WW_NICAM_I: - dprintk("%s PAL-I NICAM (status: unknown)\n",__FUNCTION__); - set_audio_registers(core, nicam_pal_i); - break; - case WW_NICAM_BGDKL: - dprintk("%s PAL-BGDK NICAM (status: unknown)\n",__FUNCTION__); - set_audio_registers(core, nicam_default); - break; - }; - set_audio_finish(core); -} -#endif static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo) { diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index dc997549b63..c44a079d08c 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1,5 +1,5 @@ /* - * $Id: cx88-video.c,v 1.70 2005/06/20 03:36:00 mkrufky Exp $ + * $Id: cx88-video.c,v 1.79 2005/07/07 14:17:47 mchehab Exp $ * * device driver for Conexant 2388x based TV cards * video4linux video interface @@ -86,13 +86,6 @@ static struct cx88_tvnorm tvnorms[] = { .id = V4L2_STD_NTSC_M_JP, .cxiformat = VideoFormatNTSCJapan, .cxoformat = 0x181f0008, -#if 0 - },{ - .name = "NTSC-4.43", - .id = FIXME, - .cxiformat = VideoFormatNTSC443, - .cxoformat = 0x181f0008, -#endif },{ .name = "PAL-BG", .id = V4L2_STD_PAL_BG, @@ -248,6 +241,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .default_value = 0, .type = V4L2_CTRL_TYPE_INTEGER, }, + .off = 0, .reg = MO_CONTR_BRIGHT, .mask = 0xff00, .shift = 8, @@ -674,231 +668,6 @@ static struct videobuf_queue_ops cx8800_video_qops = { /* ------------------------------------------------------------------ */ -#if 0 /* overlay support not finished yet */ -static u32* ov_risc_field(struct cx8800_dev *dev, struct cx8800_fh *fh, - u32 *rp, struct btcx_skiplist *skips, - u32 sync_line, int skip_even, int skip_odd) -{ - int line,maxy,start,end,skip,nskips; - u32 ri,ra; - u32 addr; - - /* sync instruction */ - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - addr = (unsigned long)dev->fbuf.base; - addr += dev->fbuf.fmt.bytesperline * fh->win.w.top; - addr += (fh->fmt->depth >> 3) * fh->win.w.left; - - /* scan lines */ - for (maxy = -1, line = 0; line < fh->win.w.height; - line++, addr += dev->fbuf.fmt.bytesperline) { - if ((line%2) == 0 && skip_even) - continue; - if ((line%2) == 1 && skip_odd) - continue; - - /* calculate clipping */ - if (line > maxy) - btcx_calc_skips(line, fh->win.w.width, &maxy, - skips, &nskips, fh->clips, fh->nclips); - - /* write out risc code */ - for (start = 0, skip = 0; start < fh->win.w.width; start = end) { - if (skip >= nskips) { - ri = RISC_WRITE; - end = fh->win.w.width; - } else if (start < skips[skip].start) { - ri = RISC_WRITE; - end = skips[skip].start; - } else { - ri = RISC_SKIP; - end = skips[skip].end; - skip++; - } - if (RISC_WRITE == ri) - ra = addr + (fh->fmt->depth>>3)*start; - else - ra = 0; - - if (0 == start) - ri |= RISC_SOL; - if (fh->win.w.width == end) - ri |= RISC_EOL; - ri |= (fh->fmt->depth>>3) * (end-start); - - *(rp++)=cpu_to_le32(ri); - if (0 != ra) - *(rp++)=cpu_to_le32(ra); - } - } - kfree(skips); - return rp; -} - -static int ov_risc_frame(struct cx8800_dev *dev, struct cx8800_fh *fh, - struct cx88_buffer *buf) -{ - struct btcx_skiplist *skips; - u32 instructions,fields; - u32 *rp; - int rc; - - /* skip list for window clipping */ - if (NULL == (skips = kmalloc(sizeof(*skips) * fh->nclips,GFP_KERNEL))) - return -ENOMEM; - - fields = 0; - if (V4L2_FIELD_HAS_TOP(fh->win.field)) - fields++; - if (V4L2_FIELD_HAS_BOTTOM(fh->win.field)) - fields++; - - /* estimate risc mem: worst case is (clip+1) * lines instructions - + syncs + jump (all 2 dwords) */ - instructions = (fh->nclips+1) * fh->win.w.height; - instructions += 3 + 4; - if ((rc = btcx_riscmem_alloc(dev->pci,&buf->risc,instructions*8)) < 0) { - kfree(skips); - return rc; - } - - /* write risc instructions */ - rp = buf->risc.cpu; - switch (fh->win.field) { - case V4L2_FIELD_TOP: - rp = ov_risc_field(dev, fh, rp, skips, 0, 0, 0); - break; - case V4L2_FIELD_BOTTOM: - rp = ov_risc_field(dev, fh, rp, skips, 0x200, 0, 0); - break; - case V4L2_FIELD_INTERLACED: - rp = ov_risc_field(dev, fh, rp, skips, 0, 0, 1); - rp = ov_risc_field(dev, fh, rp, skips, 0x200, 1, 0); - break; - default: - BUG(); - } - - /* save pointer to jmp instruction address */ - buf->risc.jmp = rp; - kfree(skips); - return 0; -} - -static int verify_window(struct cx8800_dev *dev, struct v4l2_window *win) -{ - enum v4l2_field field; - int maxw, maxh; - - if (NULL == dev->fbuf.base) - return -EINVAL; - if (win->w.width < 48 || win->w.height < 32) - return -EINVAL; - if (win->clipcount > 2048) - return -EINVAL; - - field = win->field; - maxw = norm_maxw(core->tvnorm); - maxh = norm_maxh(core->tvnorm); - - if (V4L2_FIELD_ANY == field) { - field = (win->w.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - win->field = field; - if (win->w.width > maxw) - win->w.width = maxw; - if (win->w.height > maxh) - win->w.height = maxh; - return 0; -} - -static int setup_window(struct cx8800_dev *dev, struct cx8800_fh *fh, - struct v4l2_window *win) -{ - struct v4l2_clip *clips = NULL; - int n,size,retval = 0; - - if (NULL == fh->fmt) - return -EINVAL; - retval = verify_window(dev,win); - if (0 != retval) - return retval; - - /* copy clips -- luckily v4l1 + v4l2 are binary - compatible here ...*/ - n = win->clipcount; - size = sizeof(*clips)*(n+4); - clips = kmalloc(size,GFP_KERNEL); - if (NULL == clips) - return -ENOMEM; - if (n > 0) { - if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) { - kfree(clips); - return -EFAULT; - } - } - - /* clip against screen */ - if (NULL != dev->fbuf.base) - n = btcx_screen_clips(dev->fbuf.fmt.width, dev->fbuf.fmt.height, - &win->w, clips, n); - btcx_sort_clips(clips,n); - - /* 4-byte alignments */ - switch (fh->fmt->depth) { - case 8: - case 24: - btcx_align(&win->w, clips, n, 3); - break; - case 16: - btcx_align(&win->w, clips, n, 1); - break; - case 32: - /* no alignment fixups needed */ - break; - default: - BUG(); - } - - down(&fh->vidq.lock); - if (fh->clips) - kfree(fh->clips); - fh->clips = clips; - fh->nclips = n; - fh->win = *win; -#if 0 - fh->ov.setup_ok = 1; -#endif - - /* update overlay if needed */ - retval = 0; -#if 0 - if (check_btres(fh, RESOURCE_OVERLAY)) { - struct bttv_buffer *new; - - new = videobuf_alloc(sizeof(*new)); - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - retval = bttv_switch_overlay(btv,fh,new); - } -#endif - up(&fh->vidq.lock); - return retval; -} -#endif /* ------------------------------------------------------------------ */ @@ -1327,9 +1096,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file, struct cx8800_fh *fh = file->private_data; struct cx8800_dev *dev = fh->dev; struct cx88_core *core = dev->core; -#if 0 - unsigned long flags; -#endif int err; if (video_debug > 1) @@ -1350,9 +1116,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file, V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE | -#if 0 - V4L2_CAP_VIDEO_OVERLAY | -#endif 0; if (UNSET != core->tuner_type) cap->capabilities |= V4L2_CAP_TUNER; @@ -1453,36 +1216,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } -#if 0 - /* needs review */ - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; - unsigned int n = a->index; - - memset(a,0,sizeof(*a)); - a->index = n; - switch (n) { - case 0: - if ((CX88_VMUX_TELEVISION == INPUT(n)->type) - || (CX88_VMUX_CABLE == INPUT(n)->type)) { - strcpy(a->name,"Television"); - // FIXME figure out if stereo received and set V4L2_AUDCAP_STEREO. - return 0; - } - break; - case 1: - if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q == core->board) { - strcpy(a->name,"Line In"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; - } - break; - } - // Audio input not available. - return -EINVAL; - } -#endif /* --- capture ioctls ---------------------------------------- */ case VIDIOC_ENUM_FMT: @@ -1592,6 +1325,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file, f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->freq; + + cx88_call_i2c_clients(dev->core,VIDIOC_G_FREQUENCY,f); + return 0; } case VIDIOC_S_FREQUENCY: @@ -1846,6 +1582,14 @@ static void cx8800_vid_timeout(unsigned long data) spin_unlock_irqrestore(&dev->slock,flags); } +static char *cx88_vid_irqs[32] = { + "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", + "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", + "y_oflow", "u_oflow", "v_oflow", "vbi_oflow", + "y_sync", "u_sync", "v_sync", "vbi_sync", + "opc_err", "par_err", "rip_err", "pci_abort", +}; + static void cx8800_vid_irq(struct cx8800_dev *dev) { struct cx88_core *core = dev->core; @@ -2013,7 +1757,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, { struct cx8800_dev *dev; struct cx88_core *core; - struct tuner_addr tun_addr; int err; dev = kmalloc(sizeof(*dev),GFP_KERNEL); @@ -2087,22 +1830,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, request_module("tuner"); if (core->tda9887_conf) request_module("tda9887"); - if (core->radio_type != UNSET) { - tun_addr.v4l2_tuner = V4L2_TUNER_RADIO; - tun_addr.type = core->radio_type; - tun_addr.addr = core->radio_addr; - cx88_call_i2c_clients(dev->core,TUNER_SET_TYPE_ADDR, &tun_addr); - } - if (core->tuner_type != UNSET) { - tun_addr.v4l2_tuner = V4L2_TUNER_ANALOG_TV; - tun_addr.type = core->tuner_type; - tun_addr.addr = core->tuner_addr; - cx88_call_i2c_clients(dev->core,TUNER_SET_TYPE_ADDR, &tun_addr); - } - - if (core->tda9887_conf) - cx88_call_i2c_clients(dev->core,TDA9887_SET_CONFIG,&core->tda9887_conf); - /* register v4l devices */ dev->video_dev = cx88_vdev_init(core,dev->pci, &cx8800_video_template,"video"); @@ -2212,10 +1939,8 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) } spin_unlock(&dev->slock); -#if 1 /* FIXME -- shutdown device */ cx88_shutdown(dev->core); -#endif pci_save_state(pci_dev); if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { @@ -2237,10 +1962,8 @@ static int cx8800_resume(struct pci_dev *pci_dev) pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); -#if 1 /* FIXME: re-initialize hardware */ cx88_reset(dev->core); -#endif /* restart video+vbi capture */ spin_lock(&dev->slock); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index bc5e038bc0f..307beae04f2 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -1,5 +1,5 @@ /* - * $Id: cx88.h,v 1.67 2005/07/01 12:10:07 mkrufky Exp $ + * $Id: cx88.h,v 1.68 2005/07/07 14:17:47 mchehab Exp $ * * v4l2 device driver for cx2388x based TV cards * @@ -82,9 +82,9 @@ struct cx88_tvnorm { static unsigned int inline norm_maxw(struct cx88_tvnorm *norm) { return (norm->id & V4L2_STD_625_50) ? 768 : 640; -// return (norm->id & V4L2_STD_625_50) ? 720 : 640; } + static unsigned int inline norm_maxh(struct cx88_tvnorm *norm) { return (norm->id & V4L2_STD_625_50) ? 576 : 480; @@ -220,7 +220,6 @@ struct cx88_subid { #define RESOURCE_VBI 4 #define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ -//#define BUFFER_TIMEOUT (HZ*2) /* buffer for one video frame */ struct cx88_buffer { @@ -336,11 +335,6 @@ struct cx8800_dev { struct pci_dev *pci; unsigned char pci_rev,pci_lat; -#if 0 - /* video overlay */ - struct v4l2_framebuffer fbuf; - struct cx88_buffer *screen; -#endif /* capture queues */ struct cx88_dmaqueue vidq; @@ -435,8 +429,6 @@ struct cx8802_dev { /* ----------------------------------------------------------- */ /* cx88-core.c */ -extern char *cx88_vid_irqs[32]; -extern char *cx88_mpeg_irqs[32]; extern void cx88_print_irqbits(char *name, char *tag, char **strings, u32 bits, u32 mask); extern void cx88_print_ioctl(char *name, unsigned int cmd); -- cgit v1.2.3 From 86ddd96fcd479ec4b718abaa661e5884f9dc9a33 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:47 -0700 Subject: [PATCH] v4l: SAA7134 hybrid DVB - Add new Typhoon DVB-T Cardbus. - DVB-T support for MD7134 cardbus and the PCI variants - initial DVB-T support for Lifeview Flydvb-t duo - DVB-T support for Philips TOUGH reference design - Don't turn off the xtal output of tda8274/75 in sleep mode - Let Kconfig decide whether to include frontend-specific code in saa7134-dvb. - Removed unused structures. Signed-off-by: Juergen Orschiedt Signed-off-by: Michael Krufky Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/saa7134/saa6752hs.c | 4 - drivers/media/video/saa7134/saa7134-dvb.c | 420 +++++++++++++++++++++++++++--- 2 files changed, 389 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index e6d0a18833d..79d05ea1b69 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -155,10 +155,6 @@ static struct v4l2_mpeg_compression param_defaults = .target = 256, }, -#if 0 - /* FIXME: size? via S_FMT? */ - .video_format = MPEG_VIDEO_FORMAT_D1, -#endif }; /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index aa8e2cf62d5..3959a571486 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1,8 +1,11 @@ /* - * $Id: saa7134-dvb.c,v 1.13 2005/06/12 04:19:19 mchehab Exp $ + * $Id: saa7134-dvb.c,v 1.18 2005/07/04 16:05:50 mkrufky Exp $ * * (c) 2004 Gerd Knorr [SuSE Labs] * + * Extended 3 / 2005 by Hartmut Hackmann to support various + * cards with the tda10046 DVB-T channel decoder + * * 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 @@ -30,20 +33,25 @@ #include "saa7134-reg.h" #include "saa7134.h" -#include "dvb-pll.h" -#include "mt352.h" -#include "mt352_priv.h" /* FIXME */ -#include "tda1004x.h" +#if CONFIG_DVB_MT352 +# include "mt352.h" +# include "mt352_priv.h" /* FIXME */ +#endif +#if CONFIG_DVB_TDA1004X +# include "tda1004x.h" +#endif MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); static unsigned int antenna_pwr = 0; + module_param(antenna_pwr, int, 0444); MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)"); /* ------------------------------------------------------------------ */ +#if CONFIG_DVB_MT352 static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) { u32 ok; @@ -138,48 +146,387 @@ static struct mt352_config pinnacle_300i = { .demod_init = mt352_pinnacle_init, .pll_set = mt352_pinnacle_pll_set, }; +#endif /* ------------------------------------------------------------------ */ -static int medion_cardbus_init(struct dvb_frontend* fe) +#if CONFIG_DVB_TDA1004X +static int philips_tu1216_pll_init(struct dvb_frontend *fe) { - /* anything to do here ??? */ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; + + /* setup PLL configuration */ + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + msleep(1); + return 0; } -static int medion_cardbus_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) +static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct saa7134_dev *dev = fe->dvb->priv; - struct v4l2_frequency f; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = + sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + /* determine charge pump */ + tuner_frequency = params->frequency + 36166000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) + cp = 3; + else if (tuner_frequency < 160000000) + cp = 5; + else if (tuner_frequency < 200000000) + cp = 6; + else if (tuner_frequency < 290000000) + cp = 3; + else if (tuner_frequency < 420000000) + cp = 5; + else if (tuner_frequency < 480000000) + cp = 6; + else if (tuner_frequency < 620000000) + cp = 3; + else if (tuner_frequency < 830000000) + cp = 5; + else if (tuner_frequency < 895000000) + cp = 7; + else + return -EINVAL; + + /* determine band */ + if (params->frequency < 49000000) + return -EINVAL; + else if (params->frequency < 161000000) + band = 1; + else if (params->frequency < 444000000) + band = 2; + else if (params->frequency < 861000000) + band = 4; + else + return -EINVAL; + + /* setup PLL filter */ + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + filter = 0; + break; + + case BANDWIDTH_7_MHZ: + filter = 0; + break; + + case BANDWIDTH_8_MHZ: + filter = 1; + break; - /* - * this instructs tuner.o to set the frequency, the call will - * end up in tuner_command(), VIDIOC_S_FREQUENCY switch. - * tda9887.o will see that as well. + default: + return -EINVAL; + } + + /* calculate divisor + * ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) */ - f.tuner = 0; - f.type = V4L2_TUNER_DIGITAL_TV; - f.frequency = params->frequency / 1000 * 16 / 1000; - saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f); + tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000; + + /* setup tuner buffer */ + tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); return 0; } -static int fe_request_firmware(struct dvb_frontend* fe, - const struct firmware **fw, char* name) +static int philips_tu1216_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) { struct saa7134_dev *dev = fe->dvb->priv; return request_firmware(fw, name, &dev->pci->dev); } +static struct tda1004x_config philips_tu1216_config = { + + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 1, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .pll_init = philips_tu1216_pll_init, + .pll_set = philips_tu1216_pll_set, + .pll_sleep = NULL, + .request_firmware = philips_tu1216_request_firmware, +}; + +/* ------------------------------------------------------------------ */ + + +static int philips_fmd1216_pll_init(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + /* this message is to set up ATC and ALC */ + static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 }; + struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; + + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + msleep(1); + + return 0; +} + +static void philips_fmd1216_analog(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + /* this message actually turns the tuner back to analog mode */ + static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 }; + struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; + + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); + msleep(1); + fmd1216_init[2] = 0x86; + fmd1216_init[3] = 0x54; + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); + msleep(1); +} + +static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct saa7134_dev *dev = fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = tuner_buf,.len = + sizeof(tuner_buf) }; + int tuner_frequency = 0; + int divider = 0; + u8 band, mode, cp; + + /* determine charge pump */ + tuner_frequency = params->frequency + 36130000; + if (tuner_frequency < 87000000) + return -EINVAL; + /* low band */ + else if (tuner_frequency < 180000000) { + band = 1; + mode = 7; + cp = 0; + } else if (tuner_frequency < 195000000) { + band = 1; + mode = 6; + cp = 1; + /* mid band */ + } else if (tuner_frequency < 366000000) { + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + band = 10; + } else { + band = 2; + } + mode = 7; + cp = 0; + } else if (tuner_frequency < 478000000) { + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + band = 10; + } else { + band = 2; + } + mode = 6; + cp = 1; + /* high band */ + } else if (tuner_frequency < 662000000) { + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + band = 12; + } else { + band = 4; + } + mode = 7; + cp = 0; + } else if (tuner_frequency < 840000000) { + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + band = 12; + } else { + band = 4; + } + mode = 6; + cp = 1; + } else { + if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + band = 12; + } else { + band = 4; + } + mode = 7; + cp = 1; + + } + /* calculate divisor */ + /* ((36166000 + Finput) / 166666) rounded! */ + divider = (tuner_frequency + 83333) / 166667; + + /* setup tuner buffer */ + tuner_buf[0] = (divider >> 8) & 0x7f; + tuner_buf[1] = divider & 0xff; + tuner_buf[2] = 0x80 | (cp << 6) | (mode << 3) | 4; + tuner_buf[3] = 0x40 | band; + + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + return 0; +} + + static struct tda1004x_config medion_cardbus = { - .demod_address = 0x08, /* not sure this is correct */ - .invert = 0, - .invert_oclk = 0, - .pll_init = medion_cardbus_init, - .pll_set = medion_cardbus_pll_set, - .request_firmware = fe_request_firmware, + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_IFO_AUTO_NEG, + .if_freq = TDA10046_FREQ_3613, + .pll_init = philips_fmd1216_pll_init, + .pll_set = philips_fmd1216_pll_set, + .pll_sleep = philips_fmd1216_analog, + .request_firmware = NULL, +}; + +/* ------------------------------------------------------------------ */ + +struct tda827x_data { + u32 lomax; + u8 spd; + u8 bs; + u8 bp; + u8 cp; + u8 gc3; + u8 div1p5; +}; + +static struct tda827x_data tda827x_dvbt[] = { + { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, + { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, + { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, + { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, + { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, + { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, + { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} +}; + +static int philips_tda827x_pll_init(struct dvb_frontend *fe) +{ + return 0; +} + +static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct saa7134_dev *dev = fe->dvb->priv; + u8 tuner_buf[14]; + + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf, + .len = sizeof(tuner_buf) }; + int i, tuner_freq, if_freq; + u32 N; + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + if_freq = 4000000; + break; + case BANDWIDTH_7_MHZ: + if_freq = 4500000; + break; + default: /* 8 MHz or Auto */ + if_freq = 5000000; + break; + } + tuner_freq = params->frequency + if_freq; + + i = 0; + while (tda827x_dvbt[i].lomax < tuner_freq) { + if(tda827x_dvbt[i + 1].lomax == 0) + break; + i++; + } + + N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); + tuner_buf[0] = 0; + tuner_buf[1] = (N>>8) | 0x40; + tuner_buf[2] = N & 0xff; + tuner_buf[3] = 0; + tuner_buf[4] = 0x52; + tuner_buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + + (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; + tuner_buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; + tuner_buf[7] = 0xbf; + tuner_buf[8] = 0x2a; + tuner_buf[9] = 0x05; + tuner_buf[10] = 0xff; + tuner_buf[11] = 0x00; + tuner_buf[12] = 0x00; + tuner_buf[13] = 0x40; + + tuner_msg.len = 14; + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(500); + /* correct CP value */ + tuner_buf[0] = 0x30; + tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp; + tuner_msg.len = 2; + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); + + return 0; +} + +static void philips_tda827x_pll_sleep(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 tda827x_sleep[] = { 0x30, 0xd0}; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep, + .len = sizeof(tda827x_sleep) }; + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); +} + +static struct tda1004x_config tda827x_lifeview_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .if_freq = TDA10046_FREQ_045, + .pll_init = philips_tda827x_pll_init, + .pll_set = philips_tda827x_pll_set, + .pll_sleep = philips_tda827x_pll_sleep, + .request_firmware = NULL, }; +#endif /* ------------------------------------------------------------------ */ @@ -197,18 +544,31 @@ static int dvb_init(struct saa7134_dev *dev) dev); switch (dev->board) { +#if CONFIG_DVB_MT352 case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: printk("%s: pinnacle 300i dvb setup\n",dev->name); dev->dvb.frontend = mt352_attach(&pinnacle_300i, &dev->i2c_adap); break; +#endif +#if CONFIG_DVB_TDA1004X case SAA7134_BOARD_MD7134: dev->dvb.frontend = tda10046_attach(&medion_cardbus, &dev->i2c_adap); - if (NULL == dev->dvb.frontend) - printk("%s: Hmm, looks like this is the old MD7134 " - "version without DVB-T support\n",dev->name); break; + case SAA7134_BOARD_PHILIPS_TOUGH: + dev->dvb.frontend = tda10046_attach(&philips_tu1216_config, + &dev->i2c_adap); + break; + case SAA7134_BOARD_FLYDVBTDUO: + dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config, + &dev->i2c_adap); + break; + case SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS: + dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config, + &dev->i2c_adap); + break; +#endif default: printk("%s: Huh? unknown DVB card?\n",dev->name); break; @@ -227,8 +587,6 @@ static int dvb_fini(struct saa7134_dev *dev) { static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; - printk("%s: %s\n",dev->name,__FUNCTION__); - switch (dev->board) { case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: /* otherwise we don't detect the tuner on next insmod */ -- cgit v1.2.3 From 5f8434a620383eec1115e73fdb18c53e049b26b9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:51 -0700 Subject: [PATCH] v4l: I2C BT832 - Removed unused structures. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/bt832.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c index 9a642c7de54..a070417e65e 100644 --- a/drivers/media/video/bt832.c +++ b/drivers/media/video/bt832.c @@ -138,25 +138,13 @@ int bt832_init(struct i2c_client *i2c_client_s) bt832_hexdump(i2c_client_s,buf); -#if 0 - // Full 30/25 Frame rate - printk("Full 30/25 Frame rate\n"); - buf[0]=BT832_VP_CONTROL0; // Reg.39 - buf[1]= 0x00; - if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) - printk("bt832: i2c i/o error FFR: rc == %d (should be 2)\n",rc); - - bt832_hexdump(i2c_client_s,buf); -#endif -#if 1 // for testing (even works when no camera attached) printk("bt832: *** Generate NTSC M Bars *****\n"); buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42 buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally if (2 != (rc = i2c_master_send(i2c_client_s,buf,2))) printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc); -#endif printk("Bt832: Camera Present: %s\n", (buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no"); -- cgit v1.2.3 From 60acbc99e82753b0baa64834435caf81eabc2501 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:52 -0700 Subject: [PATCH] v4l: I2C Infrared Remote Control - Removed unused structures. - CodingStyle rules applied to comments. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/common/ir-common.c | 255 +++++++++++++++++---------------------- 1 file changed, 110 insertions(+), 145 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c index 4adb2843f8b..ab7a1fba442 100644 --- a/drivers/media/common/ir-common.c +++ b/drivers/media/common/ir-common.c @@ -1,5 +1,5 @@ /* - * $Id: ir-common.c,v 1.10 2005/05/22 19:23:39 nsh Exp $ + * $Id: ir-common.c,v 1.11 2005/07/07 14:44:43 mchehab Exp $ * * some common structs and functions to handle infrared remotes via * input layer ... @@ -46,79 +46,49 @@ module_param(debug, int, 0644); /* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */ /* used by old (black) Hauppauge remotes */ IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = { - [ 0x00 ] = KEY_KP0, // 0 - [ 0x01 ] = KEY_KP1, // 1 - [ 0x02 ] = KEY_KP2, // 2 - [ 0x03 ] = KEY_KP3, // 3 - [ 0x04 ] = KEY_KP4, // 4 - [ 0x05 ] = KEY_KP5, // 5 - [ 0x06 ] = KEY_KP6, // 6 - [ 0x07 ] = KEY_KP7, // 7 - [ 0x08 ] = KEY_KP8, // 8 - [ 0x09 ] = KEY_KP9, // 9 - - [ 0x0b ] = KEY_CHANNEL, // channel / program (japan: 11) - [ 0x0c ] = KEY_POWER, // standby - [ 0x0d ] = KEY_MUTE, // mute / demute - [ 0x0f ] = KEY_TV, // display - [ 0x10 ] = KEY_VOLUMEUP, // volume + - [ 0x11 ] = KEY_VOLUMEDOWN, // volume - - [ 0x12 ] = KEY_BRIGHTNESSUP, // brightness + - [ 0x13 ] = KEY_BRIGHTNESSDOWN, // brightness - - [ 0x1e ] = KEY_SEARCH, // search + - [ 0x20 ] = KEY_CHANNELUP, // channel / program + - [ 0x21 ] = KEY_CHANNELDOWN, // channel / program - - [ 0x22 ] = KEY_CHANNEL, // alt / channel - [ 0x23 ] = KEY_LANGUAGE, // 1st / 2nd language - [ 0x26 ] = KEY_SLEEP, // sleeptimer - [ 0x2e ] = KEY_MENU, // 2nd controls (USA: menu) - [ 0x30 ] = KEY_PAUSE, // pause - [ 0x32 ] = KEY_REWIND, // rewind - [ 0x33 ] = KEY_GOTO, // go to - [ 0x35 ] = KEY_PLAY, // play - [ 0x36 ] = KEY_STOP, // stop - [ 0x37 ] = KEY_RECORD, // recording - [ 0x3c ] = KEY_TEXT, // teletext submode (Japan: 12) - [ 0x3d ] = KEY_SUSPEND, // system standby - -#if 0 /* FIXME */ - [ 0x0a ] = KEY_RESERVED, // 1/2/3 digits (japan: 10) - [ 0x0e ] = KEY_RESERVED, // P.P. (personal preference) - [ 0x14 ] = KEY_RESERVED, // colour saturation + - [ 0x15 ] = KEY_RESERVED, // colour saturation - - [ 0x16 ] = KEY_RESERVED, // bass + - [ 0x17 ] = KEY_RESERVED, // bass - - [ 0x18 ] = KEY_RESERVED, // treble + - [ 0x19 ] = KEY_RESERVED, // treble - - [ 0x1a ] = KEY_RESERVED, // balance right - [ 0x1b ] = KEY_RESERVED, // balance left - [ 0x1c ] = KEY_RESERVED, // contrast + - [ 0x1d ] = KEY_RESERVED, // contrast - - [ 0x1f ] = KEY_RESERVED, // tint/hue + - [ 0x24 ] = KEY_RESERVED, // spacial stereo on/off - [ 0x25 ] = KEY_RESERVED, // mono / stereo (USA) - [ 0x27 ] = KEY_RESERVED, // tint / hue - - [ 0x28 ] = KEY_RESERVED, // RF switch/PIP select - [ 0x29 ] = KEY_RESERVED, // vote - [ 0x2a ] = KEY_RESERVED, // timed page/channel clck - [ 0x2b ] = KEY_RESERVED, // increment (USA) - [ 0x2c ] = KEY_RESERVED, // decrement (USA) - [ 0x2d ] = KEY_RESERVED, // - [ 0x2f ] = KEY_RESERVED, // PIP shift - [ 0x31 ] = KEY_RESERVED, // erase - [ 0x34 ] = KEY_RESERVED, // wind - [ 0x38 ] = KEY_RESERVED, // external 1 - [ 0x39 ] = KEY_RESERVED, // external 2 - [ 0x3a ] = KEY_RESERVED, // PIP display mode - [ 0x3b ] = KEY_RESERVED, // view data mode / advance - [ 0x3e ] = KEY_RESERVED, // crispener on/off - [ 0x3f ] = KEY_RESERVED, // system select -#endif + /* Keys 0 to 9 */ + [ 0x00 ] = KEY_KP0, + [ 0x01 ] = KEY_KP1, + [ 0x02 ] = KEY_KP2, + [ 0x03 ] = KEY_KP3, + [ 0x04 ] = KEY_KP4, + [ 0x05 ] = KEY_KP5, + [ 0x06 ] = KEY_KP6, + [ 0x07 ] = KEY_KP7, + [ 0x08 ] = KEY_KP8, + [ 0x09 ] = KEY_KP9, + + [ 0x0b ] = KEY_CHANNEL, /* channel / program (japan: 11) */ + [ 0x0c ] = KEY_POWER, /* standby */ + [ 0x0d ] = KEY_MUTE, /* mute / demute */ + [ 0x0f ] = KEY_TV, /* display */ + [ 0x10 ] = KEY_VOLUMEUP, + [ 0x11 ] = KEY_VOLUMEDOWN, + [ 0x12 ] = KEY_BRIGHTNESSUP, + [ 0x13 ] = KEY_BRIGHTNESSDOWN, + [ 0x1e ] = KEY_SEARCH, /* search + */ + [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */ + [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */ + [ 0x22 ] = KEY_CHANNEL, /* alt / channel */ + [ 0x23 ] = KEY_LANGUAGE, /* 1st / 2nd language */ + [ 0x26 ] = KEY_SLEEP, /* sleeptimer */ + [ 0x2e ] = KEY_MENU, /* 2nd controls (USA: menu) */ + [ 0x30 ] = KEY_PAUSE, + [ 0x32 ] = KEY_REWIND, + [ 0x33 ] = KEY_GOTO, + [ 0x35 ] = KEY_PLAY, + [ 0x36 ] = KEY_STOP, + [ 0x37 ] = KEY_RECORD, /* recording */ + [ 0x3c ] = KEY_TEXT, /* teletext submode (Japan: 12) */ + [ 0x3d ] = KEY_SUSPEND, /* system standby */ + }; EXPORT_SYMBOL_GPL(ir_codes_rc5_tv); /* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { + /* Keys 0 to 9 */ + [ 18 ] = KEY_KP0, [ 5 ] = KEY_KP1, [ 6 ] = KEY_KP2, [ 7 ] = KEY_KP3, @@ -128,39 +98,31 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { [ 13 ] = KEY_KP7, [ 14 ] = KEY_KP8, [ 15 ] = KEY_KP9, - [ 18 ] = KEY_KP0, [ 0 ] = KEY_POWER, -// [ 27 ] = MTS button - [ 2 ] = KEY_TUNER, // TV/FM + [ 2 ] = KEY_TUNER, /* TV/FM */ [ 30 ] = KEY_VIDEO, -// [ 22 ] = display button [ 4 ] = KEY_VOLUMEUP, [ 8 ] = KEY_VOLUMEDOWN, [ 12 ] = KEY_CHANNELUP, [ 16 ] = KEY_CHANNELDOWN, - [ 3 ] = KEY_ZOOM, // fullscreen - [ 31 ] = KEY_SUBTITLE, // closed caption/teletext + [ 3 ] = KEY_ZOOM, /* fullscreen */ + [ 31 ] = KEY_SUBTITLE, /* closed caption/teletext */ [ 32 ] = KEY_SLEEP, -// [ 41 ] = boss key [ 20 ] = KEY_MUTE, [ 43 ] = KEY_RED, [ 44 ] = KEY_GREEN, [ 45 ] = KEY_YELLOW, [ 46 ] = KEY_BLUE, - [ 24 ] = KEY_KPPLUS, //fine tune + - [ 25 ] = KEY_KPMINUS, //fine tune - -// [ 42 ] = picture in picture + [ 24 ] = KEY_KPPLUS, /* fine tune + */ + [ 25 ] = KEY_KPMINUS, /* fine tune - */ [ 33 ] = KEY_KPDOT, [ 19 ] = KEY_KPENTER, -// [ 17 ] = recall [ 34 ] = KEY_BACK, [ 35 ] = KEY_PLAYPAUSE, [ 36 ] = KEY_NEXT, -// [ 37 ] = time shifting [ 38 ] = KEY_STOP, [ 39 ] = KEY_RECORD -// [ 40 ] = snapshot }; EXPORT_SYMBOL_GPL(ir_codes_winfast); @@ -174,54 +136,61 @@ EXPORT_SYMBOL_GPL(ir_codes_empty); * slightly different versions), shipped with cx88+ivtv cards. * almost rc5 coding, but some non-standard keys */ IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = { - [ 0x00 ] = KEY_KP0, // 0 - [ 0x01 ] = KEY_KP1, // 1 - [ 0x02 ] = KEY_KP2, // 2 - [ 0x03 ] = KEY_KP3, // 3 - [ 0x04 ] = KEY_KP4, // 4 - [ 0x05 ] = KEY_KP5, // 5 - [ 0x06 ] = KEY_KP6, // 6 - [ 0x07 ] = KEY_KP7, // 7 - [ 0x08 ] = KEY_KP8, // 8 - [ 0x09 ] = KEY_KP9, // 9 - [ 0x0a ] = KEY_TEXT, // keypad asterisk as well - [ 0x0b ] = KEY_RED, // red button - [ 0x0c ] = KEY_RADIO, // radio - [ 0x0d ] = KEY_MENU, // menu - [ 0x0e ] = KEY_SUBTITLE, // also the # key - [ 0x0f ] = KEY_MUTE, // mute - [ 0x10 ] = KEY_VOLUMEUP, // volume + - [ 0x11 ] = KEY_VOLUMEDOWN, // volume - - [ 0x12 ] = KEY_PREVIOUS, // previous channel - [ 0x14 ] = KEY_UP, // up - [ 0x15 ] = KEY_DOWN, // down - [ 0x16 ] = KEY_LEFT, // left - [ 0x17 ] = KEY_RIGHT, // right - [ 0x18 ] = KEY_VIDEO, // Videos - [ 0x19 ] = KEY_AUDIO, // Music - [ 0x1a ] = KEY_MHP, // Pictures - presume this means "Multimedia Home Platform"- no "PICTURES" key in input.h - [ 0x1b ] = KEY_EPG, // Guide - [ 0x1c ] = KEY_TV, // TV - [ 0x1e ] = KEY_NEXTSONG, // skip >| - [ 0x1f ] = KEY_EXIT, // back/exit - [ 0x20 ] = KEY_CHANNELUP, // channel / program + - [ 0x21 ] = KEY_CHANNELDOWN, // channel / program - - [ 0x22 ] = KEY_CHANNEL, // source (old black remote) - [ 0x24 ] = KEY_PREVIOUSSONG, // replay |< - [ 0x25 ] = KEY_ENTER, // OK - [ 0x26 ] = KEY_SLEEP, // minimize (old black remote) - [ 0x29 ] = KEY_BLUE, // blue key - [ 0x2e ] = KEY_GREEN, // green button - [ 0x30 ] = KEY_PAUSE, // pause - [ 0x32 ] = KEY_REWIND, // backward << - [ 0x34 ] = KEY_FASTFORWARD, // forward >> - [ 0x35 ] = KEY_PLAY, // play - [ 0x36 ] = KEY_STOP, // stop - [ 0x37 ] = KEY_RECORD, // recording - [ 0x38 ] = KEY_YELLOW, // yellow key - [ 0x3b ] = KEY_SELECT, // top right button - [ 0x3c ] = KEY_ZOOM, // full - [ 0x3d ] = KEY_POWER, // system power (green button) + /* Keys 0 to 9 */ + [ 0x00 ] = KEY_KP0, + [ 0x01 ] = KEY_KP1, + [ 0x02 ] = KEY_KP2, + [ 0x03 ] = KEY_KP3, + [ 0x04 ] = KEY_KP4, + [ 0x05 ] = KEY_KP5, + [ 0x06 ] = KEY_KP6, + [ 0x07 ] = KEY_KP7, + [ 0x08 ] = KEY_KP8, + [ 0x09 ] = KEY_KP9, + + [ 0x0a ] = KEY_TEXT, /* keypad asterisk as well */ + [ 0x0b ] = KEY_RED, /* red button */ + [ 0x0c ] = KEY_RADIO, + [ 0x0d ] = KEY_MENU, + [ 0x0e ] = KEY_SUBTITLE, /* also the # key */ + [ 0x0f ] = KEY_MUTE, + [ 0x10 ] = KEY_VOLUMEUP, + [ 0x11 ] = KEY_VOLUMEDOWN, + [ 0x12 ] = KEY_PREVIOUS, /* previous channel */ + [ 0x14 ] = KEY_UP, + [ 0x15 ] = KEY_DOWN, + [ 0x16 ] = KEY_LEFT, + [ 0x17 ] = KEY_RIGHT, + [ 0x18 ] = KEY_VIDEO, /* Videos */ + [ 0x19 ] = KEY_AUDIO, /* Music */ + /* 0x1a: Pictures - presume this means + "Multimedia Home Platform" - + no "PICTURES" key in input.h + */ + [ 0x1a ] = KEY_MHP, + + [ 0x1b ] = KEY_EPG, /* Guide */ + [ 0x1c ] = KEY_TV, + [ 0x1e ] = KEY_NEXTSONG, /* skip >| */ + [ 0x1f ] = KEY_EXIT, /* back/exit */ + [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */ + [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */ + [ 0x22 ] = KEY_CHANNEL, /* source (old black remote) */ + [ 0x24 ] = KEY_PREVIOUSSONG, /* replay |< */ + [ 0x25 ] = KEY_ENTER, /* OK */ + [ 0x26 ] = KEY_SLEEP, /* minimize (old black remote) */ + [ 0x29 ] = KEY_BLUE, /* blue key */ + [ 0x2e ] = KEY_GREEN, /* green button */ + [ 0x30 ] = KEY_PAUSE, /* pause */ + [ 0x32 ] = KEY_REWIND, /* backward << */ + [ 0x34 ] = KEY_FASTFORWARD, /* forward >> */ + [ 0x35 ] = KEY_PLAY, + [ 0x36 ] = KEY_STOP, + [ 0x37 ] = KEY_RECORD, /* recording */ + [ 0x38 ] = KEY_YELLOW, /* yellow key */ + [ 0x3b ] = KEY_SELECT, /* top right button */ + [ 0x3c ] = KEY_ZOOM, /* full */ + [ 0x3d ] = KEY_POWER, /* system power (green button) */ }; EXPORT_SYMBOL(ir_codes_hauppauge_new); @@ -237,9 +206,9 @@ IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = { [ 10 ] = KEY_KP8, [ 18 ] = KEY_KP9, - [ 3 ] = KEY_TUNER, // TV/FM - [ 7 ] = KEY_SEARCH, // scan - [ 28 ] = KEY_ZOOM, // full screen + [ 3 ] = KEY_TUNER, /* TV/FM */ + [ 7 ] = KEY_SEARCH, /* scan */ + [ 28 ] = KEY_ZOOM, /* full screen */ [ 30 ] = KEY_POWER, [ 23 ] = KEY_VOLUMEDOWN, [ 31 ] = KEY_VOLUMEUP, @@ -247,14 +216,14 @@ IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = { [ 22 ] = KEY_CHANNELUP, [ 24 ] = KEY_MUTE, - [ 0 ] = KEY_LIST, // source - [ 19 ] = KEY_INFO, // loop - [ 16 ] = KEY_LAST, // +100 - [ 13 ] = KEY_CLEAR, // reset - [ 12 ] = BTN_RIGHT, // fun++ - [ 4 ] = BTN_LEFT, // fun-- - [ 14 ] = KEY_GOTO, // function - [ 15 ] = KEY_STOP, // freeze + [ 0 ] = KEY_LIST, /* source */ + [ 19 ] = KEY_INFO, /* loop */ + [ 16 ] = KEY_LAST, /* +100 */ + [ 13 ] = KEY_CLEAR, /* reset */ + [ 12 ] = BTN_RIGHT, /* fun++ */ + [ 4 ] = BTN_LEFT, /* fun-- */ + [ 14 ] = KEY_GOTO, /* function */ + [ 15 ] = KEY_STOP, /* freeze */ }; EXPORT_SYMBOL(ir_codes_pixelview); @@ -321,10 +290,6 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir, ir->keypressed = 1; ir_input_key_event(dev,ir); } -#if 0 - /* maybe do something like this ??? */ - input_event(a, EV_IR, ir->ir_type, ir->ir_raw); -#endif } /* -------------------------------------------------------------------------- */ -- cgit v1.2.3 From ebe4c6fa535b0410e58e9c8352320896d07e2efb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:53 -0700 Subject: [PATCH] v4l: I2C Miscelaneous - Removed unused structures. - CodingStyle rules applied to comments. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/msp3400.c | 25 ++++--------------------- drivers/media/video/tda7432.c | 13 ------------- drivers/media/video/tda9875.c | 13 ------------- drivers/media/video/tvaudio.c | 5 ----- 4 files changed, 4 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index b4ee9dfe6d4..6239254db27 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -567,10 +567,6 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode) switch (audmode) { case V4L2_TUNER_MODE_STEREO: src = 0x0020 | nicam; -#if 0 - /* spatial effect */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000); -#endif break; case V4L2_TUNER_MODE_MONO: if (msp->mode == MSP_MODE_AM_NICAM) { @@ -741,16 +737,14 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout) set_current_state(TASK_INTERRUPTIBLE); schedule(); } else { -#if 0 - /* hmm, that one doesn't return on wakeup ... */ - msleep_interruptible(timeout); -#else set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(msecs_to_jiffies(timeout)); -#endif } } - try_to_freeze(); + if (current->flags & PF_FREEZE) { + refrigerator (); + } + remove_wait_queue(&msp->wq, &wait); return msp->restart; } @@ -1154,17 +1148,10 @@ static int msp3410d_thread(void *data) MSP_CARRIER(10.7)); /* scart routing */ msp3400c_set_scart(client,SCART_IN2,0); -#if 0 - /* radio from SCART_IN2 */ - msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0220); - msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0220); -#else /* msp34xx does radio decoding */ msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020); msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020); msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020); -#endif break; case 0x0003: case 0x0004: @@ -1507,10 +1494,6 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind) return -1; } -#if 0 - /* this will turn on a 1kHz beep - might be useful for debugging... */ - msp3400c_write(c,I2C_MSP3400C_DFP, 0x0014, 0x1040); -#endif msp3400c_setvolume(c, msp->muted, msp->volume, msp->balance); snprintf(c->name, sizeof(c->name), "MSP34%02d%c-%c%d", diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 07ba6d3ed08..7cb1fb3e66f 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -243,19 +243,6 @@ static int tda7432_write(struct i2c_client *client, int subaddr, int val) } /* I don't think we ever actually _read_ the chip... */ -#if 0 -static int tda7432_read(struct i2c_client *client) -{ - unsigned char buffer; - d2printk("tda7432: In tda7432_read\n"); - if (1 != i2c_master_recv(client,&buffer,1)) { - printk(KERN_WARNING "tda7432: I/O error, trying (read)\n"); - return -1; - } - dprintk("tda7432: Read 0x%02x\n", buffer); - return buffer; -} -#endif static int tda7432_set(struct i2c_client *client) { diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 97b113e070f..566e1a5ca13 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -123,19 +123,6 @@ static int tda9875_write(struct i2c_client *client, int subaddr, unsigned char v return 0; } -#if 0 -static int tda9875_read(struct i2c_client *client) -{ - unsigned char buffer; - dprintk("In tda9875_read\n"); - if (1 != i2c_master_recv(client,&buffer,1)) { - printk(KERN_WARNING "tda9875: I/O error, trying (read)\n"); - return -1; - } - dprintk("Read 0x%02x\n", buffer); - return buffer; -} -#endif static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg) { diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 9a493bea76d..d8b78f1d686 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -864,13 +864,8 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) * But changing the mode to VIDEO_SOUND_MONO would switch * external 4052 multiplexer in audio_hook(). */ -#if 0 - if((nsr & 0x02) && !(dsr & 0x10)) /* NSR.S/MB=1 and DSR.AMSTAT=0 */ - mode |= VIDEO_SOUND_STEREO; -#else if(nsr & 0x02) /* NSR.S/MB=1 */ mode |= VIDEO_SOUND_STEREO; -#endif if(nsr & 0x01) /* NSR.D/SB=1 */ mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } else { -- cgit v1.2.3 From f7ce3cc67052de63a29bad90110640b687d12058 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:55 -0700 Subject: [PATCH] v4l: I2C Tuner - Fixed a trouble on tuner-core that generates erros on computers with more than one TV card. - Rename tuner structures fields. - Tail spaces removed. - I2C cleanups and converged to a basic reference structure. - Removed unused structures. - Fix setting frequency on tda8290. - Added code for TEA5767 autodetection. - Standby mode support implemented. It is used to disable a non used tuner. Currenlty implemented on tea5767. - New macro: set_type disables other tuner when changing mode. - Some cleanups. - Use 50 kHz step when tunning radio for most tuners to improve precision. Signed-off-by: Fabien Perrot Signed-off-by: Michael Krufky Signed-off-By: Nickolay V. Shmyrev Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/mt20xx.c | 16 - drivers/media/video/tda8290.c | 13 +- drivers/media/video/tda9887.c | 9 - drivers/media/video/tea5767.c | 158 +++++---- drivers/media/video/tuner-core.c | 707 +++++++++++++++++++++---------------- drivers/media/video/tuner-simple.c | 85 ++--- 6 files changed, 524 insertions(+), 464 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 9c005cb128d..2fb7c2d1787 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -511,22 +511,6 @@ int microtune_init(struct i2c_client *c) tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", company_code,buf[0x13],buf[0x14]); -#if 0 - /* seems to cause more problems than it solves ... */ - switch (company_code) { - case 0x30bf: - case 0x3cbf: - case 0x3dbf: - case 0x4d54: - case 0x8e81: - case 0x8e91: - /* ok (?) */ - break; - default: - tuner_warn("tuner: microtune: unknown companycode\n"); - return 0; - } -#endif if (buf[0x13] < ARRAY_SIZE(microtune_part) && NULL != microtune_part[buf[0x13]]) diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index f59d4601cc6..a8b6a8df510 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -1,5 +1,5 @@ /* - * $Id: tda8290.c,v 1.11 2005/06/18 06:09:06 nsh Exp $ + * $Id: tda8290.c,v 1.15 2005/07/08 20:21:33 mchehab Exp $ * * i2c tv tuner chip device driver * controls the philips tda8290+75 tuner chip combo. @@ -136,15 +136,12 @@ static int tda8290_tune(struct i2c_client *c) return 0; } -static void set_frequency(struct tuner *t, u16 ifc) +static void set_frequency(struct tuner *t, u16 ifc, unsigned int freq) { - u32 freq; u32 N; if (t->mode == V4L2_TUNER_RADIO) - freq = t->freq / 1000; - else - freq = t->freq; + freq = freq / 1000; N = (((freq<<3)+ifc)&0x3fffc); @@ -187,14 +184,14 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) struct tuner *t = i2c_get_clientdata(c); set_audio(t); - set_frequency(t, 864); + set_frequency(t, 864, freq); tda8290_tune(c); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); - set_frequency(t, 704); + set_frequency(t, 704, freq); tda8290_tune(c); } diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index ee35562f4d1..108c3ad7d62 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -569,15 +569,6 @@ static int tda9887_configure(struct tda9887 *t) tda9887_set_config(t,buf); tda9887_set_insmod(t,buf); -#if 0 - /* This as-is breaks some cards, must be fixed in a - * card-specific way, probably using TDA9887_SET_CONFIG to - * turn on/off port2 */ - if (t->std & V4L2_STD_SECAM_L) { - /* secam fixup (FIXME: move this to tvnorms array?) */ - buf[1] &= ~cOutputPort2Inactive; - } -#endif dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n", buf[1],buf[2],buf[3]); diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index a29f08f81f6..b53c748caf2 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -2,7 +2,7 @@ * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview * I2C address is allways 0xC0. * - * $Id: tea5767.c,v 1.11 2005/06/21 15:40:33 mchehab Exp $ + * $Id: tea5767.c,v 1.18 2005/07/07 03:02:55 mchehab Exp $ * * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br) * This code is placed under the terms of the GNU General Public License @@ -11,23 +11,11 @@ * from their contributions on DScaler. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include - +#include +#include +#include #include - -/* Declared at tuner-core.c */ -extern unsigned int tuner_debug; #define PREFIX "TEA5767 " @@ -38,8 +26,8 @@ extern unsigned int tuner_debug; ******************************/ /* First register */ -#define TEA5767_MUTE 0x80 /* Mutes output */ -#define TEA5767_SEARCH 0x40 /* Activates station search */ +#define TEA5767_MUTE 0x80 /* Mutes output */ +#define TEA5767_SEARCH 0x40 /* Activates station search */ /* Bits 0-5 for divider MSB */ /* Second register */ @@ -130,6 +118,14 @@ extern unsigned int tuner_debug; /* Reserved for future extensions */ #define TEA5767_RESERVED_MASK 0xff +enum tea5767_xtal_freq { + TEA5767_LOW_LO_32768 = 0, + TEA5767_HIGH_LO_32768 = 1, + TEA5767_LOW_LO_13MHz = 2, + TEA5767_HIGH_LO_13MHz = 3, +}; + + /*****************************************************************************/ static void set_tv_freq(struct i2c_client *c, unsigned int freq) @@ -153,103 +149,112 @@ static void tea5767_status_dump(unsigned char *buffer) else printk(PREFIX "Tuner not at band limit\n"); - div=((buffer[0]&0x3f)<<8) | buffer[1]; + div = ((buffer[0] & 0x3f) << 8) | buffer[1]; switch (TEA5767_HIGH_LO_32768) { case TEA5767_HIGH_LO_13MHz: - frq = 1000*(div*50-700-225)/4; /* Freq in KHz */ + frq = 1000 * (div * 50 - 700 - 225) / 4; /* Freq in KHz */ break; case TEA5767_LOW_LO_13MHz: - frq = 1000*(div*50+700+225)/4; /* Freq in KHz */ + frq = 1000 * (div * 50 + 700 + 225) / 4; /* Freq in KHz */ break; case TEA5767_LOW_LO_32768: - frq = 1000*(div*32768/1000+700+225)/4; /* Freq in KHz */ + frq = 1000 * (div * 32768 / 1000 + 700 + 225) / 4; /* Freq in KHz */ break; case TEA5767_HIGH_LO_32768: default: - frq = 1000*(div*32768/1000-700-225)/4; /* Freq in KHz */ + frq = 1000 * (div * 32768 / 1000 - 700 - 225) / 4; /* Freq in KHz */ break; } - buffer[0] = (div>>8) & 0x3f; - buffer[1] = div & 0xff; + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n", - frq/1000,frq%1000,div); + frq / 1000, frq % 1000, div); if (TEA5767_STEREO_MASK & buffer[2]) printk(PREFIX "Stereo\n"); else printk(PREFIX "Mono\n"); - printk(PREFIX "IF Counter = %d\n",buffer[2] & TEA5767_IF_CNTR_MASK); + printk(PREFIX "IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK); - printk(PREFIX "ADC Level = %d\n",(buffer[3] & TEA5767_ADC_LEVEL_MASK)>>4); + printk(PREFIX "ADC Level = %d\n", + (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4); - printk(PREFIX "Chip ID = %d\n",(buffer[3] & TEA5767_CHIP_ID_MASK)); + printk(PREFIX "Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK)); - printk(PREFIX "Reserved = 0x%02x\n",(buffer[4] & TEA5767_RESERVED_MASK)); + printk(PREFIX "Reserved = 0x%02x\n", + (buffer[4] & TEA5767_RESERVED_MASK)); } /* Freq should be specifyed at 62.5 Hz */ static void set_radio_freq(struct i2c_client *c, unsigned int frq) { struct tuner *t = i2c_get_clientdata(c); - unsigned char buffer[5]; + unsigned char buffer[5]; unsigned div; int rc; - if ( tuner_debug ) - printk(PREFIX "radio freq counter %d\n",frq); + tuner_dbg (PREFIX "radio freq counter %d\n", frq); /* Rounds freq to next decimal value - for 62.5 KHz step */ /* frq = 20*(frq/16)+radio_frq[frq%16]; */ buffer[2] = TEA5767_PORT1_HIGH; - buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; - buffer[4]=0; + buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | + TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; + buffer[4] = 0; + + if (t->mode == T_STANDBY) { + tuner_dbg("TEA5767 set to standby mode\n"); + buffer[3] |= TEA5767_STDBY; + } if (t->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5767 set to mono\n"); buffer[2] |= TEA5767_MONO; - } else - tuner_dbg("TEA5767 set to stereo\n"); + } else { + tuner_dbg("TEA5767 set to stereo\n"); + } - switch (t->type) { + /* Should be replaced */ + switch (TEA5767_HIGH_LO_32768) { case TEA5767_HIGH_LO_13MHz: - tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); + tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; buffer[4] |= TEA5767_PLLREF_ENABLE; - div = (frq*4/16+700+225+25)/50; + div = (frq * 4 / 16 + 700 + 225 + 25) / 50; break; case TEA5767_LOW_LO_13MHz: - tuner_dbg("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); + tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); buffer[4] |= TEA5767_PLLREF_ENABLE; - div = (frq*4/16-700-225+25)/50; + div = (frq * 4 / 16 - 700 - 225 + 25) / 50; break; case TEA5767_LOW_LO_32768: - tuner_dbg("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); + tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); buffer[3] |= TEA5767_XTAL_32768; /* const 700=4000*175 Khz - to adjust freq to right value */ - div = (1000*(frq*4/16-700-225)+16384)>>15; + div = (1000 * (frq * 4 / 16 - 700 - 225) + 16384) >> 15; break; case TEA5767_HIGH_LO_32768: default: - tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n"); + tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; buffer[3] |= TEA5767_XTAL_32768; - div = (1000*(frq*4/16+700+225)+16384)>>15; + div = (1000 * (frq * 4 / 16 + 700 + 225) + 16384) >> 15; break; } - buffer[0] = (div>>8) & 0x3f; - buffer[1] = div & 0xff; + buffer[0] = (div >> 8) & 0x3f; + buffer[1] = div & 0xff; - if ( tuner_debug ) + if (tuner_debug) tea5767_status_dump(buffer); - if (5 != (rc = i2c_master_send(c,buffer,5))) - tuner_warn("i2c i/o error: rc == %d (should be 5)\n",rc); + if (5 != (rc = i2c_master_send(c, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); } static int tea5767_signal(struct i2c_client *c) @@ -258,11 +263,11 @@ static int tea5767_signal(struct i2c_client *c) int rc; struct tuner *t = i2c_get_clientdata(c); - memset(buffer,0,sizeof(buffer)); - if (5 != (rc = i2c_master_recv(c,buffer,5))) - tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc); + memset(buffer, 0, sizeof(buffer)); + if (5 != (rc = i2c_master_recv(c, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); - return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) <<(13-4)); + return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << (13 - 4)); } static int tea5767_stereo(struct i2c_client *c) @@ -271,47 +276,46 @@ static int tea5767_stereo(struct i2c_client *c) int rc; struct tuner *t = i2c_get_clientdata(c); - memset(buffer,0,sizeof(buffer)); - if (5 != (rc = i2c_master_recv(c,buffer,5))) - tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc); + memset(buffer, 0, sizeof(buffer)); + if (5 != (rc = i2c_master_recv(c, buffer, 5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); rc = buffer[2] & TEA5767_STEREO_MASK; - if ( tuner_debug ) - tuner_dbg("TEA5767 radio ST GET = %02x\n", rc); + tuner_dbg("TEA5767 radio ST GET = %02x\n", rc); - return ( (buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO: 0); + return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0); } -int tea_detection(struct i2c_client *c) +int tea5767_autodetection(struct i2c_client *c) { - unsigned char buffer[5]= { 0xff, 0xff, 0xff, 0xff, 0xff }; + unsigned char buffer[5] = { 0xff, 0xff, 0xff, 0xff, 0xff }; int rc; struct tuner *t = i2c_get_clientdata(c); - if (5 != (rc = i2c_master_recv(c,buffer,5))) { - tuner_warn ( "it is not a TEA5767. Received %i chars.\n",rc ); + if (5 != (rc = i2c_master_recv(c, buffer, 5))) { + tuner_warn("it is not a TEA5767. Received %i chars.\n", rc); return EINVAL; } /* If all bytes are the same then it's a TV tuner and not a tea5767 chip. */ - if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && - buffer[0] == buffer[3] && buffer[0] == buffer[4]) { - tuner_warn ( "All bytes are equal. It is not a TEA5767\n" ); + if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && + buffer[0] == buffer[3] && buffer[0] == buffer[4]) { + tuner_warn("All bytes are equal. It is not a TEA5767\n"); return EINVAL; } /* Status bytes: * Byte 4: bit 3:1 : CI (Chip Identification) == 0 - * bit 0 : internally set to 0 + * bit 0 : internally set to 0 * Byte 5: bit 7:0 : == 0 */ if (!((buffer[3] & 0x0f) == 0x00) && (buffer[4] == 0x00)) { - tuner_warn ( "Chip ID is not zero. It is not a TEA5767\n" ); + tuner_warn("Chip ID is not zero. It is not a TEA5767\n"); return EINVAL; } - tuner_warn ( "TEA5767 detected.\n" ); + tuner_warn("TEA5767 detected.\n"); return 0; } @@ -319,16 +323,16 @@ int tea5767_tuner_init(struct i2c_client *c) { struct tuner *t = i2c_get_clientdata(c); - if (tea_detection(c)==EINVAL) return EINVAL; + if (tea5767_autodetection(c) == EINVAL) + return EINVAL; - tuner_info("type set to %d (%s)\n", - t->type, TEA5767_TUNER_NAME); - strlcpy(c->name, TEA5767_TUNER_NAME, sizeof(c->name)); + tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio"); + strlcpy(c->name, "tea5767", sizeof(c->name)); - t->tv_freq = set_tv_freq; + t->tv_freq = set_tv_freq; t->radio_freq = set_radio_freq; t->has_signal = tea5767_signal; - t->is_stereo = tea5767_stereo; + t->is_stereo = tea5767_stereo; return (0); } diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 6f6bf4a633f..de190630bab 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -1,5 +1,5 @@ /* - * $Id: tuner-core.c,v 1.29 2005/06/21 15:40:33 mchehab Exp $ + * $Id: tuner-core.c,v 1.55 2005/07/08 13:20:33 mchehab Exp $ * * i2c tv tuner chip device driver * core core, i.e. kernel interfaces, registering and so on @@ -23,42 +23,36 @@ #include #include -/* - * comment line bellow to return to old behavor, where only one I2C device is supported - */ - #define UNSET (-1U) /* standard i2c insmod options */ static unsigned short normal_i2c[] = { - 0x4b, /* tda8290 */ + 0x4b, /* tda8290 */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, I2C_CLIENT_END }; + I2C_CLIENT_INSMOD; /* insmod options used at init time => read/only */ -static unsigned int addr = 0; +static unsigned int addr = 0; module_param(addr, int, 0444); /* insmod options used at runtime => read/write */ -unsigned int tuner_debug = 0; -module_param(tuner_debug, int, 0644); +unsigned int tuner_debug = 0; +module_param(tuner_debug, int, 0644); -static unsigned int tv_range[2] = { 44, 958 }; +static unsigned int tv_range[2] = { 44, 958 }; static unsigned int radio_range[2] = { 65, 108 }; -module_param_array(tv_range, int, NULL, 0644); +module_param_array(tv_range, int, NULL, 0644); module_param_array(radio_range, int, NULL, 0644); MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); -static int this_adap; -static unsigned short first_tuner, tv_tuner, radio_tuner; - static struct i2c_driver driver; static struct i2c_client client_template; @@ -70,18 +64,19 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) struct tuner *t = i2c_get_clientdata(c); if (t->type == UNSET) { - tuner_info("tuner type not set\n"); + tuner_warn ("tuner type not set\n"); return; } if (NULL == t->tv_freq) { - tuner_info("Huh? tv_set is NULL?\n"); + tuner_warn ("Tuner has no way to set tv freq\n"); return; } - if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { - tuner_info("TV freq (%d.%02d) out of range (%d-%d)\n", - freq/16,freq%16*100/16,tv_range[0],tv_range[1]); + if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) { + tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n", + freq / 16, freq % 16 * 100 / 16, tv_range[0], + tv_range[1]); } - t->tv_freq(c,freq); + t->tv_freq(c, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) @@ -89,24 +84,20 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) struct tuner *t = i2c_get_clientdata(c); if (t->type == UNSET) { - tuner_info("tuner type not set\n"); + tuner_warn ("tuner type not set\n"); return; } if (NULL == t->radio_freq) { - tuner_info("no radio tuning for this one, sorry.\n"); + tuner_warn ("tuner has no way to set radio frequency\n"); return; } - if (freq >= radio_range[0]*16000 && freq <= radio_range[1]*16000) { - if (tuner_debug) - tuner_info("radio freq step 62.5Hz (%d.%06d)\n", - freq/16000,freq%16000*1000/16); - t->radio_freq(c,freq); - } else { - tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n", - freq/16,freq%16*100/16, - radio_range[0],radio_range[1]); + if (freq <= radio_range[0] * 16000 || freq >= radio_range[1] * 16000) { + tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n", + freq / 16000, freq % 16000 * 100 / 16000, + radio_range[0], radio_range[1]); } + t->radio_freq(c, freq); return; } @@ -117,42 +108,45 @@ static void set_freq(struct i2c_client *c, unsigned long freq) switch (t->mode) { case V4L2_TUNER_RADIO: tuner_dbg("radio freq set to %lu.%02lu\n", - freq/16,freq%16*100/16); - set_radio_freq(c,freq); + freq / 16000, freq % 16000 * 100 / 16000); + set_radio_freq(c, freq); break; case V4L2_TUNER_ANALOG_TV: case V4L2_TUNER_DIGITAL_TV: tuner_dbg("tv freq set to %lu.%02lu\n", - freq/16,freq%16*100/16); + freq / 16, freq % 16 * 100 / 16); set_tv_freq(c, freq); break; } t->freq = freq; } -static void set_type(struct i2c_client *c, unsigned int type) +static void set_type(struct i2c_client *c, unsigned int type, + unsigned int new_mode_mask) { struct tuner *t = i2c_get_clientdata(c); unsigned char buffer[4]; - /* sanity check */ - if (type == UNSET || type == TUNER_ABSENT) + if (type == UNSET || type == TUNER_ABSENT) { + tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr); return; - if (type >= tuner_count) + } + + if (type >= tuner_count) { + tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count); return; + } + /* This code detects calls by card attach_inform */ if (NULL == t->i2c.dev.driver) { - /* not registered yet */ - t->type = type; + tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); + + t->type=type; return; } - if ((t->initialized) && (t->type == type)) - /* run only once except type change Hac 04/05*/ - return; - - t->initialized = 1; t->type = type; + switch (t->type) { case TUNER_MT2032: microtune_init(c); @@ -161,136 +155,194 @@ static void set_type(struct i2c_client *c, unsigned int type) tda8290_init(c); break; case TUNER_TEA5767: - if (tea5767_tuner_init(c)==EINVAL) t->type=TUNER_ABSENT; + if (tea5767_tuner_init(c) == EINVAL) { + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + return; + } + t->mode_mask = T_RADIO; break; case TUNER_PHILIPS_FMD1216ME_MK3: buffer[0] = 0x0b; buffer[1] = 0xdc; buffer[2] = 0x9c; buffer[3] = 0x60; - i2c_master_send(c,buffer,4); + i2c_master_send(c, buffer, 4); mdelay(1); buffer[2] = 0x86; buffer[3] = 0x54; - i2c_master_send(c,buffer,4); + i2c_master_send(c, buffer, 4); default_tuner_init(c); break; default: - /* TEA5767 autodetection code */ - if (tea5767_tuner_init(c)!=EINVAL) { - t->type = TUNER_TEA5767; - if (first_tuner == 0x60) - first_tuner++; - break; - } - default_tuner_init(c); break; } - tuner_dbg ("I2C addr 0x%02x with type %d\n",c->addr<<1,type); + + if (t->mode_mask == T_UNINITIALIZED) + t->mode_mask = new_mode_mask; + + set_freq(c, t->freq); + tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", + c->adapter->name, c->driver->name, c->addr << 1, type, + t->mode_mask); } -#define CHECK_ADDR(tp,cmd,tun) if (client->addr!=tp) { \ - return 0; } else if (tuner_debug) \ - tuner_info ("Cmd %s accepted to "tun"\n",cmd); -#define CHECK_MODE(cmd) if (t->mode == V4L2_TUNER_RADIO) { \ - CHECK_ADDR(radio_tuner,cmd,"radio") } else \ - { CHECK_ADDR(tv_tuner,cmd,"TV"); } +/* + * This function apply tuner config to tuner specified + * by tun_setup structure. I addr is unset, then admin status + * and tun addr status is more precise then current status, + * it's applied. Otherwise status and type are applied only to + * tuner with exactly the same addr. +*/ + +static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) +{ + struct tuner *t = i2c_get_clientdata(c); + + if (tun_setup->addr == ADDR_UNSET) { + if (t->mode_mask & tun_setup->mode_mask) + set_type(c, tun_setup->type, tun_setup->mode_mask); + } else if (tun_setup->addr == c->addr) { + set_type(c, tun_setup->type, tun_setup->mode_mask); + } +} -static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr) +static inline int check_mode(struct tuner *t, char *cmd) { - /* ADDR_UNSET defaults to first available tuner */ - if ( tun_addr->addr == ADDR_UNSET ) { - if (first_tuner != c->addr) - return; - switch (tun_addr->v4l2_tuner) { + if (1 << t->mode & t->mode_mask) { + switch (t->mode) { case V4L2_TUNER_RADIO: - radio_tuner=c->addr; + tuner_dbg("Cmd %s accepted for radio\n", cmd); break; - default: - tv_tuner=c->addr; + case V4L2_TUNER_ANALOG_TV: + tuner_dbg("Cmd %s accepted for analog TV\n", cmd); + break; + case V4L2_TUNER_DIGITAL_TV: + tuner_dbg("Cmd %s accepted for digital TV\n", cmd); break; } - } else { - /* Sets tuner to its configured value */ - switch (tun_addr->v4l2_tuner) { - case V4L2_TUNER_RADIO: - radio_tuner=tun_addr->addr; - if ( tun_addr->addr == c->addr ) set_type(c,tun_addr->type); - return; - default: - tv_tuner=tun_addr->addr; - if ( tun_addr->addr == c->addr ) set_type(c,tun_addr->type); - return; - } + return 0; } - set_type(c,tun_addr->type); + return EINVAL; } static char pal[] = "-"; module_param_string(pal, pal, sizeof(pal), 0644); +static char secam[] = "-"; +module_param_string(secam, secam, sizeof(secam), 0644); +/* get more precise norm info from insmod option */ static int tuner_fixup_std(struct tuner *t) { if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { - /* get more precise norm info from insmod option */ switch (pal[0]) { case 'b': case 'B': case 'g': case 'G': - tuner_dbg("insmod fixup: PAL => PAL-BG\n"); + tuner_dbg ("insmod fixup: PAL => PAL-BG\n"); t->std = V4L2_STD_PAL_BG; break; case 'i': case 'I': - tuner_dbg("insmod fixup: PAL => PAL-I\n"); + tuner_dbg ("insmod fixup: PAL => PAL-I\n"); t->std = V4L2_STD_PAL_I; break; case 'd': case 'D': case 'k': case 'K': - tuner_dbg("insmod fixup: PAL => PAL-DK\n"); + tuner_dbg ("insmod fixup: PAL => PAL-DK\n"); t->std = V4L2_STD_PAL_DK; break; + case 'M': + case 'm': + tuner_dbg ("insmod fixup: PAL => PAL-M\n"); + t->std = V4L2_STD_PAL_M; + break; + case 'N': + case 'n': + tuner_dbg ("insmod fixup: PAL => PAL-N\n"); + t->std = V4L2_STD_PAL_N; + break; } } + if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) { + switch (secam[0]) { + case 'd': + case 'D': + case 'k': + case 'K': + tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n"); + t->std = V4L2_STD_SECAM_DK; + break; + case 'l': + case 'L': + tuner_dbg ("insmod fixup: SECAM => SECAM-L\n"); + t->std = V4L2_STD_SECAM_L; + break; + } + } + return 0; } /* ---------------------------------------------------------------------- */ +/* static var Used only in tuner_attach and tuner_probe */ +static unsigned default_mode_mask; + +/* During client attach, set_type is called by adapter's attach_inform callback. + set_type must then be completed by tuner_attach. + */ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) { struct tuner *t; - /* by default, first I2C card is both tv and radio tuner */ - if (this_adap == 0) { - first_tuner = addr; - tv_tuner = addr; - radio_tuner = addr; - } - this_adap++; - - client_template.adapter = adap; - client_template.addr = addr; + client_template.adapter = adap; + client_template.addr = addr; - t = kmalloc(sizeof(struct tuner),GFP_KERNEL); - if (NULL == t) - return -ENOMEM; - memset(t,0,sizeof(struct tuner)); - memcpy(&t->i2c,&client_template,sizeof(struct i2c_client)); + t = kmalloc(sizeof(struct tuner), GFP_KERNEL); + if (NULL == t) + return -ENOMEM; + memset(t, 0, sizeof(struct tuner)); + memcpy(&t->i2c, &client_template, sizeof(struct i2c_client)); i2c_set_clientdata(&t->i2c, t); - t->type = UNSET; - t->radio_if2 = 10700*1000; /* 10.7MHz - FM radio */ - t->audmode = V4L2_TUNER_MODE_STEREO; + t->type = UNSET; + t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ + t->audmode = V4L2_TUNER_MODE_STEREO; + t->mode_mask = T_UNINITIALIZED; + + + tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); + + /* TEA5767 autodetection code - only for addr = 0xc0 */ + if (addr == 0x60) { + if (tea5767_autodetection(&t->i2c) != EINVAL) { + t->type = TUNER_TEA5767; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + t->freq = 87.5 * 16; /* Sets freq to FM range */ + default_mode_mask &= ~T_RADIO; + + i2c_attach_client (&t->i2c); + set_type(&t->i2c,t->type, t->mode_mask); + return 0; + } + } - i2c_attach_client(&t->i2c); - tuner_info("chip found @ 0x%x (%s)\n", - addr << 1, adap->name); + /* Initializes only the first adapter found */ + if (default_mode_mask != T_UNINITIALIZED) { + tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask); + t->mode_mask = default_mode_mask; + t->freq = 400 * 16; /* Sets freq to VHF High */ + default_mode_mask = T_UNINITIALIZED; + } - set_type(&t->i2c, t->type); + /* Should be just before return */ + i2c_attach_client (&t->i2c); + set_type (&t->i2c,t->type, t->mode_mask); return 0; } @@ -300,11 +352,8 @@ static int tuner_probe(struct i2c_adapter *adap) normal_i2c[0] = addr; normal_i2c[1] = I2C_CLIENT_END; } - this_adap = 0; - first_tuner = 0; - tv_tuner = 0; - radio_tuner = 0; + default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tuner_attach); @@ -316,9 +365,10 @@ static int tuner_detach(struct i2c_client *client) struct tuner *t = i2c_get_clientdata(client); int err; - err=i2c_detach_client(&t->i2c); + err = i2c_detach_client(&t->i2c); if (err) { - tuner_warn ("Client deregistration failed, client not detached.\n"); + tuner_warn + ("Client deregistration failed, client not detached.\n"); return err; } @@ -326,37 +376,65 @@ static int tuner_detach(struct i2c_client *client) return 0; } -#define SWITCH_V4L2 if (!t->using_v4l2 && tuner_debug) \ - tuner_info("switching to v4l2\n"); \ - t->using_v4l2 = 1; -#define CHECK_V4L2 if (t->using_v4l2) { if (tuner_debug) \ - tuner_info("ignore v4l1 call\n"); \ - return 0; } +/* + * Switch tuner to other mode. If tuner support both tv and radio, + * set another frequency to some value (This is needed for some pal + * tuners to avoid locking). Otherwise, just put second tuner in + * standby mode. + */ + +static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) +{ + if (mode != t->mode) { + + t->mode = mode; + if (check_mode(t, cmd) == EINVAL) { + t->mode = T_STANDBY; + if (V4L2_TUNER_RADIO == mode) { + set_tv_freq(client, 400 * 16); + } else { + set_radio_freq(client, 87.5 * 16000); + } + return EINVAL; + } + } + return 0; +} + +#define switch_v4l2() if (!t->using_v4l2) \ + tuner_dbg("switching to v4l2\n"); \ + t->using_v4l2 = 1; + +static inline int check_v4l2(struct tuner *t) +{ + if (t->using_v4l2) { + tuner_dbg ("ignore v4l1 call\n"); + return EINVAL; + } + return 0; +} -static int -tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); - unsigned int *iarg = (int*)arg; + unsigned int *iarg = (int *)arg; - switch (cmd) { + switch (cmd) { /* --- configuration --- */ - case TUNER_SET_TYPE: - set_type(client,*iarg); - break; case TUNER_SET_TYPE_ADDR: - set_addr(client,(struct tuner_addr *)arg); + tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x\n", + ((struct tuner_setup *)arg)->type, + ((struct tuner_setup *)arg)->addr, + ((struct tuner_setup *)arg)->mode_mask); + + set_addr(client, (struct tuner_setup *)arg); break; case AUDC_SET_RADIO: - t->mode = V4L2_TUNER_RADIO; - CHECK_ADDR(tv_tuner,"AUDC_SET_RADIO","TV"); - - if (V4L2_TUNER_RADIO != t->mode) { - set_tv_freq(client,400 * 16); - } + set_mode(client,t,V4L2_TUNER_RADIO, "AUDC_SET_RADIO"); break; case AUDC_CONFIG_PINNACLE: - CHECK_ADDR(tv_tuner,"AUDC_CONFIG_PINNACLE","TV"); + if (check_mode(t, "AUDC_CONFIG_PINNACLE") == EINVAL) + return 0; switch (*iarg) { case 2: tuner_dbg("pinnacle pal\n"); @@ -368,219 +446,238 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } break; + case TDA9887_SET_CONFIG: + break; /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ case VIDIOCSCHAN: - { - static const v4l2_std_id map[] = { - [ VIDEO_MODE_PAL ] = V4L2_STD_PAL, - [ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M, - [ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM, - [ 4 /* bttv */ ] = V4L2_STD_PAL_M, - [ 5 /* bttv */ ] = V4L2_STD_PAL_N, - [ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP, - }; - struct video_channel *vc = arg; - - CHECK_V4L2; - t->mode = V4L2_TUNER_ANALOG_TV; - CHECK_ADDR(tv_tuner,"VIDIOCSCHAN","TV"); - - if (vc->norm < ARRAY_SIZE(map)) - t->std = map[vc->norm]; - tuner_fixup_std(t); - if (t->freq) - set_tv_freq(client,t->freq); - return 0; - } + { + static const v4l2_std_id map[] = { + [VIDEO_MODE_PAL] = V4L2_STD_PAL, + [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M, + [VIDEO_MODE_SECAM] = V4L2_STD_SECAM, + [4 /* bttv */ ] = V4L2_STD_PAL_M, + [5 /* bttv */ ] = V4L2_STD_PAL_N, + [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP, + }; + struct video_channel *vc = arg; + + if (check_v4l2(t) == EINVAL) + return 0; + + if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL) + return 0; + + if (vc->norm < ARRAY_SIZE(map)) + t->std = map[vc->norm]; + tuner_fixup_std(t); + if (t->freq) + set_tv_freq(client, t->freq); + return 0; + } case VIDIOCSFREQ: - { - unsigned long *v = arg; + { + unsigned long *v = arg; - CHECK_MODE("VIDIOCSFREQ"); - CHECK_V4L2; - set_freq(client,*v); - return 0; - } + if (check_mode(t, "VIDIOCSFREQ") == EINVAL) + return 0; + if (check_v4l2(t) == EINVAL) + return 0; + + set_freq(client, *v); + return 0; + } case VIDIOCGTUNER: - { - struct video_tuner *vt = arg; - - CHECK_ADDR(radio_tuner,"VIDIOCGTUNER","radio"); - CHECK_V4L2; - if (V4L2_TUNER_RADIO == t->mode) { - if (t->has_signal) - vt->signal = t->has_signal(client); - if (t->is_stereo) { - if (t->is_stereo(client)) - vt->flags |= VIDEO_TUNER_STEREO_ON; - else - vt->flags &= ~VIDEO_TUNER_STEREO_ON; - } - vt->flags |= V4L2_TUNER_CAP_LOW; /* Allow freqs at 62.5 Hz */ + { + struct video_tuner *vt = arg; + + if (check_mode(t, "VIDIOCGTUNER") == EINVAL) + return 0; + if (check_v4l2(t) == EINVAL) + return 0; + + if (V4L2_TUNER_RADIO == t->mode) { + if (t->has_signal) + vt->signal = t->has_signal(client); + if (t->is_stereo) { + if (t->is_stereo(client)) + vt->flags |= + VIDEO_TUNER_STEREO_ON; + else + vt->flags &= + ~VIDEO_TUNER_STEREO_ON; + } + vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ - vt->rangelow = radio_range[0] * 16000; - vt->rangehigh = radio_range[1] * 16000; + vt->rangelow = radio_range[0] * 16000; + vt->rangehigh = radio_range[1] * 16000; - } else { - vt->rangelow = tv_range[0] * 16; - vt->rangehigh = tv_range[1] * 16; - } + } else { + vt->rangelow = tv_range[0] * 16; + vt->rangehigh = tv_range[1] * 16; + } - return 0; - } + return 0; + } case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - CHECK_ADDR(radio_tuner,"VIDIOCGAUDIO","radio"); - CHECK_V4L2; - if (V4L2_TUNER_RADIO == t->mode && t->is_stereo) - va->mode = t->is_stereo(client) - ? VIDEO_SOUND_STEREO - : VIDEO_SOUND_MONO; - return 0; - } + { + struct video_audio *va = arg; + + if (check_mode(t, "VIDIOCGAUDIO") == EINVAL) + return 0; + if (check_v4l2(t) == EINVAL) + return 0; + + if (V4L2_TUNER_RADIO == t->mode && t->is_stereo) + va->mode = t->is_stereo(client) + ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; + return 0; + } case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; + { + v4l2_std_id *id = arg; - SWITCH_V4L2; - t->mode = V4L2_TUNER_ANALOG_TV; - CHECK_ADDR(tv_tuner,"VIDIOC_S_STD","TV"); + if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD") + == EINVAL) + return 0; - t->std = *id; - tuner_fixup_std(t); - if (t->freq) - set_freq(client,t->freq); - break; - } + switch_v4l2(); + + t->std = *id; + tuner_fixup_std(t); + if (t->freq) + set_freq(client, t->freq); + break; + } case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - CHECK_MODE("VIDIOC_S_FREQUENCY"); - SWITCH_V4L2; - if (V4L2_TUNER_RADIO == f->type && - V4L2_TUNER_RADIO != t->mode) - set_tv_freq(client,400*16); - t->mode = f->type; - set_freq(client,f->frequency); - break; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; + { + struct v4l2_frequency *f = arg; + + t->freq = f->frequency; + switch_v4l2(); + if (V4L2_TUNER_RADIO == f->type && + V4L2_TUNER_RADIO != t->mode) { + if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY") + == EINVAL) + return 0; + } + set_freq(client,t->freq); - CHECK_MODE("VIDIOC_G_FREQUENCY"); - SWITCH_V4L2; - f->type = t->mode; - f->frequency = t->freq; - break; - } + break; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL) + return 0; + switch_v4l2(); + f->type = t->mode; + f->frequency = t->freq; + break; + } case VIDIOC_G_TUNER: - { - struct v4l2_tuner *tuner = arg; - - CHECK_MODE("VIDIOC_G_TUNER"); - SWITCH_V4L2; - if (V4L2_TUNER_RADIO == t->mode) { - if (t->has_signal) - tuner -> signal = t->has_signal(client); - if (t->is_stereo) { - if (t->is_stereo(client)) { - tuner -> rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; - } else { - tuner -> rxsubchans = V4L2_TUNER_SUB_MONO; + { + struct v4l2_tuner *tuner = arg; + + if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL) + return 0; + switch_v4l2(); + + if (V4L2_TUNER_RADIO == t->mode) { + + if (t->has_signal) + tuner->signal = t->has_signal(client); + + if (t->is_stereo) { + if (t->is_stereo(client)) { + tuner->rxsubchans = + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_MONO; + } else { + tuner->rxsubchans = + V4L2_TUNER_SUB_MONO; + } } + + tuner->capability |= + V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + + tuner->audmode = t->audmode; + + tuner->rangelow = radio_range[0] * 16000; + tuner->rangehigh = radio_range[1] * 16000; + } else { + tuner->rangelow = tv_range[0] * 16; + tuner->rangehigh = tv_range[1] * 16; } - tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; - tuner->audmode = t->audmode; - - tuner->rangelow = radio_range[0] * 16000; - tuner->rangehigh = radio_range[1] * 16000; - } else { - tuner->rangelow = tv_range[0] * 16; - tuner->rangehigh = tv_range[1] * 16; + break; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *tuner = arg; + + if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL) + return 0; + + switch_v4l2(); + + if (V4L2_TUNER_RADIO == t->mode) { + t->audmode = tuner->audmode; + set_radio_freq(client, t->freq); + } + break; } - break; - } - case VIDIOC_S_TUNER: /* Allow changing radio range and audio mode */ - { - struct v4l2_tuner *tuner = arg; - - CHECK_ADDR(radio_tuner,"VIDIOC_S_TUNER","radio"); - SWITCH_V4L2; - - /* To switch the audio mode, applications initialize the - index and audmode fields and the reserved array and - call the VIDIOC_S_TUNER ioctl. */ - /* rxsubchannels: V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO, - V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2, - V4L2_TUNER_MODE_SAP */ - - if (tuner->audmode == V4L2_TUNER_MODE_MONO) - t->audmode = V4L2_TUNER_MODE_MONO; - else - t->audmode = V4L2_TUNER_MODE_STEREO; - - set_radio_freq(client, t->freq); - break; - } - case TDA9887_SET_CONFIG: /* Nothing to do on tuner-core */ - break; default: - tuner_dbg ("Unimplemented IOCTL 0x%08x called to tuner.\n", cmd); - /* nothing */ + tuner_dbg("Unimplemented IOCTL 0x%08x called to tuner.\n", cmd); break; } return 0; } -static int tuner_suspend(struct device * dev, u32 state, u32 level) +static int tuner_suspend(struct device *dev, u32 state, u32 level) { - struct i2c_client *c = container_of(dev, struct i2c_client, dev); - struct tuner *t = i2c_get_clientdata(c); + struct i2c_client *c = container_of (dev, struct i2c_client, dev); + struct tuner *t = i2c_get_clientdata (c); - tuner_dbg("suspend\n"); + tuner_dbg ("suspend\n"); /* FIXME: power down ??? */ return 0; } -static int tuner_resume(struct device * dev, u32 level) +static int tuner_resume(struct device *dev, u32 level) { - struct i2c_client *c = container_of(dev, struct i2c_client, dev); - struct tuner *t = i2c_get_clientdata(c); + struct i2c_client *c = container_of (dev, struct i2c_client, dev); + struct tuner *t = i2c_get_clientdata (c); - tuner_dbg("resume\n"); + tuner_dbg ("resume\n"); if (t->freq) - set_freq(c,t->freq); + set_freq(c, t->freq); return 0; } /* ----------------------------------------------------------------------- */ static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = "tuner", - .id = I2C_DRIVERID_TUNER, - .flags = I2C_DF_NOTIFY, - .attach_adapter = tuner_probe, - .detach_client = tuner_detach, - .command = tuner_command, + .owner = THIS_MODULE, + .name = "tuner", + .id = I2C_DRIVERID_TUNER, + .flags = I2C_DF_NOTIFY, + .attach_adapter = tuner_probe, + .detach_client = tuner_detach, + .command = tuner_command, .driver = { - .suspend = tuner_suspend, - .resume = tuner_resume, - }, + .suspend = tuner_suspend, + .resume = tuner_resume, + }, }; -static struct i2c_client client_template = -{ +static struct i2c_client client_template = { I2C_DEVNAME("(tuner unset)"), - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + .flags = I2C_CLIENT_ALLOW_USE, + .driver = &driver, }; static int __init tuner_init_module(void) diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index c39ed6226ee..a3f8e83f531 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -1,5 +1,5 @@ /* - * $Id: tuner-simple.c,v 1.31 2005/06/21 16:02:25 mkrufky Exp $ + * $Id: tuner-simple.c,v 1.39 2005/07/07 01:49:30 mkrufky Exp $ * * i2c tv tuner chip device driver * controls all those simple 4-control-bytes style tuners. @@ -54,6 +54,27 @@ #define PHILIPS_MF_SET_PAL_L 0x03 // France #define PHILIPS_MF_SET_PAL_L2 0x02 // L' +/* Control byte */ + +#define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */ +#define TUNER_RATIO_SELECT_50 0x00 +#define TUNER_RATIO_SELECT_32 0x02 +#define TUNER_RATIO_SELECT_166 0x04 +#define TUNER_RATIO_SELECT_62 0x06 + +#define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */ + +/* Status byte */ + +#define TUNER_POR 0x80 +#define TUNER_FL 0x40 +#define TUNER_MODE 0x38 +#define TUNER_AFC 0x07 +#define TUNER_SIGNAL 0x07 +#define TUNER_STEREO 0x10 + +#define TUNER_PLL_LOCKED 0x40 +#define TUNER_STEREO_MK3 0x04 /* ---------------------------------------------------------------------- */ @@ -211,21 +232,17 @@ static struct tunertype tuners[] = { 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 }, { "Philips FQ1236A MK4", Philips, NTSC, 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, - - /* Should work for TVF8531MF, TVF8831MF, TVF8731MF */ - { "Ymec TVision TVF-8531MF", Philips, NTSC, + { "Ymec TVision TVF-8531MF/8831MF/8731MF", Philips, NTSC, 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, { "Ymec TVision TVF-5533MF", Philips, NTSC, 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732}, + { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC, 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, - /* Should work for TNF9533-D/IF, TNF9533-B/DF */ - { "Tena TNF9533-D/IF", Philips, PAL, + { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL, 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623}, - - /* This entry is for TEA5767 FM radio only chip used on several boards w/TV tuner */ - { TEA5767_TUNER_NAME, Philips, RADIO, - -1, -1, 0, 0, 0, TEA5767_LOW_LO_32768,0}, + { "Philips TEA5767HN FM Radio", Philips, RADIO, + /* see tea5767.c for details */}, { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL, 16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 }, }; @@ -244,15 +261,6 @@ static int tuner_getstatus(struct i2c_client *c) return byte; } -#define TUNER_POR 0x80 -#define TUNER_FL 0x40 -#define TUNER_MODE 0x38 -#define TUNER_AFC 0x07 - -#define TUNER_STEREO 0x10 /* radio mode */ -#define TUNER_STEREO_MK3 0x04 /* radio mode */ -#define TUNER_SIGNAL 0x07 /* radio mode */ - static int tuner_signal(struct i2c_client *c) { return (tuner_getstatus(c) & TUNER_SIGNAL) << 13; @@ -278,22 +286,6 @@ static int tuner_stereo(struct i2c_client *c) return stereo; } -#if 0 /* unused */ -static int tuner_islocked (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_FL); -} - -static int tuner_afcstatus (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_AFC) - 2; -} - -static int tuner_mode (struct i2c_client *c) -{ - return (tuner_getstatus (c) & TUNER_MODE) >> 3; -} -#endif /* ---------------------------------------------------------------------- */ @@ -376,7 +368,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) case TUNER_MICROTUNE_4042FI5: /* Set the charge pump for fast tuning */ - tun->config |= 0x40; + tun->config |= TUNER_CHARGE_PUMP; break; } @@ -425,14 +417,13 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc); break; } - /* bit 6 is PLL locked indicator */ - if (status_byte & 0x40) + if (status_byte & TUNER_PLL_LOCKED) break; udelay(10); } /* Set the charge pump for optimized phase noise figure */ - tun->config &= ~0x40; + tun->config &= ~TUNER_CHARGE_PUMP; buffer[0] = (div>>8) & 0x7f; buffer[1] = div & 0xff; buffer[2] = tun->config; @@ -453,26 +444,22 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) unsigned div; int rc; - tun=&tuners[t->type]; - div = (freq / 1000) + (int)(16*10.7); - buffer[2] = tun->config; + tun = &tuners[t->type]; + div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */ + buffer[2] = (tun->config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ switch (t->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - /*These values are empirically determinated */ - div = (freq * 122) / 16000 - 20; - buffer[2] = 0x88; /* could be also 0x80 */ - buffer[3] = 0x19; /* could be also 0x10, 0x18, 0x99 */ - break; + tuner_dbg ("This tuner doesn't have FM. Most cards has a TEA5767 for FM\n"); + return; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FMD1216ME_MK3: buffer[3] = 0x19; break; case TUNER_PHILIPS_FM1256_IH3: - div = (20 * freq) / 16000 + 333 * 2; - buffer[2] = 0x80; + div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ buffer[3] = 0x19; break; case TUNER_LG_PAL_FM: -- cgit v1.2.3 From 1455050f04084161c8a9425008e3b9b5f5c4c2a3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:57 -0700 Subject: [PATCH] v4l: drivers/media/video/Kconfig - Removed obsolete option. Current code needs multi tuner. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/Kconfig | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index e771064689e..f461750c764 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -7,19 +7,6 @@ menu "Video For Linux" comment "Video Adapters" -config TUNER_MULTI_I2C - bool "Enable support for multiple I2C devices on Video Adapters (EXPERIMENTAL)" - depends on VIDEO_DEV && EXPERIMENTAL - ---help--- - Some video adapters have more than one tuner inside. This patch - enables support for using more than one tuner. This is required - for some cards to allow tunning both video and radio. - It also improves I2C autodetection for these cards. - - Only few tuners currently is supporting this. More to come. - - It is safe to say 'Y' here even if your card has only one I2C tuner. - config VIDEO_BT848 tristate "BT848 Video For Linux" depends on VIDEO_DEV && PCI && I2C -- cgit v1.2.3 From 85369df350b138f26eac779da33de0960635ca4d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:58:59 -0700 Subject: [PATCH] v4l: MXB fix to correct tuner ioctl - driver command adapted to use new control (TUNER_SET_TYPE_ADDR, instead of TUNER_SET_TYPE) Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/mxb.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index 70bf1f1fad5..486234d41b5 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -326,6 +326,7 @@ static int mxb_init_done(struct saa7146_dev* dev) struct mxb* mxb = (struct mxb*)dev->ext_priv; struct video_decoder_init init; struct i2c_msg msg; + struct tuner_setup tun_setup; int i = 0, err = 0; struct tea6415c_multiplex vm; @@ -349,8 +350,10 @@ static int mxb_init_done(struct saa7146_dev* dev) mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i); /* select a tuner type */ - i = 5; - mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE, &i); + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.addr = ADDR_UNSET; + tun_setup.type = 5; + mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup); /* mute audio on tea6420s */ mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]); -- cgit v1.2.3 From 330a115ae46e7d7b5fe2d4e506ba8ae2e0027143 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:59:01 -0700 Subject: [PATCH] v4l: SAA7134 Update - Corrected all cards marked as 7135 cards to 7133. - Add new card support for Compro VideoMate TV Gold+II. - Add new card support for Kworld Xpert TV PVR7134 - Add new card support for Typhoon DVB-T Cardbus. - Changes to comply with CodingStyle: // comments converted to /* */ - Remove irq2_mask field from saa7134_dev structure. - Collect all the bits needed in saa7134_hwinit2() instead. - Distinguish the different variants of the Medion MD7134 modules via eeprom - moved Philips FMD1216 radio specific setup to saa7134-core.c - Fix kernel compile error with CONFIG_MODULES=n - Cleanup tuner private calls. - Some Indent fixes. Signed-off-by: Michael Tokarev Signed-off-by: Michael Krufky Signed-off-by: Hannibal Signed-off-by: Elshin Roman Signed-off-by: Hermann Pitton Signed-off-by: Juergen Orschiedt Signed-off-by: Hartmut Hackmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/saa7134/saa7134-cards.c | 2174 +++++++++++++++---------- drivers/media/video/saa7134/saa7134-core.c | 74 +- drivers/media/video/saa7134/saa7134-i2c.c | 45 +- drivers/media/video/saa7134/saa7134-input.c | 48 +- drivers/media/video/saa7134/saa7134-oss.c | 19 +- drivers/media/video/saa7134/saa7134-ts.c | 6 +- drivers/media/video/saa7134/saa7134-tvaudio.c | 121 +- drivers/media/video/saa7134/saa7134-vbi.c | 12 - drivers/media/video/saa7134/saa7134-video.c | 54 +- drivers/media/video/saa7134/saa7134.h | 21 +- 10 files changed, 1498 insertions(+), 1076 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 0c781e24c44..88b71a20b60 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -1,6 +1,5 @@ - /* - * $Id: saa7134-cards.c,v 1.58 2005/06/07 18:05:00 nsh Exp $ + * $Id: saa7134-cards.c,v 1.80 2005/07/07 01:49:30 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * card-specific stuff. @@ -47,6 +46,10 @@ struct saa7134_board saa7134_boards[] = { .name = "UNKNOWN/GENERIC", .audio_clock = 0x00187de7, .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = "default", .vmux = 0, @@ -58,6 +61,10 @@ struct saa7134_board saa7134_boards[] = { .name = "Proteus Pro [philips reference design]", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = name_comp1, .vmux = 0, @@ -83,6 +90,10 @@ struct saa7134_board saa7134_boards[] = { .name = "LifeView FlyVIDEO3000", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0xe000, .inputs = {{ .name = name_tv, @@ -90,7 +101,7 @@ struct saa7134_board saa7134_boards[] = { .amux = TV, .gpio = 0x8000, .tv = 1, - },{ + },{ .name = name_tv_mono, .vmux = 1, .amux = LINE2, @@ -117,12 +128,21 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .gpio = 0x2000, }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x8000, + }, }, [SAA7134_BOARD_FLYVIDEO2000] = { /* "TC Wan" */ .name = "LifeView FlyVIDEO2000", .audio_clock = 0x00200000, .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0xe000, .inputs = {{ .name = name_tv, @@ -146,14 +166,14 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .gpio = 0x4000, }}, - .radio = { - .name = name_radio, - .amux = LINE2, + .radio = { + .name = name_radio, + .amux = LINE2, .gpio = 0x2000, - }, + }, .mute = { .name = name_mute, - .amux = LINE2, + .amux = LINE2, .gpio = 0x8000, }, }, @@ -162,6 +182,10 @@ struct saa7134_board saa7134_boards[] = { .name = "LifeView FlyTV Platinum Mini", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = name_tv, .vmux = 1, @@ -183,6 +207,10 @@ struct saa7134_board saa7134_boards[] = { .name = "LifeView FlyTV Platinum FM", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0x1E000, /* Set GP16 and unused 15,14,13 to Output */ .inputs = {{ .name = name_tv, @@ -190,7 +218,7 @@ struct saa7134_board saa7134_boards[] = { .amux = TV, .gpio = 0x10000, /* GP16=1 selects TV input */ .tv = 1, - },{ + },{ /* .name = name_tv_mono, .vmux = 1, .amux = LINE2, @@ -200,29 +228,38 @@ struct saa7134_board saa7134_boards[] = { */ .name = name_comp1, /* Composite signal on S-Video input */ .vmux = 0, .amux = LINE2, -// .gpio = 0x4000, +/* .gpio = 0x4000, */ },{ .name = name_comp2, /* Composite input */ .vmux = 3, .amux = LINE2, -// .gpio = 0x4000, +/* .gpio = 0x4000, */ },{ .name = name_svideo, /* S-Video signal on S-Video input */ .vmux = 8, .amux = LINE2, -// .gpio = 0x4000, +/* .gpio = 0x4000, */ }}, .radio = { .name = name_radio, .amux = TV, .gpio = 0x00000, /* GP16=0 selects FM radio antenna */ }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x10000, + }, }, [SAA7134_BOARD_EMPRESS] = { /* "Gert Vervoort" */ .name = "EMPRESS", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = name_comp1, .vmux = 0, @@ -245,33 +282,40 @@ struct saa7134_board saa7134_boards[] = { .video_out = CCIR656, }, [SAA7134_BOARD_MONSTERTV] = { - /* "K.Ohta" */ - .name = "SKNet Monster TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, + /* "K.Ohta" */ + .name = "SKNet Monster TV", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_NTSC_M, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, }, [SAA7134_BOARD_MD9717] = { .name = "Tevion MD 9717", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_tv, .vmux = 1, @@ -302,10 +346,13 @@ struct saa7134_board saa7134_boards[] = { }, }, [SAA7134_BOARD_TVSTATION_RDS] = { - /* Typhoon TV Tuner RDS: Art.Nr. 50694 */ + /* Typhoon TV Tuner RDS: Art.Nr. 50694 */ .name = "KNC One TV-Station RDS / Typhoon TV Tuner RDS", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, @@ -314,10 +361,10 @@ struct saa7134_board saa7134_boards[] = { .tv = 1, },{ .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ .name = name_svideo, .vmux = 8, @@ -328,10 +375,10 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, },{ - .name = "CVid over SVid", - .vmux = 0, - .amux = LINE1, - }}, + .name = "CVid over SVid", + .vmux = 0, + .amux = LINE1, + }}, .radio = { .name = name_radio, .amux = LINE2, @@ -341,6 +388,9 @@ struct saa7134_board saa7134_boards[] = { .name = "KNC One TV-Station DVR", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .gpiomask = 0x820000, .inputs = {{ @@ -369,32 +419,38 @@ struct saa7134_board saa7134_boards[] = { .video_out = CCIR656, }, [SAA7134_BOARD_CINERGY400] = { - .name = "Terratec Cinergy 400 TV", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, // CVideo over SVideo Connector - .vmux = 0, - .amux = LINE1, - }} - }, + .name = "Terratec Cinergy 400 TV", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp2, /* CVideo over SVideo Connector */ + .vmux = 0, + .amux = LINE1, + }} + }, [SAA7134_BOARD_MD5044] = { .name = "Medion 5044", - .audio_clock = 0x00187de7, // was: 0x00200000, + .audio_clock = 0x00187de7, /* was: 0x00200000, */ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, @@ -426,57 +482,65 @@ struct saa7134_board saa7134_boards[] = { }, }, [SAA7134_BOARD_KWORLD] = { - .name = "Kworld/KuroutoShikou SAA7130-TVPCI", + .name = "Kworld/KuroutoShikou SAA7130-TVPCI", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC_M, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, - }, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }}, + }, [SAA7134_BOARD_CINERGY600] = { - .name = "Terratec Cinergy 600 TV", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, + .name = "Terratec Cinergy 600 TV", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, // CVideo over SVideo Connector - .vmux = 0, - .amux = LINE1, - }}, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp2, /* CVideo over SVideo Connector */ + .vmux = 0, + .amux = LINE1, + }}, .radio = { .name = name_radio, .amux = LINE2, - }, - }, + }, + }, [SAA7134_BOARD_MD7134] = { .name = "Medion 7134", - //.audio_clock = 0x00200000, .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -504,6 +568,9 @@ struct saa7134_board saa7134_boards[] = { .name = "Typhoon TV+Radio 90031", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, @@ -523,11 +590,14 @@ struct saa7134_board saa7134_boards[] = { .name = name_radio, .amux = LINE2, }, - }, + }, [SAA7134_BOARD_ELSA] = { .name = "ELSA EX-VISION 300TV", .audio_clock = 0x00187de7, .tuner_type = TUNER_HITACHI_NTSC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_svideo, .vmux = 8, @@ -542,11 +612,14 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .tv = 1, }}, - }, + }, [SAA7134_BOARD_ELSA_500TV] = { .name = "ELSA EX-VISION 500TV", .audio_clock = 0x00187de7, .tuner_type = TUNER_HITACHI_NTSC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_svideo, .vmux = 7, @@ -562,83 +635,100 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .tv = 1, }}, - }, + }, [SAA7134_BOARD_ASUSTeK_TVFM7134] = { - .name = "ASUS TV-FM 7134", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - }, - }, - [SAA7135_BOARD_ASUSTeK_TVFM7135] = { - .name = "ASUS TV-FM 7135", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, + .name = "ASUS TV-FM 7134", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 6, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + }, + }, + [SAA7134_BOARD_ASUSTeK_TVFM7135] = { + .name = "ASUS TV-FM 7135", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0x200000, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, .gpio = 0x0000, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE2, .gpio = 0x0000, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 6, + .amux = LINE2, .gpio = 0x0000, - }}, - .radio = { - .name = name_radio, - .amux = TV, + }}, + .radio = { + .name = name_radio, + .amux = TV, .gpio = 0x200000, - }, + }, + .mute = { + .name = name_mute, + .gpio = 0x0000, + }, + }, [SAA7134_BOARD_VA1000POWER] = { - .name = "AOPEN VA1000 POWER", + .name = "AOPEN VA1000 POWER", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }}, }, [SAA7134_BOARD_10MOONSTVMASTER] = { /* "lilicheng" */ .name = "10MOONS PCI TV CAPTURE CARD", .audio_clock = 0x00200000, .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0xe000, .inputs = {{ .name = name_tv, @@ -662,14 +752,14 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, .gpio = 0x4000, }}, - .radio = { - .name = name_radio, - .amux = LINE2, + .radio = { + .name = name_radio, + .amux = LINE2, .gpio = 0x2000, - }, + }, .mute = { .name = name_mute, - .amux = LINE2, + .amux = LINE2, .gpio = 0x8000, }, }, @@ -678,6 +768,9 @@ struct saa7134_board saa7134_boards[] = { .name = "BMK MPEX No Tuner", .audio_clock = 0x200000, .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_comp1, .vmux = 4, @@ -706,80 +799,94 @@ struct saa7134_board saa7134_boards[] = { .name = "Compro VideoMate TV", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC_M, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = { + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }}, + }, + [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = { .name = "Compro VideoMate TV Gold+", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC_M, .gpiomask = 0x800c0000, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0x06c00012, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x0ac20012, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .gpio = 0x08c20012, - .tv = 1, - }}, - }, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0x06c00012, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x0ac20012, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .gpio = 0x08c20012, + .tv = 1, + }}, /* radio and probably mute is missing */ + }, [SAA7134_BOARD_CRONOS_PLUS] = { - /* gpio pins: - 0 .. 3 BASE_ID - 4 .. 7 PROTECT_ID - 8 .. 11 USER_OUT - 12 .. 13 USER_IN - 14 .. 15 VIDIN_SEL */ + /* + gpio pins: + 0 .. 3 BASE_ID + 4 .. 7 PROTECT_ID + 8 .. 11 USER_OUT + 12 .. 13 USER_IN + 14 .. 15 VIDIN_SEL + */ .name = "Matrox CronosPlus", .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0xcf00, - .inputs = {{ - .name = name_comp1, - .vmux = 0, + .inputs = {{ + .name = name_comp1, + .vmux = 0, .gpio = 2 << 14, },{ - .name = name_comp2, - .vmux = 0, + .name = name_comp2, + .vmux = 0, .gpio = 1 << 14, },{ - .name = name_comp3, - .vmux = 0, + .name = name_comp3, + .vmux = 0, .gpio = 0 << 14, },{ - .name = name_comp4, - .vmux = 0, + .name = name_comp4, + .vmux = 0, .gpio = 3 << 14, },{ .name = name_svideo, .vmux = 8, .gpio = 2 << 14, - }}, - }, + }}, + }, [SAA7134_BOARD_MD2819] = { .name = "AverMedia M156 / Medion 2819", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, @@ -809,6 +916,9 @@ struct saa7134_board saa7134_boards[] = { .name = "BMK MPEX Tuner", .audio_clock = 0x200000, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_comp1, .vmux = 1, @@ -825,88 +935,101 @@ struct saa7134_board saa7134_boards[] = { }}, .mpeg = SAA7134_MPEG_EMPRESS, .video_out = CCIR656, - }, - [SAA7134_BOARD_ASUSTEK_TVFM7133] = { - .name = "ASUS TV-FM 7133", - .audio_clock = 0x00187de7, - // probably wrong, the 7133 one is the NTSC version ... - // .tuner_type = TUNER_PHILIPS_FM1236_MK3 - .tuner_type = TUNER_LG_NTSC_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 6, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_PINNACLE_PCTV_STEREO] = { - .name = "Pinnacle PCTV Stereo (saa7134)", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_MT2032, - .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 1, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_MANLI_MTV002] = { - /* Ognjen Nastic */ - .name = "Manli MuchTV M-TV002/Behold TV 403 FM", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, + }, + [SAA7134_BOARD_ASUSTEK_TVFM7133] = { + .name = "ASUS TV-FM 7133", + .audio_clock = 0x00187de7, + /* probably wrong, the 7133 one is the NTSC version ... + * .tuner_type = TUNER_PHILIPS_FM1236_MK3 */ + .tuner_type = TUNER_LG_NTSC_NEW_TAPC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, + .name = name_comp1, + .vmux = 4, + .amux = LINE2, },{ - .name = name_tv, - .vmux = 3, + .name = name_svideo, + .vmux = 6, .amux = LINE2, - .tv = 1, }}, .radio = { .name = name_radio, - .amux = LINE2, + .amux = LINE1, }, }, - [SAA7134_BOARD_MANLI_MTV001] = { - /* Ognjen Nastic UNTESTED */ - .name = "Manli MuchTV M-TV001/Behold TV 401", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, + [SAA7134_BOARD_PINNACLE_PCTV_STEREO] = { + .name = "Pinnacle PCTV Stereo (saa7134)", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_MT2032, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, .inputs = {{ - .name = name_svideo, + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 1, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, + [SAA7134_BOARD_MANLI_MTV002] = { + /* Ognjen Nastic */ + .name = "Manli MuchTV M-TV002/Behold TV 403 FM", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_MANLI_MTV001] = { + /* Ognjen Nastic UNTESTED */ + .name = "Manli MuchTV M-TV001/Behold TV 401", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, .vmux = 8, .amux = LINE1, },{ @@ -921,14 +1044,17 @@ struct saa7134_board saa7134_boards[] = { }}, .mute = { .name = name_mute, - .amux = LINE1, + .amux = LINE1, }, - }, + }, [SAA7134_BOARD_TG3000TV] = { /* TransGear 3000TV */ .name = "Nagase Sangyo TransGear 3000TV", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC_M, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_tv, .vmux = 1, @@ -944,81 +1070,90 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, }}, }, - [SAA7134_BOARD_ECS_TVP3XP] = { - .name = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ", - .audio_clock = 0x187de7, // xtal 32.1 MHz - .tuner_type = TUNER_PHILIPS_PAL, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, + [SAA7134_BOARD_ECS_TVP3XP] = { + .name = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ", + .audio_clock = 0x187de7, /* xtal 32.1 MHz */ + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = "CVid over SVid", + .vmux = 0, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_ECS_TVP3XP_4CB5] = { + .name = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)", + .audio_clock = 0x187de7, + .tuner_type = TUNER_PHILIPS_NTSC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, },{ .name = "CVid over SVid", .vmux = 0, .amux = LINE1, }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_ECS_TVP3XP_4CB5] = { - .name = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)", - .audio_clock = 0x187de7, - .tuner_type = TUNER_PHILIPS_NTSC, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_tv_mono, - .vmux = 1, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = "CVid over SVid", - .vmux = 0, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, [SAA7134_BOARD_AVACSSMARTTV] = { /* Roman Pszonczenko */ .name = "AVACS SmartTV", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_tv, .vmux = 1, .amux = TV, .tv = 1, - },{ + },{ .name = name_tv_mono, .vmux = 1, .amux = LINE2, @@ -1047,6 +1182,9 @@ struct saa7134_board saa7134_boards[] = { .name = "AVerMedia DVD EZMaker", .audio_clock = 0x00187de7, .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_comp1, .vmux = 3, @@ -1055,28 +1193,34 @@ struct saa7134_board saa7134_boards[] = { .vmux = 8, }}, }, - [SAA7134_BOARD_NOVAC_PRIMETV7133] = { - /* toshii@netbsd.org */ - .name = "Noval Prime TV 7133", - .audio_clock = 0x00200000, - .tuner_type = TUNER_ALPS_TSBH1_NTSC, - .inputs = {{ - .name = name_comp1, - .vmux = 3, - },{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_svideo, - .vmux = 8, - }}, - }, + [SAA7134_BOARD_NOVAC_PRIMETV7133] = { + /* toshii@netbsd.org */ + .name = "Noval Prime TV 7133", + .audio_clock = 0x00200000, + .tuner_type = TUNER_ALPS_TSBH1_NTSC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_comp1, + .vmux = 3, + },{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_svideo, + .vmux = 8, + }}, + }, [SAA7134_BOARD_AVERMEDIA_STUDIO_305] = { .name = "AverMedia AverTV Studio 305", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1256_IH3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, @@ -1097,35 +1241,41 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, }}, .radio = { - .name = name_radio, - .amux = LINE2, - }, + .name = name_radio, + .amux = LINE2, + }, .mute = { - .name = name_mute, - .amux = LINE1, + .name = name_mute, + .amux = LINE1, }, }, - [SAA7133_BOARD_UPMOST_PURPLE_TV] = { - .name = "UPMOST PURPLE TV", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 7, - .amux = TV, - .tv = 1, - },{ - .name = name_svideo, - .vmux = 7, - .amux = LINE1, - }}, + [SAA7134_BOARD_UPMOST_PURPLE_TV] = { + .name = "UPMOST PURPLE TV", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1236_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 7, + .amux = TV, + .tv = 1, + },{ + .name = name_svideo, + .vmux = 7, + .amux = LINE1, + }}, }, [SAA7134_BOARD_ITEMS_MTV005] = { /* Norman Jonas */ .name = "Items MuchTV Plus / IT-005", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_tv, .vmux = 3, @@ -1149,27 +1299,30 @@ struct saa7134_board saa7134_boards[] = { .name = "Terratec Cinergy 200 TV", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ - .name = name_tv, + .name = name_tv, .vmux = 1, .amux = LINE2, .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, // CVideo over SVideo Connector - .vmux = 0, - .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp2, /* CVideo over SVideo Connector */ + .vmux = 0, + .amux = LINE1, }}, .mute = { - .name = name_mute, - .amux = LINE2, + .name = name_mute, + .amux = LINE2, }, }, [SAA7134_BOARD_VIDEOMATE_TV_PVR] = { @@ -1177,84 +1330,96 @@ struct saa7134_board saa7134_boards[] = { .name = "Compro VideoMate TV PVR/FM", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC_M, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0x808c0080, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, .gpio = 0x00080, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, .gpio = 0x00080, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2_LEFT, - .tv = 1, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2_LEFT, + .tv = 1, .gpio = 0x00080, - }}, + }}, .radio = { .name = name_radio, .amux = LINE2, .gpio = 0x80000, - }, + }, .mute = { .name = name_mute, - .amux = LINE2, + .amux = LINE2, .gpio = 0x40000, }, - }, - [SAA7134_BOARD_SABRENT_SBTTVFM] = { + }, + [SAA7134_BOARD_SABRENT_SBTTVFM] = { /* Michael Rodriguez-Torrent */ - .name = "Sabrent SBT-TVFM (saa7130)", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .inputs = {{ + .name = "Sabrent SBT-TVFM (saa7130)", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_NTSC_M, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = name_comp1, .vmux = 1, .amux = LINE2, },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, [SAA7134_BOARD_ZOLID_XPERT_TV7134] = { /* Helge Jensen */ - .name = ":Zolid Xpert TV7134", + .name = ":Zolid Xpert TV7134", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_NTSC, - .inputs = {{ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 1, - .amux = LINE2, - .tv = 1, - }}, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }}, }, [SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE] = { /* "Matteo Az" ;-) */ .name = "Empire PCI TV-Radio LE", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0x4000, .inputs = {{ .name = name_tv_mono, @@ -1273,18 +1438,18 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, .gpio = 0x8000, }}, - .radio = { - .name = name_radio, - .amux = LINE1, - .gpio = 0x8000, - }, + .radio = { + .name = name_radio, + .amux = LINE1, + .gpio = 0x8000, + }, .mute = { - .name = name_mute, - .amux = TV, - .gpio =0x8000, - } + .name = name_mute, + .amux = TV, + .gpio =0x8000, + } }, - [SAA7134_BOARD_AVERMEDIA_STUDIO_307] = { + [SAA7134_BOARD_AVERMEDIA_STUDIO_307] = { /* Nickolay V. Shmyrev Lots of thanks to Andrey Zolotarev @@ -1292,6 +1457,9 @@ struct saa7134_board saa7134_boards[] = { .name = "Avermedia AVerTV Studio 307", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1256_IH3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .gpiomask = 0x03, .inputs = {{ @@ -1321,13 +1489,21 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, .gpio = 0x01, }, - }, - [SAA7134_BOARD_AVERMEDIA_GO_007_FM] = { + .mute = { + .name = name_mute, + .amux = LINE1, + .gpio = 0x00, + }, + }, + [SAA7134_BOARD_AVERMEDIA_GO_007_FM] = { .name = "Avermedia AVerTV GO 007 FM", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .gpiomask = 0x00300003, -// .gpiomask = 0x8c240003, + /* .gpiomask = 0x8c240003, */ .inputs = {{ .name = name_tv, .vmux = 1, @@ -1350,16 +1526,24 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, .gpio = 0x00300001, }, - }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x01, + }, + }, [SAA7134_BOARD_AVERMEDIA_CARDBUS] = { - /* Jon Westgate */ - .name = "AVerMedia Cardbus TV/Radio", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_PAL, + /* Kees.Blom@cwi.nl */ + .name = "AVerMedia Cardbus TV/Radio (E500)", + .audio_clock = 0x187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .inputs = {{ .name = name_tv, .vmux = 1, - .amux = LINE2, + .amux = TV, .tv = 1, },{ .name = name_comp1, @@ -1368,10 +1552,10 @@ struct saa7134_board saa7134_boards[] = { },{ .name = name_svideo, .vmux = 8, - .amux = LINE2, + .amux = LINE1, }}, .radio = { - .name = name_radio, + .name = name_radio, .amux = LINE1, }, }, @@ -1379,119 +1563,134 @@ struct saa7134_board saa7134_boards[] = { .name = "Terratec Cinergy 400 mobile", .audio_clock = 0x187de7, .tuner_type = TUNER_ALPS_TSBE5_PAL, - .tda9887_conf = TDA9887_PRESENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, .inputs = {{ - .name = name_tv, + .name = name_tv, .vmux = 1, .amux = TV, .tv = 1, - },{ + },{ .name = name_tv_mono, .vmux = 1, .amux = LINE2, .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, }}, }, [SAA7134_BOARD_CINERGY600_MK3] = { - .name = "Terratec Cinergy 600 TV MK3", - .audio_clock = 0x00200000, + .name = "Terratec Cinergy 600 TV MK3", + .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 4, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp2, // CVideo over SVideo Connector - .vmux = 0, - .amux = LINE1, - }}, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 4, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp2, /* CVideo over SVideo Connector */ + .vmux = 0, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = { + /* Dylan Walkden */ + .name = "Compro VideoMate Gold+ Pal", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0x1ce780, + .inputs = {{ + .name = name_svideo, + .vmux = 0, /* CVideo over SVideo Connector - ok? */ + .amux = LINE1, + .gpio = 0x008080, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x008080, + },{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x008080, + }}, .radio = { .name = name_radio, .amux = LINE2, - }, - }, - [SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = { - /* Dylan Walkden */ - .name = "Compro VideoMate Gold+ Pal", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_PAL, - .gpiomask = 0x1ce780, - .inputs = {{ - .name = name_svideo, - .vmux = 0, // CVideo over SVideo Connector - ok? - .amux = LINE1, - .gpio = 0x008080, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x008080, - },{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x008080, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0x80000, - }, - .mute = { - .name = name_mute, - .amux = LINE2, - .gpio = 0x0c8000, - }, - }, + .gpio = 0x80000, + }, + .mute = { + .name = name_mute, + .amux = LINE2, + .gpio = 0x0c8000, + }, + }, [SAA7134_BOARD_PINNACLE_300I_DVBT_PAL] = { - .name = "Pinnacle PCTV 300i DVB-T + PAL", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_MT2032, - .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, + .name = "Pinnacle PCTV 300i DVB-T + PAL", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_MT2032, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, .mpeg = SAA7134_MPEG_DVB, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, - .vmux = 1, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 1, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, [SAA7134_BOARD_PROVIDEO_PV952] = { /* andreas.kretschmer@web.de */ .name = "ProVideo PV952", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_comp1, @@ -1503,151 +1702,307 @@ struct saa7134_board saa7134_boards[] = { .amux = TV, .tv = 1, },{ - .name = name_tv_mono, - .vmux = 1, + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_AVERMEDIA_305] = { + /* much like the "studio" version but without radio + * and another tuner (sirspiritus@yandex.ru) */ + .name = "AverMedia AverTV/305", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + }, + [SAA7134_BOARD_FLYDVBTDUO] = { + /* LifeView FlyDVB-T DUO */ + /* "Nico Sabbi Hartmut Hackmann hartmut.hackmann@t-online.de*/ + .name = "LifeView FlyDVB-T DUO", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, /* Composite signal on S-Video input */ + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, /* Composite input */ + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, /* S-Video signal on S-Video input */ + .vmux = 8, .amux = LINE2, - .tv = 1, }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, }, - [SAA7134_BOARD_AVERMEDIA_305] = { - /* much like the "studio" version but without radio - * and another tuner (sirspiritus@yandex.ru) */ - .name = "AverMedia AverTV/305", + [SAA7134_BOARD_PHILIPS_TOUGH] = { + .name = "Philips TOUGH DVB-T reference design", + .tuner_type = TUNER_ABSENT, + .audio_clock = 0x00187de7, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_comp1, + .vmux = 0, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_AVERMEDIA_307] = { + /* + Davydov Vladimir + */ + .name = "Avermedia AVerTV 307", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .inputs = {{ .name = name_tv, .vmux = 1, - .amux = LINE2, + .amux = TV, .tv = 1, },{ .name = name_comp1, .vmux = 0, - .amux = LINE2, + .amux = LINE1, },{ .name = name_comp2, .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_ADS_INSTANT_TV] = { + .name = "ADS Tech Instant TV (saa7135)", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, .amux = LINE2, },{ .name = name_svideo, .vmux = 8, .amux = LINE2, }}, - .mute = { - .name = name_mute, - .amux = LINE1, + }, + [SAA7134_BOARD_KWORLD_VSTREAM_XPERT] = { + .name = "Kworld/Tevion V-Stream Xpert TV PVR7134", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_PAL_I, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0x0700, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x000, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x200, /* gpio by DScaler */ + },{ + .name = name_svideo, + .vmux = 0, + .amux = LINE1, + .gpio = 0x200, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + .gpio = 0x100, + }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x000, }, }, - [SAA7134_BOARD_FLYDVBTDUO] = { - /* LifeView FlyDVB-T DUO */ - /* "Nico Sabbi */ - .name = "LifeView FlyDVB-T DUO", + [SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS] = { + .name = "Typhoon DVB-T Duo Digital/Analog Cardbus", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, -// .gpiomask = 0xe000, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + /* .gpiomask = 0xe000, */ .inputs = {{ .name = name_tv, .vmux = 1, .amux = TV, -// .gpio = 0x0000, + /* .gpio = 0x0000, */ .tv = 1, - },{ + },{ .name = name_comp1, /* Composite signal on S-Video input */ .vmux = 0, .amux = LINE2, -// .gpio = 0x4000, + /* .gpio = 0x4000, */ },{ .name = name_comp2, /* Composite input */ .vmux = 3, .amux = LINE2, -// .gpio = 0x4000, + /* .gpio = 0x4000, */ },{ .name = name_svideo, /* S-Video signal on S-Video input */ .vmux = 8, .amux = LINE2, -// .gpio = 0x4000, + /* .gpio = 0x4000, */ }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + .mute = { + .name = name_mute, + .amux = LINE1, + }, }, - [SAA7134_BOARD_AVERMEDIA_307] = { - /* - Davydov Vladimir - */ - .name = "Avermedia AVerTV 307", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 0, - .amux = LINE1, - },{ - .name = name_comp2, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_ADS_INSTANT_TV] = { - .name = "ADS Tech Instant TV (saa7135)", + [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII] = { + .name = "Compro VideoMate TV Gold+II", + .audio_clock = 0x002187de7, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .radio_type = TUNER_TEA5767, + .tuner_addr = 0x63, + .radio_addr = 0x60, + .gpiomask = 0x8c1880, + .inputs = {{ + .name = name_svideo, + .vmux = 0, + .amux = LINE1, + .gpio = 0x800800, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x801000, + },{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x800000, + }}, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x880000, + }, + .mute = { + .name = name_mute, + .amux = LINE2, + .gpio = 0x840000, + }, + }, + [SAA7134_BOARD_KWORLD_XPERT] = { + /* + FIXME: + - Remote control doesn't initialize properly. + - Audio volume starts muted, + then gradually increases after channel change. + - Overlay scaling problems (application error?) + - Composite S-Video untested. + From: Konrad Rzepecki + */ + .name = "Kworld Xpert TV PVR7134", .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE2, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE2, - }}, - }, - [SAA7134_BOARD_KWORLD_VSTREAM_XPERT] = { - .name = "Kworld/Tevion V-Stream Xpert TV PVR7134", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_PAL_I, - .gpiomask = 0x0700, - .inputs = {{ - .name = name_tv, - .vmux = 1, - .amux = TV, - .tv = 1, - .gpio = 0x000, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - .gpio = 0x200, //gpio by DScaler - },{ - .name = name_svideo, - .vmux = 0, - .amux = LINE1, - .gpio = 0x200, - }}, - .radio = { - .name = name_radio, - .amux = LINE1, - .gpio = 0x100, - }, - }, - }; + .tuner_type = TUNER_TENA_9533_DI, + .radio_type = TUNER_TEA5767, + .tuner_addr = 0x61, + .radio_addr = 0x60, + .gpiomask = 0x0700, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x000, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x200, /* gpio by DScaler */ + },{ + .name = name_svideo, + .vmux = 0, + .amux = LINE1, + .gpio = 0x200, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + .gpio = 0x100, + }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x000, + }, + }, +}; + const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -1661,13 +2016,13 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0x2001, .driver_data = SAA7134_BOARD_PROTEUS_PRO, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0x2001, .driver_data = SAA7134_BOARD_PROTEUS_PRO, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = PCI_VENDOR_ID_PHILIPS, @@ -1676,70 +2031,70 @@ struct pci_device_id saa7134_pci_tbl[] = { },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1131, - .subdevice = 0x4e85, + .subvendor = 0x1131, + .subdevice = 0x4e85, .driver_data = SAA7134_BOARD_MONSTERTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153B, - .subdevice = 0x1142, - .driver_data = SAA7134_BOARD_CINERGY400, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153B, - .subdevice = 0x1143, - .driver_data = SAA7134_BOARD_CINERGY600, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153B, - .subdevice = 0x1158, - .driver_data = SAA7134_BOARD_CINERGY600_MK3, - },{ + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x153B, + .subdevice = 0x1142, + .driver_data = SAA7134_BOARD_CINERGY400, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x153B, + .subdevice = 0x1143, + .driver_data = SAA7134_BOARD_CINERGY600, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x153B, + .subdevice = 0x1158, + .driver_data = SAA7134_BOARD_CINERGY600_MK3, + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x153b, .subdevice = 0x1162, .driver_data = SAA7134_BOARD_CINERGY400_CARDBUS, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x5168, .subdevice = 0x0138, .driver_data = SAA7134_BOARD_FLYVIDEO3000, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x4e42, //"Typhoon PCI Capture TV Card" Art.No. 50673 - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO3000, - },{ + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x4e42, /* "Typhoon PCI Capture TV Card" Art.No. 50673 */ + .subdevice = 0x0138, + .driver_data = SAA7134_BOARD_FLYVIDEO3000, + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, .subvendor = 0x5168, .subdevice = 0x0138, .driver_data = SAA7134_BOARD_FLYVIDEO2000, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5168, .subdevice = 0x0212, /* minipci, LR212 */ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5168, /* Animation Technologies (LifeView) */ .subdevice = 0x0214, /* Standard PCI, LR214WF */ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1489, /* KYE */ .subdevice = 0x0214, /* Genius VideoWonder ProTV */ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */ - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x16be, @@ -1758,36 +2113,36 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0x226b, .driver_data = SAA7134_BOARD_ELSA_500TV, },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4842, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4842, + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4845, + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7135, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4830, + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4845, - .driver_data = SAA7135_BOARD_ASUSTeK_TVFM7135, + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4843, + .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133, },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4830, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4843, - .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133, + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = PCI_VENDOR_ID_ASUSTEK, + .subdevice = 0x4840, + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4840, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = PCI_VENDOR_ID_PHILIPS, @@ -1808,118 +2163,118 @@ struct pci_device_id saa7134_pci_tbl[] = { },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1131, - .subdevice = 0x7133, + .subvendor = 0x1131, + .subdevice = 0x7133, .driver_data = SAA7134_BOARD_VA1000POWER, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2001, + .subvendor = PCI_VENDOR_ID_PHILIPS, + .subdevice = 0x2001, .driver_data = SAA7134_BOARD_10MOONSTVMASTER, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc100, + .subvendor = 0x185b, + .subdevice = 0xc100, .driver_data = SAA7134_BOARD_VIDEOMATE_TV, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc100, + .subvendor = 0x185b, + .subdevice = 0xc100, .driver_data = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_MATROX, - .subdevice = 0x48d0, + .subvendor = PCI_VENDOR_ID_MATROX, + .subdevice = 0x48d0, .driver_data = SAA7134_BOARD_CRONOS_PLUS, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa70b, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xa70b, .driver_data = SAA7134_BOARD_MD2819, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2115, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x2115, .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2108, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x2108, .driver_data = SAA7134_BOARD_AVERMEDIA_305, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x10ff, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x10ff, .driver_data = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER, - },{ + },{ /* AVerMedia CardBus */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xd6ee, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xd6ee, .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS, },{ /* TransGear 3000TV */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x050c, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x050c, .driver_data = SAA7134_BOARD_TG3000TV, },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x11bd, - .subdevice = 0x002b, - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x11bd, - .subdevice = 0x002d, - .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1019, - .subdevice = 0x4cb4, - .driver_data = SAA7134_BOARD_ECS_TVP3XP, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1019, - .subdevice = 0x4cb5, - .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5, - },{ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x12ab, - .subdevice = 0x0800, - .driver_data = SAA7133_BOARD_UPMOST_PURPLE_TV, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x11bd, + .subdevice = 0x002b, + .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x11bd, + .subdevice = 0x002d, + .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1019, + .subdevice = 0x4cb4, + .driver_data = SAA7134_BOARD_ECS_TVP3XP, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1019, + .subdevice = 0x4cb5, + .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x12ab, + .subdevice = 0x0800, + .driver_data = SAA7134_BOARD_UPMOST_PURPLE_TV, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, .subvendor = 0x153B, .subdevice = 0x1152, .driver_data = SAA7134_BOARD_CINERGY200, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x185b, - .subdevice = 0xc100, + .subvendor = 0x185b, + .subdevice = 0xc100, .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1131, - .subdevice = 0, + .subvendor = 0x1131, + .subdevice = 0, .driver_data = SAA7134_BOARD_SABRENT_SBTTVFM, },{ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -1939,18 +2294,24 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x185b, .subdevice = 0xc200, .driver_data = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x1540, .subdevice = 0x9524, .driver_data = SAA7134_BOARD_PROVIDEO_PV952, - },{ + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5168, + .subdevice = 0x0502, /* Cardbus version */ + .driver_data = SAA7134_BOARD_FLYDVBTDUO, + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5168, - .subdevice = 0x0306, + .subdevice = 0x0306, /* PCI version */ .driver_data = SAA7134_BOARD_FLYDVBTDUO, },{ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -1959,31 +2320,44 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0xf31f, .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = PCI_VENDOR_ID_PHILIPS, + .subdevice = 0x2004, + .driver_data = SAA7134_BOARD_PHILIPS_TOUGH, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1421, .subdevice = 0x0350, /* PCI version */ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1421, .subdevice = 0x0370, /* cardbus version */ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ + },{ /* Typhoon DVB-T Duo Digital/Analog Cardbus */ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x4e42, + .subdevice = 0x0502, + .driver_data = SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS, + + },{ /* --- boards without eeprom + subsystem ID --- */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0, .driver_data = SAA7134_BOARD_NOAUTO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = PCI_VENDOR_ID_PHILIPS, .subdevice = 0, .driver_data = SAA7134_BOARD_NOAUTO, },{ @@ -1991,26 +2365,26 @@ struct pci_device_id saa7134_pci_tbl[] = { /* --- default catch --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .driver_data = SAA7134_BOARD_UNKNOWN, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .driver_data = SAA7134_BOARD_UNKNOWN, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .driver_data = SAA7134_BOARD_UNKNOWN, - },{ + },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7135, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .driver_data = SAA7134_BOARD_UNKNOWN, },{ /* --- end of list --- */ @@ -2021,46 +2395,9 @@ MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl); /* ----------------------------------------------------------- */ /* flyvideo tweaks */ -#if 0 -static struct { - char *model; - int tuner_type; -} fly_list[0x20] = { - /* default catch ... */ - [ 0 ... 0x1f ] = { - .model = "UNKNOWN", - .tuner_type = TUNER_ABSENT, - }, - /* ... the ones known so far */ - [ 0x05 ] = { - .model = "PAL-BG", - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - }, - [ 0x10 ] = { - .model = "PAL-BG / PAL-DK", - .tuner_type = TUNER_PHILIPS_PAL, - }, - [ 0x15 ] = { - .model = "NTSC", - .tuner_type = TUNER_ABSENT /* FIXME */, - }, -}; -#endif static void board_flyvideo(struct saa7134_dev *dev) { -#if 0 - /* non-working attempt to detect the correct tuner type ... */ - u32 value; - int index; - - value = dev->gpio_value; - index = (value & 0x1f00) >> 8; - printk(KERN_INFO "%s: flyvideo: gpio is 0x%x [model=%s,tuner=%d]\n", - dev->name, value, fly_list[index].model, - fly_list[index].tuner_type); - dev->tuner_type = fly_list[index].tuner_type; -#endif printk("%s: there are different flyvideo cards with different tuners\n" "%s: out there, you might have to use the tuner= insmod\n" "%s: option to override the default value.\n", @@ -2071,7 +2408,7 @@ static void board_flyvideo(struct saa7134_dev *dev) int saa7134_board_init1(struct saa7134_dev *dev) { - // Always print gpio, often manufacturers encode tuner type and other info. + /* Always print gpio, often manufacturers encode tuner type and other info. */ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0); dev->gpio_value = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); printk(KERN_INFO "%s: board init: gpio is %x\n", dev->name, dev->gpio_value); @@ -2082,7 +2419,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) dev->has_remote = 1; board_flyvideo(dev); break; - case SAA7134_BOARD_FLYTVPLATINUM_FM: + case SAA7134_BOARD_FLYTVPLATINUM_FM: case SAA7134_BOARD_CINERGY400: case SAA7134_BOARD_CINERGY600: case SAA7134_BOARD_CINERGY600_MK3: @@ -2090,23 +2427,25 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_ECS_TVP3XP_4CB5: case SAA7134_BOARD_MD2819: case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: + case SAA7134_BOARD_KWORLD_XPERT: case SAA7134_BOARD_AVERMEDIA_STUDIO_305: case SAA7134_BOARD_AVERMEDIA_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_307: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: -// case SAA7134_BOARD_SABRENT_SBTTVFM: /* not finished yet */ +/* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */ case SAA7134_BOARD_VIDEOMATE_TV_PVR: - case SAA7134_BOARD_MANLI_MTV001: - case SAA7134_BOARD_MANLI_MTV002: + case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: + case SAA7134_BOARD_MANLI_MTV001: + case SAA7134_BOARD_MANLI_MTV002: case SAA7134_BOARD_AVACSSMARTTV: dev->has_remote = 1; break; case SAA7134_BOARD_MD5044: printk("%s: seems there are two different versions of the MD5044\n" - "%s: (with the same ID) out there. If sound doesn't work for\n" - "%s: you try the audio_clock_override=0x200000 insmod option.\n", - dev->name,dev->name,dev->name); + "%s: (with the same ID) out there. If sound doesn't work for\n" + "%s: you try the audio_clock_override=0x200000 insmod option.\n", + dev->name,dev->name,dev->name); break; case SAA7134_BOARD_CINERGY400_CARDBUS: /* power-up tuner chip */ @@ -2114,11 +2453,19 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000); msleep(1); break; + case SAA7134_BOARD_FLYDVBTDUO: + case SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS: + /* turn the fan on Hac: static for the time being */ + saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); + saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06); + break; + case SAA7134_BOARD_AVERMEDIA_CARDBUS: + /* power-up tuner chip */ + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff); + msleep(1); + break; } - if (dev->has_remote) - dev->irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 | - SAA7134_IRQ2_INTE_GPIO18A | - SAA7134_IRQ2_INTE_GPIO16 ); return 0; } @@ -2139,10 +2486,85 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; dev->board = board; printk("%s: board type fixup: %s\n", dev->name, - saa7134_boards[dev->board].name); + saa7134_boards[dev->board].name); dev->tuner_type = saa7134_boards[dev->board].tuner_type; - if (TUNER_ABSENT != dev->tuner_type) - saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&dev->tuner_type); + + if (TUNER_ABSENT != dev->tuner_type) { + struct tuner_setup tun_setup; + + tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; + tun_setup.type = dev->tuner_type; + tun_setup.addr = ADDR_UNSET; + + saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR, &tun_setup); + } + break; +case SAA7134_BOARD_MD7134: + { + struct tuner_setup tun_setup; + u8 subaddr; + u8 data[3]; + int ret, tuner_t; + + struct i2c_msg msg[] = {{.addr=0x50, .flags=0, .buf=&subaddr, .len = 1}, + {.addr=0x50, .flags=I2C_M_RD, .buf=data, .len = 3}}; + subaddr= 0x14; + tuner_t = 0; + ret = i2c_transfer(&dev->i2c_adap, msg, 2); + if (ret != 2) { + printk(KERN_ERR "EEPROM read failure\n"); + } else if ((data[0] != 0) && (data[0] != 0xff)) { + /* old config structure */ + subaddr = data[0] + 2; + msg[1].len = 2; + i2c_transfer(&dev->i2c_adap, msg, 2); + tuner_t = (data[0] << 8) + data[1]; + switch (tuner_t){ + case 0x0103: + dev->tuner_type = TUNER_PHILIPS_PAL; + break; + case 0x010C: + dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3; + break; + default: + printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t); + } + } else if ((data[1] != 0) && (data[1] != 0xff)) { + /* new config structure */ + subaddr = data[1] + 1; + msg[1].len = 1; + i2c_transfer(&dev->i2c_adap, msg, 2); + subaddr = data[0] + 1; + msg[1].len = 2; + i2c_transfer(&dev->i2c_adap, msg, 2); + tuner_t = (data[1] << 8) + data[0]; + switch (tuner_t) { + case 0x0005: + dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3; + break; + case 0x001d: + dev->tuner_type = TUNER_PHILIPS_FMD1216ME_MK3; + printk(KERN_INFO "%s Board has DVB-T\n", dev->name); + break; + default: + printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t); + } + } else { + printk(KERN_ERR "%s unexpected config structure\n", dev->name); + } + + printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); + if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) { + dev->tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE; + saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG, &dev->tda9887_conf); + } + + tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; + tun_setup.type = dev->tuner_type; + tun_setup.addr = ADDR_UNSET; + + saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); + } break; } return 0; diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index f61ed1849a2..1dbe61755e9 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-core.c,v 1.30 2005/05/22 19:23:39 nsh Exp $ + * $Id: saa7134-core.c,v 1.39 2005/07/05 17:37:35 nsh Exp $ * * device driver for philips saa7134 based TV cards * driver core @@ -183,46 +183,6 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) /* ------------------------------------------------------------------ */ -#if 0 -static char *dec1_bits[8] = { - "DCSTD0", "DCSCT1", "WIPA", "GLIMB", - "GLIMT", "SLTCA", "HLCK" -}; -static char *dec2_bits[8] = { - "RDCAP", "COPRO", "COLSTR", "TYPE3", - NULL, "FIDT", "HLVLN", "INTL" -}; -static char *scale1_bits[8] = { - "VID_A", "VBI_A", NULL, NULL, "VID_B", "VBI_B" -}; -static char *scale2_bits[8] = { - "TRERR", "CFERR", "LDERR", "WASRST", - "FIDSCI", "FIDSCO", "D6^D5", "TASK" -}; - -static void dump_statusreg(struct saa7134_dev *dev, int reg, - char *regname, char **bits) -{ - int value,i; - - value = saa_readb(reg); - printk(KERN_DEBUG "%s: %s:", dev->name, regname); - for (i = 7; i >= 0; i--) { - if (NULL == bits[i]) - continue; - printk(" %s=%d", bits[i], (value & (1 << i)) ? 1 : 0); - } - printk("\n"); -} - -static void dump_statusregs(struct saa7134_dev *dev) -{ - dump_statusreg(dev,SAA7134_STATUS_VIDEO1,"dec1",dec1_bits); - dump_statusreg(dev,SAA7134_STATUS_VIDEO2,"dec2",dec2_bits); - dump_statusreg(dev,SAA7134_SCALER_STATUS0,"scale0",scale1_bits); - dump_statusreg(dev,SAA7134_SCALER_STATUS1,"scale1",scale2_bits); -} -#endif /* ----------------------------------------------------------- */ /* delayed request_module */ @@ -616,10 +576,6 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) if (irq_debug) print_irqstatus(dev,loop,report,status); -#if 0 - if (report & SAA7134_IRQ_REPORT_CONF_ERR) - dump_statusregs(dev); -#endif if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */) saa7134_irq_video_intl(dev); @@ -711,7 +667,6 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) SAA7134_MAIN_CTRL_EVFE1 | SAA7134_MAIN_CTRL_EVFE2 | SAA7134_MAIN_CTRL_ESFE | - SAA7134_MAIN_CTRL_EBADC | SAA7134_MAIN_CTRL_EBDAC); /* enable peripheral devices */ @@ -726,14 +681,28 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) /* late init (with i2c + irq) */ static int saa7134_hwinit2(struct saa7134_dev *dev) { + unsigned int irq2_mask; dprintk("hwinit2\n"); saa7134_video_init2(dev); saa7134_tvaudio_init2(dev); /* enable IRQ's */ + irq2_mask = + SAA7134_IRQ2_INTE_DEC3 | + SAA7134_IRQ2_INTE_DEC2 | + SAA7134_IRQ2_INTE_DEC1 | + SAA7134_IRQ2_INTE_DEC0 | + SAA7134_IRQ2_INTE_PE | + SAA7134_IRQ2_INTE_AR; + + if (dev->has_remote) + irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 | + SAA7134_IRQ2_INTE_GPIO18A | + SAA7134_IRQ2_INTE_GPIO16 ); + saa_writel(SAA7134_IRQ1, 0); - saa_writel(SAA7134_IRQ2, dev->irq2_mask); + saa_writel(SAA7134_IRQ2, irq2_mask); return 0; } @@ -954,13 +923,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, } /* initialize hardware #1 */ - dev->irq2_mask = - SAA7134_IRQ2_INTE_DEC3 | - SAA7134_IRQ2_INTE_DEC2 | - SAA7134_IRQ2_INTE_DEC1 | - SAA7134_IRQ2_INTE_DEC0 | - SAA7134_IRQ2_INTE_PE | - SAA7134_IRQ2_INTE_AR; saa7134_board_init1(dev); saa7134_hwinit1(dev); @@ -990,6 +952,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, request_module("saa6752hs"); request_module_depend("saa7134-empress",&need_empress); } + if (card_is_dvb(dev)) request_module_depend("saa7134-dvb",&need_dvb); @@ -1144,9 +1107,6 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) release_mem_region(pci_resource_start(pci_dev,0), pci_resource_len(pci_dev,0)); -#if 0 /* causes some trouble when reinserting the driver ... */ - pci_disable_device(pci_dev); -#endif pci_set_drvdata(pci_dev, NULL); /* free memory */ diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index b6f002e8421..93dd6197854 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-i2c.c,v 1.11 2005/06/12 01:36:14 mchehab Exp $ + * $Id: saa7134-i2c.c,v 1.19 2005/07/07 01:49:30 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * i2c interface support @@ -197,10 +197,6 @@ static inline int i2c_send_byte(struct saa7134_dev *dev, enum i2c_status status; __u32 dword; -#if 0 - i2c_set_attr(dev,attr); - saa_writeb(SAA7134_I2C_DATA, data); -#else /* have to write both attr + data in one 32bit word */ dword = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2); dword &= 0x0f; @@ -210,7 +206,6 @@ static inline int i2c_send_byte(struct saa7134_dev *dev, // dword |= 0x40 << 16; /* 400 kHz */ dword |= 0xf0 << 24; saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword); -#endif d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data); if (!i2c_is_busy_wait(dev)) @@ -331,12 +326,44 @@ static u32 functionality(struct i2c_adapter *adap) static int attach_inform(struct i2c_client *client) { - struct saa7134_dev *dev = client->adapter->algo_data; + struct saa7134_dev *dev = client->adapter->algo_data; int tuner = dev->tuner_type; int conf = dev->tda9887_conf; + struct tuner_setup tun_setup; + + d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", + client->driver->name,client->addr,i2c_clientname(client)); + + if (!client->driver->command) + return 0; + + if (saa7134_boards[dev->board].radio_type != UNSET) { + + tun_setup.type = saa7134_boards[dev->board].radio_type; + tun_setup.addr = saa7134_boards[dev->board].radio_addr; + + if ((tun_setup.addr == ADDR_UNSET) || (tun_setup.addr == client->addr)) { + tun_setup.mode_mask = T_RADIO; + + client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup); + } + } + + if (tuner != UNSET) { + + tun_setup.type = tuner; + tun_setup.addr = saa7134_boards[dev->board].tuner_addr; + + if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) { + + tun_setup.mode_mask = T_ANALOG_TV; + + client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup); + } + } + + client->driver->command(client, TDA9887_SET_CONFIG, &conf); - saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&tuner); - saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&conf); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index aba2b9de60d..213740122fe 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-input.c,v 1.19 2005/06/07 18:02:26 nsh Exp $ + * $Id: saa7134-input.c,v 1.21 2005/06/22 23:37:34 nsh Exp $ * * handle saa7134 IR remotes via linux kernel input layer. * @@ -68,10 +68,8 @@ static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = { [ 6 ] = KEY_AGAIN, // Recal [ 16 ] = KEY_KPENTER, // Enter -#if 1 /* FIXME */ [ 26 ] = KEY_F22, // Stereo [ 24 ] = KEY_EDIT, // AV Source -#endif }; static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = { @@ -172,45 +170,45 @@ static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = { }; static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = { - [ 30 ] = KEY_POWER, // power + [ 30 ] = KEY_POWER, // power [ 28 ] = KEY_SEARCH, // scan - [ 7 ] = KEY_SELECT, // source + [ 7 ] = KEY_SELECT, // source [ 22 ] = KEY_VOLUMEUP, [ 20 ] = KEY_VOLUMEDOWN, - [ 31 ] = KEY_CHANNELUP, + [ 31 ] = KEY_CHANNELUP, [ 23 ] = KEY_CHANNELDOWN, [ 24 ] = KEY_MUTE, [ 2 ] = KEY_KP0, - [ 1 ] = KEY_KP1, - [ 11 ] = KEY_KP2, - [ 27 ] = KEY_KP3, - [ 5 ] = KEY_KP4, - [ 9 ] = KEY_KP5, - [ 21 ] = KEY_KP6, + [ 1 ] = KEY_KP1, + [ 11 ] = KEY_KP2, + [ 27 ] = KEY_KP3, + [ 5 ] = KEY_KP4, + [ 9 ] = KEY_KP5, + [ 21 ] = KEY_KP6, [ 6 ] = KEY_KP7, - [ 10 ] = KEY_KP8, + [ 10 ] = KEY_KP8, [ 18 ] = KEY_KP9, [ 16 ] = KEY_KPDOT, [ 3 ] = KEY_TUNER, // tv/fm - [ 4 ] = KEY_REWIND, // fm tuning left or function left - [ 12 ] = KEY_FORWARD, // fm tuning right or function right + [ 4 ] = KEY_REWIND, // fm tuning left or function left + [ 12 ] = KEY_FORWARD, // fm tuning right or function right [ 0 ] = KEY_RECORD, - [ 8 ] = KEY_STOP, - [ 17 ] = KEY_PLAY, + [ 8 ] = KEY_STOP, + [ 17 ] = KEY_PLAY, [ 25 ] = KEY_ZOOM, [ 14 ] = KEY_MENU, // function [ 19 ] = KEY_AGAIN, // recall [ 29 ] = KEY_RESTART, // reset + [ 26 ] = KEY_SHUFFLE, // snapshot/shuffle // FIXME [ 13 ] = KEY_F21, // mts - [ 15 ] = KEY_F22, // min - [ 26 ] = KEY_F23, // freeze + [ 15 ] = KEY_F22, // min }; /* Alex Hermann */ @@ -489,13 +487,14 @@ int saa7134_input_init1(struct saa7134_dev *dev) break; case SAA7134_BOARD_ECS_TVP3XP: case SAA7134_BOARD_ECS_TVP3XP_4CB5: - ir_codes = eztv_codes; - mask_keycode = 0x00017c; - mask_keyup = 0x000002; + ir_codes = eztv_codes; + mask_keycode = 0x00017c; + mask_keyup = 0x000002; polling = 50; // ms - break; + break; + case SAA7134_BOARD_KWORLD_XPERT: case SAA7134_BOARD_AVACSSMARTTV: - ir_codes = avacssmart_codes; + ir_codes = avacssmart_codes; mask_keycode = 0x00001F; mask_keyup = 0x000020; polling = 50; // ms @@ -524,6 +523,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) polling = 50; // ms break; case SAA7134_BOARD_VIDEOMATE_TV_PVR: + case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: ir_codes = videomate_tv_pvr_codes; mask_keycode = 0x00003F; mask_keyup = 0x400000; diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 81732904623..b5bede95dbf 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-oss.c,v 1.14 2005/05/18 22:45:16 hhackmann Exp $ + * $Id: saa7134-oss.c,v 1.17 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * oss dsp interface @@ -556,21 +556,28 @@ mixer_recsrc_7134(struct saa7134_dev *dev) static int mixer_recsrc_7133(struct saa7134_dev *dev) { - u32 value = 0xbbbbbb; + u32 anabar, xbarin; + xbarin = 0x03; // adc + anabar = 0; switch (dev->oss.input) { case TV: - value = 0xbbbb10; /* MAIN */ + xbarin = 0; // Demodulator + anabar = 2; // DACs break; case LINE1: - value = 0xbbbb32; /* AUX1 */ + anabar = 0; // aux1, aux1 break; case LINE2: case LINE2_LEFT: - value = 0xbbbb54; /* AUX2 */ + anabar = 9; // aux2, aux2 break; } - saa_dsp_writel(dev, 0x46c >> 2, value); + /* output xbar always main channel */ + saa_dsp_writel(dev, 0x46c >> 2, 0xbbbb10); + saa_dsp_writel(dev, 0x464 >> 2, xbarin); + saa_writel(0x594 >> 2, anabar); + return 0; } diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 345eb2a8c28..4dd9f1b2392 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-ts.c,v 1.14 2005/02/03 10:24:33 kraxel Exp $ + * $Id: saa7134-ts.c,v 1.15 2005/06/14 22:48:18 hhackmann Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface @@ -221,10 +221,10 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status) if (dev->ts_q.curr) { field = dev->ts_q.curr->vb.field; if (field == V4L2_FIELD_TOP) { - if ((status & 0x100000) != 0x000000) + if ((status & 0x100000) != 0x100000) goto done; } else { - if ((status & 0x100000) != 0x100000) + if ((status & 0x100000) != 0x000000) goto done; } saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE); diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 3617e7f7a41..eeafa5a71d2 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-tvaudio.c,v 1.25 2005/06/07 19:00:38 nsh Exp $ + * $Id: saa7134-tvaudio.c,v 1.30 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * tv audio decoder (fm stereo, nicam, ...) @@ -169,7 +169,7 @@ static void tvaudio_init(struct saa7134_dev *dev) int clock = saa7134_boards[dev->board].audio_clock; if (UNSET != audio_clock_override) - clock = audio_clock_override; + clock = audio_clock_override; /* init all audio registers */ saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00); @@ -219,14 +219,17 @@ static void mute_input_7134(struct saa7134_dev *dev) in = dev->input; mute = (dev->ctl_mute || (dev->automute && (&card(dev).radio) != in)); - if (PCI_DEVICE_ID_PHILIPS_SAA7130 == dev->pci->device && - card(dev).mute.name) { - /* 7130 - we'll mute using some unconnected audio input */ + if (card(dev).mute.name) { + /* + * 7130 - we'll mute using some unconnected audio input + * 7134 - we'll probably should switch external mux with gpio + */ if (mute) in = &card(dev).mute; } + if (dev->hw_mute == mute && - dev->hw_input == in) { + dev->hw_input == in) { dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", mute,in->name); return; @@ -260,6 +263,7 @@ static void mute_input_7134(struct saa7134_dev *dev) /* switch gpio-connected external audio mux */ if (0 == card(dev).gpiomask) return; + mask = card(dev).gpiomask; saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio); @@ -339,13 +343,8 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout) set_current_state(TASK_INTERRUPTIBLE); schedule(); } else { -#if 0 - /* hmm, that one doesn't return on wakeup ... */ - msleep_interruptible(timeout); -#else set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(msecs_to_jiffies(timeout)); -#endif } } remove_wait_queue(&dev->thread.wq, &wait); @@ -400,27 +399,10 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) return value; } -#if 0 -static void sifdebug_dump_regs(struct saa7134_dev *dev) -{ - print_regb(AUDIO_STATUS); - print_regb(IDENT_SIF); - print_regb(LEVEL_READOUT1); - print_regb(LEVEL_READOUT2); - print_regb(DCXO_IDENT_CTRL); - print_regb(DEMODULATOR); - print_regb(AGC_GAIN_SELECT); - print_regb(MONITOR_SELECT); - print_regb(FM_DEEMPHASIS); - print_regb(FM_DEMATRIX); - print_regb(SIF_SAMPLE_FREQ); - print_regb(ANALOG_IO_SELECT); -} -#endif static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio) { - __u32 idp,nicam; + __u32 idp, nicam, nicam_status; int retval = -1; switch (audio->mode) { @@ -442,18 +424,24 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au break; case TVAUDIO_NICAM_FM: case TVAUDIO_NICAM_AM: - nicam = saa_readb(SAA7134_NICAM_STATUS); + nicam = saa_readb(SAA7134_AUDIO_STATUS); dprintk("getstereo: nicam=0x%x\n",nicam); - switch (nicam & 0x0b) { - case 0x08: - retval = V4L2_TUNER_SUB_MONO; - break; - case 0x09: - retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - break; - case 0x0a: - retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - break; + if (nicam & 0x1) { + nicam_status = saa_readb(SAA7134_NICAM_STATUS); + dprintk("getstereo: nicam_status=0x%x\n", nicam_status); + + switch (nicam_status & 0x03) { + case 0x01: + retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + break; + case 0x02: + retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + break; + default: + retval = V4L2_TUNER_SUB_MONO; + } + } else { + /* No nicam detected */ } break; } @@ -489,15 +477,15 @@ static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au break; case TVAUDIO_FM_K_STEREO: case TVAUDIO_FM_BG_STEREO: + case TVAUDIO_NICAM_AM: + case TVAUDIO_NICAM_FM: dprintk("setstereo [fm] => %s\n", name[ mode % ARRAY_SIZE(name) ]); reg = fm[ mode % ARRAY_SIZE(fm) ]; saa_writeb(SAA7134_FM_DEMATRIX, reg); break; case TVAUDIO_FM_SAT_STEREO: - case TVAUDIO_NICAM_AM: - case TVAUDIO_NICAM_FM: - /* FIXME */ + /* Not implemented */ break; } return 0; @@ -596,7 +584,7 @@ static int tvaudio_thread(void *data) /* find the exact tv audio norm */ for (audio = UNSET, i = 0; i < TVAUDIO; i++) { if (dev->tvnorm->id != UNSET && - !(dev->tvnorm->id & tvaudio[i].std)) + !(dev->tvnorm->id & tvaudio[i].std)) continue; if (tvaudio[i].carr1 != carrier) continue; @@ -703,24 +691,6 @@ static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit) return 0; } -#if 0 -static int saa_dsp_readl(struct saa7134_dev *dev, int reg, u32 *value) -{ - int err; - - d2printk("dsp read reg 0x%x\n", reg<<2); - saa_readl(reg); - err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_RDB); - if (err < 0) - return err; - *value = saa_readl(reg); - d2printk("dsp read => 0x%06x\n", *value & 0xffffff); - err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_IDA); - if (err < 0) - return err; - return 0; -} -#endif int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value) { @@ -753,31 +723,50 @@ static int getstereo_7133(struct saa7134_dev *dev) static int mute_input_7133(struct saa7134_dev *dev) { u32 reg = 0; + u32 xbarin, xbarout; int mask; + struct saa7134_input *in; + /* Hac 0506 route OSS sound simultanously */ + xbarin = 0x03; switch (dev->input->amux) { case TV: reg = 0x02; + xbarin = 0; break; case LINE1: reg = 0x00; break; case LINE2: case LINE2_LEFT: - reg = 0x01; + reg = 0x09; break; } - if (dev->ctl_mute) + saa_dsp_writel(dev, 0x464 >> 2, xbarin); + if (dev->ctl_mute) { reg = 0x07; + xbarout = 0xbbbbbb; + } else + xbarout = 0xbbbb10; + saa_dsp_writel(dev, 0x46c >> 2, xbarout); + saa_writel(0x594 >> 2, reg); + /* switch gpio-connected external audio mux */ if (0 != card(dev).gpiomask) { mask = card(dev).gpiomask; + + if (card(dev).mute.name && dev->ctl_mute) + in = &card(dev).mute; + else + in = dev->input; + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, dev->input->gpio); - saa7134_track_gpio(dev,dev->input->name); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio); + saa7134_track_gpio(dev,in->name); } + return 0; } diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index 3c33c591cc8..29e51cad2aa 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -130,13 +130,7 @@ static int buffer_prepare(struct videobuf_queue *q, lines = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1; if (lines > VBI_LINE_COUNT) lines = VBI_LINE_COUNT; -#if 1 llength = VBI_LINE_LENGTH; -#else - llength = (norm->h_stop - norm->h_start +1) * 2; - if (llength > VBI_LINE_LENGTH) - llength = VBI_LINE_LENGTH; -#endif size = lines * llength * 2; if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; @@ -178,13 +172,7 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) int llength,lines; lines = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 +1; -#if 1 llength = VBI_LINE_LENGTH; -#else - llength = (norm->h_stop - norm->h_start +1) * 2; - if (llength > VBI_LINE_LENGTH) - llength = VBI_LINE_LENGTH; -#endif *size = lines * llength * 2; if (0 == *count) *count = vbibufs; diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index c0a2ee52053..a4c2f751d09 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1,5 +1,5 @@ /* - * $Id: saa7134-video.c,v 1.30 2005/06/07 19:00:38 nsh Exp $ + * $Id: saa7134-video.c,v 1.36 2005/06/28 23:41:47 mkrufky Exp $ * * device driver for philips saa7134 based TV cards * video4linux video interface @@ -274,7 +274,7 @@ static struct saa7134_tvnorm tvnorms[] = { .h_start = 0, .h_stop = 719, - .video_v_start = 23, + .video_v_start = 23, .video_v_stop = 262, .vbi_v_start_0 = 10, .vbi_v_stop_0 = 21, @@ -1204,7 +1204,6 @@ static int video_open(struct inode *inode, struct file *file) struct list_head *list; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int radio = 0; - list_for_each(list,&saa7134_devlist) { h = list_entry(list, struct saa7134_dev, devlist); if (h->video_dev && (h->video_dev->minor == minor)) @@ -1256,12 +1255,12 @@ static int video_open(struct inode *inode, struct file *file) if (fh->radio) { /* switch to radio mode */ saa7134_tvaudio_setinput(dev,&card(dev).radio); - saa7134_i2c_call_clients(dev,AUDC_SET_RADIO,NULL); + saa7134_i2c_call_clients(dev,AUDC_SET_RADIO, NULL); } else { /* switch to video/vbi mode */ video_mux(dev,dev->ctl_input); } - return 0; + return 0; } static ssize_t @@ -1304,10 +1303,10 @@ video_poll(struct file *file, struct poll_table_struct *wait) } else { down(&fh->cap.lock); if (UNSET == fh->cap.read_off) { - /* need to capture a new frame */ + /* need to capture a new frame */ if (res_locked(fh->dev,RESOURCE_VIDEO)) { - up(&fh->cap.lock); - return POLLERR; + up(&fh->cap.lock); + return POLLERR; } if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) { up(&fh->cap.lock); @@ -1363,6 +1362,36 @@ static int video_release(struct inode *inode, struct file *file) res_free(dev,fh,RESOURCE_VBI); } + /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/ + saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0); + saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0); + saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); + saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); + + if (dev->tuner_type == TUNER_PHILIPS_TDA8290) { + u8 data[2]; + int ret; + struct i2c_msg msg = {.addr=I2C_ADDR_TDA8290, .flags=0, .buf=data, .len = 2}; + data[0] = 0x21; + data[1] = 0xc0; + ret = i2c_transfer(&dev->i2c_adap, &msg, 1); + if (ret != 1) + printk(KERN_ERR "TDA8290 access failure\n"); + msg.addr = I2C_ADDR_TDA8275; + data[0] = 0x30; + data[1] = 0xd0; + ret = i2c_transfer(&dev->i2c_adap, &msg, 1); + if (ret != 1) + printk(KERN_ERR "TDA8275 access failure\n"); + msg.addr = I2C_ADDR_TDA8290; + data[0] = 0x21; + data[1] = 0x80; + i2c_transfer(&dev->i2c_adap, &msg, 1); + data[0] = 0x00; + data[1] = 0x02; + i2c_transfer(&dev->i2c_adap, &msg, 1); + } + /* free stuff */ videobuf_mmap_free(&fh->cap); videobuf_mmap_free(&fh->vbi); @@ -1399,13 +1428,6 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ -#if 0 - if (V4L2_STD_PAL == norm->id) { - /* FIXME */ - f->fmt.vbi.start[0] += 3; - f->fmt.vbi.start[1] += 3*2; - } -#endif } static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, @@ -2120,8 +2142,6 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, memset(t,0,sizeof(*t)); strcpy(t->name, "Radio"); - t->rangelow = (int)(65*16); - t->rangehigh = (int)(108*16); saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index d6b1c0d4d0f..6836c07794f 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -1,5 +1,5 @@ /* - * $Id: saa7134.h,v 1.41 2005/06/07 18:02:26 nsh Exp $ + * $Id: saa7134.h,v 1.48 2005/07/01 08:22:24 nsh Exp $ * * v4l2 device driver for philips saa7134 based TV cards * @@ -46,8 +46,6 @@ #endif #define UNSET (-1U) -/* 2.4 / 2.5 driver compatibility stuff */ - /* ----------------------------------------------------------- */ /* enums */ @@ -159,7 +157,7 @@ struct saa7134_format { #define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33 #define SAA7134_BOARD_NOVAC_PRIMETV7133 34 #define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35 -#define SAA7133_BOARD_UPMOST_PURPLE_TV 36 +#define SAA7134_BOARD_UPMOST_PURPLE_TV 36 #define SAA7134_BOARD_ITEMS_MTV005 37 #define SAA7134_BOARD_CINERGY200 38 #define SAA7134_BOARD_FLYTVPLATINUM_MINI 39 @@ -176,13 +174,17 @@ struct saa7134_format { #define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50 #define SAA7134_BOARD_PROVIDEO_PV952 51 #define SAA7134_BOARD_AVERMEDIA_305 52 -#define SAA7135_BOARD_ASUSTeK_TVFM7135 53 +#define SAA7134_BOARD_ASUSTeK_TVFM7135 53 #define SAA7134_BOARD_FLYTVPLATINUM_FM 54 #define SAA7134_BOARD_FLYDVBTDUO 55 #define SAA7134_BOARD_AVERMEDIA_307 56 #define SAA7134_BOARD_AVERMEDIA_GO_007_FM 57 #define SAA7134_BOARD_ADS_INSTANT_TV 58 #define SAA7134_BOARD_KWORLD_VSTREAM_XPERT 59 +#define SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS 60 +#define SAA7134_BOARD_PHILIPS_TOUGH 61 +#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII 62 +#define SAA7134_BOARD_KWORLD_XPERT 63 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 @@ -213,6 +215,10 @@ struct saa7134_board { /* i2c chip info */ unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + unsigned int tda9887_conf; /* peripheral I/O */ @@ -403,9 +409,12 @@ struct saa7134_dev { /* config info */ unsigned int board; unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + unsigned int tda9887_conf; unsigned int gpio_value; - unsigned int irq2_mask; /* i2c i/o */ struct i2c_adapter i2c_adap; -- cgit v1.2.3 From af9eeed2d78cb9c672bdc750133506670713fdf8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:59:06 -0700 Subject: [PATCH] v4l: tuner-3026 - replace obsolete ioctl value - obsolete TUNER_SET_TVFREQ changed to VIDIOCSFREQ. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/tuner-3036.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c index 51748c6578d..7d825e510ff 100644 --- a/drivers/media/video/tuner-3036.c +++ b/drivers/media/video/tuner-3036.c @@ -152,7 +152,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch (cmd) { - case TUNER_SET_TVFREQ: + case VIDIOCSFREQ: set_tv_freq(client, *iarg); break; -- cgit v1.2.3 From 833e9a1abe8cdfc037964d3240d57bb8ff94bff0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 Jul 2005 13:59:07 -0700 Subject: [PATCH] v4l: TV EEPROM - Eliminated unused code. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/tveeprom.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 0f03c25489f..e8d9440977c 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -400,14 +400,6 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data } } -#if 0 - if (t_format < sizeof(hauppauge_tuner_fmt)/sizeof(struct HAUPPAUGE_TUNER_FMT)) { - tvee->tuner_formats = hauppauge_tuner_fmt[t_format].id; - t_fmt_name = hauppauge_tuner_fmt[t_format].name; - } else { - t_fmt_name = ""; - } -#endif TVEEPROM_KERN_INFO("Hauppauge: model = %d, rev = %s, serial# = %d\n", tvee->model, @@ -482,6 +474,7 @@ static unsigned short normal_i2c[] = { 0xa0 >> 1, I2C_CLIENT_END, }; + I2C_CLIENT_INSMOD; struct i2c_driver i2c_driver_tveeprom; -- cgit v1.2.3 From 55ee3b8365fd5d301b9076eea739146f2b91e82c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 12 Jul 2005 13:59:08 -0700 Subject: [PATCH] v4l: broken hybrid dvb inclusion Always include dvb frontend code for hybrid cx88 and saa7134 boards. Signed-off-by: Michael Krufky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/cx88/cx88-dvb.c | 5 +++++ drivers/media/video/saa7134/saa7134-dvb.c | 3 +++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 5544e1d6a34..8db68f2d135 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -30,6 +30,11 @@ #include #include +#define CONFIG_DVB_MT352 1 +#define CONFIG_DVB_CX22702 1 +#define CONFIG_DVB_OR51132 1 +#define CONFIG_DVB_LGDT3302 1 + #include "cx88.h" #include "dvb-pll.h" diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 3959a571486..334bc185009 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -30,6 +30,9 @@ #include #include +#define CONFIG_DVB_MT352 1 +#define CONFIG_DVB_TDA1004X 1 + #include "saa7134-reg.h" #include "saa7134.h" -- cgit v1.2.3 From f6a80ea8ed44de0b19c42d41928be37a186a3f41 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:01 -0700 Subject: [PATCH] device-mapper multipath: Barriers not supported dm multipath will report barriers as not supported with this patch. Signed-off-by: Lars Marowsky-Bree Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-mpath.c | 6 ++++++ drivers/md/dm-snap.c | 2 +- drivers/md/dm.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 0c1b8520ef8..84cdb700a24 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -765,6 +765,9 @@ static int multipath_map(struct dm_target *ti, struct bio *bio, struct mpath_io *mpio; struct multipath *m = (struct multipath *) ti->private; + if (bio_barrier(bio)) + return -EOPNOTSUPP; + mpio = mempool_alloc(m->mpio_pool, GFP_NOIO); dm_bio_record(&mpio->details, bio); @@ -988,6 +991,9 @@ static int do_end_io(struct multipath *m, struct bio *bio, if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio)) return error; + if (error == -EOPNOTSUPP) + return error; + spin_lock(&m->lock); if (!m->nr_valid_paths) { if (!m->queue_if_no_path || m->suspended) { diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 7e691ab9a74..594d1f6b478 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -777,7 +777,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, /* Full snapshots are not usable */ if (!s->valid) - return -1; + return -EIO; /* * Write to snapshot - higher level takes care of RW/RO diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f6b03957efc..5d40555b42b 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -384,7 +384,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone, /* error the io and bail out */ struct dm_io *io = tio->io; free_tio(tio->io->md, tio); - dec_pending(io, -EIO); + dec_pending(io, r); bio_put(clone); } } -- cgit v1.2.3 From a044d016896d2717694003f00d31a98194077511 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:02 -0700 Subject: [PATCH] device-mapper multipath: Flush workqueue when destroying The multipath destructor must flush its workqueue. Otherwise items that reference the destroyed object could remain. From: "goggin, edward" Signed-off-by: Lars Marowsky-Bree Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-mpath.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 84cdb700a24..fa72f015320 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -752,6 +752,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, static void multipath_dtr(struct dm_target *ti) { struct multipath *m = (struct multipath *) ti->private; + + flush_workqueue(kmultipathd); free_multipath(m); } -- cgit v1.2.3 From 436d41087d047b61f8ab0604dc74fff3240a8933 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:03 -0700 Subject: [PATCH] device-mapper multipath: Avoid possible suspension deadlock To avoid deadlock when suspending a multipath device after all its paths have failed, stop queueing any I/O that is about to fail *before* calling freeze_bdev instead of after. Instead of setting a multipath 'suspended' flag which would have to be reset if an error occurs during the process, save the previous queueing state and leave userspace to restore if it wishes. Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-mpath.c | 25 +++++++++++++------------ drivers/md/dm.c | 12 +++++++----- 2 files changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index fa72f015320..98da8eee2d2 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -72,7 +72,7 @@ struct multipath { unsigned queue_io; /* Must we queue all I/O? */ unsigned queue_if_no_path; /* Queue I/O if last path fails? */ - unsigned suspended; /* Has dm core suspended our I/O? */ + unsigned saved_queue_if_no_path;/* Saved state during suspension */ struct work_struct process_queued_ios; struct bio_list queued_ios; @@ -304,7 +304,7 @@ static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio, m->queue_size--; if ((pgpath && m->queue_io) || - (!pgpath && m->queue_if_no_path && !m->suspended)) { + (!pgpath && m->queue_if_no_path)) { /* Queue for the daemon to resubmit */ bio_list_add(&m->queued_ios, bio); m->queue_size++; @@ -333,6 +333,7 @@ static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path) spin_lock_irqsave(&m->lock, flags); + m->saved_queue_if_no_path = m->queue_if_no_path; m->queue_if_no_path = queue_if_no_path; if (!m->queue_if_no_path) queue_work(kmultipathd, &m->process_queued_ios); @@ -391,7 +392,7 @@ static void process_queued_ios(void *data) pgpath = m->current_pgpath; if ((pgpath && m->queue_io) || - (!pgpath && m->queue_if_no_path && !m->suspended)) + (!pgpath && m->queue_if_no_path)) must_queue = 1; init_required = m->pg_init_required; @@ -998,7 +999,7 @@ static int do_end_io(struct multipath *m, struct bio *bio, spin_lock(&m->lock); if (!m->nr_valid_paths) { - if (!m->queue_if_no_path || m->suspended) { + if (!m->queue_if_no_path) { spin_unlock(&m->lock); return -EIO; } else { @@ -1059,27 +1060,27 @@ static int multipath_end_io(struct dm_target *ti, struct bio *bio, /* * Suspend can't complete until all the I/O is processed so if - * the last path failed we will now error any queued I/O. + * the last path fails we must error any remaining I/O. + * Note that if the freeze_bdev fails while suspending, the + * queue_if_no_path state is lost - userspace should reset it. */ static void multipath_presuspend(struct dm_target *ti) { struct multipath *m = (struct multipath *) ti->private; - unsigned long flags; - spin_lock_irqsave(&m->lock, flags); - m->suspended = 1; - if (m->queue_if_no_path) - queue_work(kmultipathd, &m->process_queued_ios); - spin_unlock_irqrestore(&m->lock, flags); + queue_if_no_path(m, 0); } +/* + * Restore the queue_if_no_path setting. + */ static void multipath_resume(struct dm_target *ti) { struct multipath *m = (struct multipath *) ti->private; unsigned long flags; spin_lock_irqsave(&m->lock, flags); - m->suspended = 0; + m->queue_if_no_path = m->saved_queue_if_no_path; spin_unlock_irqrestore(&m->lock, flags); } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 5d40555b42b..bb3ad79c14d 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1055,14 +1055,17 @@ int dm_suspend(struct mapped_device *md) if (test_bit(DMF_BLOCK_IO, &md->flags)) goto out_read_unlock; - error = __lock_fs(md); - if (error) - goto out_read_unlock; - map = dm_get_table(md); if (map) + /* This does not get reverted if there's an error later. */ dm_table_presuspend_targets(map); + error = __lock_fs(md); + if (error) { + dm_table_put(map); + goto out_read_unlock; + } + up_read(&md->lock); /* @@ -1121,7 +1124,6 @@ int dm_suspend(struct mapped_device *md) return 0; out_unfreeze: - /* FIXME Undo dm_table_presuspend_targets */ __unlock_fs(md); clear_bit(DMF_BLOCK_IO, &md->flags); out_write_unlock: -- cgit v1.2.3 From c3cd4f6b275da0f594797b73f721a4185335478f Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:04 -0700 Subject: [PATCH] device-mapper multipath: Fix pg initialisation races Prevent more than one priority group initialisation function from being outstanding at once. Otherwise the completion functions interfere with each other. Also, reloading the table could reference a freed pointer. Only reset queue_io in pg_init_complete if another pg_init isn't required. Skip process_queued_ios if the queue is empty so that we only trigger a pg_init if there's I/O. Signed-off-by: Lars Marowsky-Bree Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-mpath.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 98da8eee2d2..785806bdb24 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -63,6 +63,7 @@ struct multipath { unsigned nr_priority_groups; struct list_head priority_groups; unsigned pg_init_required; /* pg_init needs calling? */ + unsigned pg_init_in_progress; /* Only one pg_init allowed at once */ unsigned nr_valid_paths; /* Total number of usable paths */ struct pgpath *current_pgpath; @@ -308,7 +309,8 @@ static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio, /* Queue for the daemon to resubmit */ bio_list_add(&m->queued_ios, bio); m->queue_size++; - if (m->pg_init_required || !m->queue_io) + if ((m->pg_init_required && !m->pg_init_in_progress) || + !m->queue_io) queue_work(kmultipathd, &m->process_queued_ios); pgpath = NULL; r = 0; @@ -335,7 +337,7 @@ static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path) m->saved_queue_if_no_path = m->queue_if_no_path; m->queue_if_no_path = queue_if_no_path; - if (!m->queue_if_no_path) + if (!m->queue_if_no_path && m->queue_size) queue_work(kmultipathd, &m->process_queued_ios); spin_unlock_irqrestore(&m->lock, flags); @@ -380,25 +382,31 @@ static void process_queued_ios(void *data) { struct multipath *m = (struct multipath *) data; struct hw_handler *hwh = &m->hw_handler; - struct pgpath *pgpath; - unsigned init_required, must_queue = 0; + struct pgpath *pgpath = NULL; + unsigned init_required = 0, must_queue = 1; unsigned long flags; spin_lock_irqsave(&m->lock, flags); + if (!m->queue_size) + goto out; + if (!m->current_pgpath) __choose_pgpath(m); pgpath = m->current_pgpath; - if ((pgpath && m->queue_io) || - (!pgpath && m->queue_if_no_path)) - must_queue = 1; + if ((pgpath && !m->queue_io) || + (!pgpath && !m->queue_if_no_path)) + must_queue = 0; - init_required = m->pg_init_required; - if (init_required) + if (m->pg_init_required && !m->pg_init_in_progress) { m->pg_init_required = 0; + m->pg_init_in_progress = 1; + init_required = 1; + } +out: spin_unlock_irqrestore(&m->lock, flags); if (init_required) @@ -843,7 +851,7 @@ static int reinstate_path(struct pgpath *pgpath) pgpath->path.is_active = 1; m->current_pgpath = NULL; - if (!m->nr_valid_paths++) + if (!m->nr_valid_paths++ && m->queue_size) queue_work(kmultipathd, &m->process_queued_ios); queue_work(kmultipathd, &m->trigger_event); @@ -969,12 +977,13 @@ void dm_pg_init_complete(struct path *path, unsigned err_flags) bypass_pg(m, pg, 1); spin_lock_irqsave(&m->lock, flags); - if (!err_flags) - m->queue_io = 0; - else { + if (err_flags) { m->current_pgpath = NULL; m->current_pg = NULL; - } + } else if (!m->pg_init_required) + m->queue_io = 0; + + m->pg_init_in_progress = 0; queue_work(kmultipathd, &m->process_queued_ios); spin_unlock_irqrestore(&m->lock, flags); } -- cgit v1.2.3 From 93c534aefb906824d71ea779ed0c7f1573843f4e Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:05 -0700 Subject: [PATCH] device-mapper: Fix dm_swap_table error cases Fix dm_swap_table() __bind error cases: a missing unlock, and EINVAL preferable to EPERM. Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index bb3ad79c14d..54fabbf0667 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -966,23 +966,20 @@ static void __flush_deferred_io(struct mapped_device *md, struct bio *c) */ int dm_swap_table(struct mapped_device *md, struct dm_table *table) { - int r; + int r = -EINVAL; down_write(&md->lock); /* device must be suspended */ - if (!test_bit(DMF_SUSPENDED, &md->flags)) { - up_write(&md->lock); - return -EPERM; - } + if (!test_bit(DMF_SUSPENDED, &md->flags)) + goto out; __unbind(md); r = __bind(md, table); - if (r) - return r; +out: up_write(&md->lock); - return 0; + return r; } /* -- cgit v1.2.3 From d5e404c10a98fc2979643476851e9cbdb1944812 Mon Sep 17 00:00:00 2001 From: Alasdair G Kergon Date: Tue, 12 Jul 2005 15:53:05 -0700 Subject: [PATCH] device-mapper snapshots: Handle origin extension Handle writes to a snapshot-origin device that has been extended since the snapshot was taken. Signed-off-by: Alasdair G Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-snap.c | 4 ++++ drivers/md/dm-table.c | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 594d1f6b478..ab54f99b7c3 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -931,6 +931,10 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) if (!snap->valid) continue; + /* Nothing to do if writing beyond end of snapshot */ + if (bio->bi_sector >= dm_table_get_size(snap->table)) + continue; + down_write(&snap->lock); /* diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 18e9b9953fc..a5a4c0ed8a1 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -943,6 +943,7 @@ EXPORT_SYMBOL(dm_vcalloc); EXPORT_SYMBOL(dm_get_device); EXPORT_SYMBOL(dm_put_device); EXPORT_SYMBOL(dm_table_event); +EXPORT_SYMBOL(dm_table_get_size); EXPORT_SYMBOL(dm_table_get_mode); EXPORT_SYMBOL(dm_table_put); EXPORT_SYMBOL(dm_table_get); -- cgit v1.2.3