···964964W: http://www.lm-sensors.nu/965965S: Maintained966966967967+HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER968968+P: Robert Love969969+M: rlove@rlove.org970970+M: linux-kernel@vger.kernel.org971971+W: http://www.kernel.org/pub/linux/kernel/people/rml/hdaps/972972+S: Maintained973973+967974HARMONY SOUND DRIVER968975P: Kyle McMartin969976M: kyle@parisc-linux.org
+17
drivers/hwmon/Kconfig
···411411 This driver can also be built as a module. If so, the module412412 will be called w83627ehf.413413414414+config SENSORS_HDAPS415415+ tristate "IBM Hard Drive Active Protection System (hdaps)"416416+ depends on HWMON && INPUT && X86417417+ default n418418+ help419419+ This driver provides support for the IBM Hard Drive Active Protection420420+ System (hdaps), which provides an accelerometer and other misc. data.421421+ Supported laptops include the IBM ThinkPad T41, T42, T43, and R51.422422+ The accelerometer data is readable via sysfs.423423+424424+ This driver also provides an input class device, allowing the425425+ laptop to act as a pinball machine-esque mouse. This is off by426426+ default but enabled via sysfs or the module parameter "mousedev".427427+428428+ Say Y here if you have an applicable laptop and want to experience429429+ the awesome power of hdaps.430430+414431config HWMON_DEBUG_CHIP415432 bool "Hardware Monitoring Chip debugging messages"416433 depends on HWMON
···11+/*22+ * drivers/hwmon/hdaps.c - driver for IBM's Hard Drive Active Protection System33+ *44+ * Copyright (C) 2005 Robert Love <rml@novell.com>55+ * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>66+ *77+ * The HardDisk Active Protection System (hdaps) is present in the IBM ThinkPad88+ * T41, T42, T43, R51, and X40, at least. It provides a basic two-axis99+ * accelerometer and other data, such as the device's temperature.1010+ *1111+ * Based on the document by Mark A. Smith available at1212+ * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html and a lot of trial1313+ * and error.1414+ *1515+ * This program is free software; you can redistribute it and/or modify it1616+ * under the terms of the GNU General Public License v2 as published by the1717+ * Free Software Foundation.1818+ *1919+ * This program is distributed in the hope that it will be useful, but WITHOUT2020+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or2121+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for2222+ * more details.2323+ *2424+ * You should have received a copy of the GNU General Public License along with2525+ * this program; if not, write to the Free Software Foundation, Inc.,2626+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA2727+ */2828+2929+#include <linux/delay.h>3030+#include <linux/device.h>3131+#include <linux/input.h>3232+#include <linux/kernel.h>3333+#include <linux/module.h>3434+#include <linux/timer.h>3535+#include <linux/dmi.h>3636+#include <asm/io.h>3737+3838+#define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */3939+#define HDAPS_NR_PORTS 0x30 /* 0x1600 - 0x162f */4040+4141+#define STATE_FRESH 0x50 /* accelerometer data is fresh */4242+4343+#define REFRESH_ASYNC 0x00 /* do asynchronous refresh */4444+#define REFRESH_SYNC 0x01 /* do synchronous refresh */4545+4646+#define HDAPS_PORT_STATE 0x1611 /* device state */4747+#define HDAPS_PORT_YPOS 0x1612 /* y-axis position */4848+#define HDAPS_PORT_XPOS 0x1614 /* x-axis position */4949+#define HDAPS_PORT_TEMP1 0x1616 /* device temperature, in celcius */5050+#define HDAPS_PORT_YVAR 0x1617 /* y-axis variance (what is this?) */5151+#define HDAPS_PORT_XVAR 0x1619 /* x-axis variance (what is this?) */5252+#define HDAPS_PORT_TEMP2 0x161b /* device temperature (again?) */5353+#define HDAPS_PORT_UNKNOWN 0x161c /* what is this? */5454+#define HDAPS_PORT_KMACT 0x161d /* keyboard or mouse activity */5555+5656+#define HDAPS_READ_MASK 0xff /* some reads have the low 8 bits set */5757+5858+#define KEYBD_MASK 0x20 /* set if keyboard activity */5959+#define MOUSE_MASK 0x40 /* set if mouse activity */6060+#define KEYBD_ISSET(n) (!! (n & KEYBD_MASK)) /* keyboard used? */6161+#define MOUSE_ISSET(n) (!! (n & MOUSE_MASK)) /* mouse used? */6262+6363+#define INIT_TIMEOUT_MSECS 4000 /* wait up to 4s for device init ... */6464+#define INIT_WAIT_MSECS 200 /* ... in 200ms increments */6565+6666+static struct platform_device *pdev;6767+static struct input_dev hdaps_idev;6868+static struct timer_list hdaps_timer;6969+static unsigned int hdaps_mousedev_threshold = 4;7070+static unsigned long hdaps_poll_ms = 50;7171+static unsigned int hdaps_mousedev;7272+static unsigned int hdaps_invert;7373+static u8 km_activity;7474+static int rest_x;7575+static int rest_y;7676+7777+static DECLARE_MUTEX(hdaps_sem);7878+7979+/*8080+ * __get_latch - Get the value from a given port. Callers must hold hdaps_sem.8181+ */8282+static inline u8 __get_latch(u16 port)8383+{8484+ return inb(port) & HDAPS_READ_MASK;8585+}8686+8787+/*8888+ * __check_latch - Check a port latch for a given value. Callers must hold8989+ * hdaps_sem. Returns zero if the port contains the given value.9090+ */9191+static inline unsigned int __check_latch(u16 port, u8 val)9292+{9393+ if (__get_latch(port) == val)9494+ return 0;9595+ return -EINVAL;9696+}9797+9898+/*9999+ * __wait_latch - Wait up to 100us for a port latch to get a certain value,100100+ * returning zero if the value is obtained. Callers must hold hdaps_sem.101101+ */102102+static unsigned int __wait_latch(u16 port, u8 val)103103+{104104+ unsigned int i;105105+106106+ for (i = 0; i < 20; i++) {107107+ if (!__check_latch(port, val))108108+ return 0;109109+ udelay(5);110110+ }111111+112112+ return -EINVAL;113113+}114114+115115+/*116116+ * __device_refresh - Request a refresh from the accelerometer.117117+ *118118+ * If sync is REFRESH_SYNC, we perform a synchronous refresh and will wait.119119+ * Returns zero if successful and nonzero on error.120120+ *121121+ * If sync is REFRESH_ASYNC, we merely kick off a new refresh if the device is122122+ * not up-to-date. Always returns zero.123123+ *124124+ * Callers must hold hdaps_sem.125125+ */126126+static int __device_refresh(unsigned int sync)127127+{128128+ u8 state;129129+130130+ udelay(100);131131+132132+ state = inb(0x1604);133133+ if (state == STATE_FRESH)134134+ return 0;135135+136136+ outb(0x11, 0x1610);137137+ outb(0x01, 0x161f);138138+ if (sync == REFRESH_ASYNC)139139+ return 0;140140+141141+ return __wait_latch(0x1604, STATE_FRESH);142142+}143143+144144+/*145145+ * __device_complete - Indicate to the accelerometer that we are done reading146146+ * data, and then initiate an async refresh. Callers must hold hdaps_sem.147147+ */148148+static inline void __device_complete(void)149149+{150150+ inb(0x161f);151151+ inb(0x1604);152152+ __device_refresh(REFRESH_ASYNC);153153+}154154+155155+static int __hdaps_readb_one(unsigned int port, u8 *val)156156+{157157+ /* do a sync refresh -- we need to be sure that we read fresh data */158158+ if (__device_refresh(REFRESH_SYNC))159159+ return -EIO;160160+161161+ *val = inb(port);162162+ __device_complete();163163+164164+ return 0;165165+}166166+167167+/*168168+ * hdaps_readb_one - reads a byte from a single I/O port, placing the value in169169+ * the given pointer. Returns zero on success or a negative error on failure.170170+ * Can sleep.171171+ */172172+static int hdaps_readb_one(unsigned int port, u8 *val)173173+{174174+ int ret;175175+176176+ down(&hdaps_sem);177177+ ret = __hdaps_readb_one(port, val);178178+ up(&hdaps_sem);179179+180180+ return ret;181181+}182182+183183+static int __hdaps_read_pair(unsigned int port1, unsigned int port2,184184+ int *x, int *y)185185+{186186+ /* do a sync refresh -- we need to be sure that we read fresh data */187187+ if (__device_refresh(REFRESH_SYNC))188188+ return -EIO;189189+190190+ *y = inw(port2);191191+ *x = inw(port1);192192+ km_activity = inb(HDAPS_PORT_KMACT);193193+ __device_complete();194194+195195+ /* if hdaps_invert is set, negate the two values */196196+ if (hdaps_invert) {197197+ *x = -*x;198198+ *y = -*y;199199+ }200200+201201+ return 0;202202+}203203+204204+/*205205+ * hdaps_read_pair - reads the values from a pair of ports, placing the values206206+ * in the given pointers. Returns zero on success. Can sleep.207207+ */208208+static int hdaps_read_pair(unsigned int port1, unsigned int port2,209209+ int *val1, int *val2)210210+{211211+ int ret;212212+213213+ down(&hdaps_sem);214214+ ret = __hdaps_read_pair(port1, port2, val1, val2);215215+ up(&hdaps_sem);216216+217217+ return ret;218218+}219219+220220+/* initialize the accelerometer */221221+static int hdaps_device_init(void)222222+{223223+ unsigned int total_msecs = INIT_TIMEOUT_MSECS;224224+ int ret = -ENXIO;225225+226226+ down(&hdaps_sem);227227+228228+ outb(0x13, 0x1610);229229+ outb(0x01, 0x161f);230230+ if (__wait_latch(0x161f, 0x00))231231+ goto out;232232+233233+ /*234234+ * The 0x03 value appears to only work on some thinkpads, such as the235235+ * T42p. Others return 0x01.236236+ *237237+ * The 0x02 value occurs when the chip has been previously initialized.238238+ */239239+ if (__check_latch(0x1611, 0x03) &&240240+ __check_latch(0x1611, 0x02) &&241241+ __check_latch(0x1611, 0x01))242242+ goto out;243243+244244+ printk(KERN_DEBUG "hdaps: initial latch check good (0x%02x).\n",245245+ __get_latch(0x1611));246246+247247+ outb(0x17, 0x1610);248248+ outb(0x81, 0x1611);249249+ outb(0x01, 0x161f);250250+ if (__wait_latch(0x161f, 0x00))251251+ goto out;252252+ if (__wait_latch(0x1611, 0x00))253253+ goto out;254254+ if (__wait_latch(0x1612, 0x60))255255+ goto out;256256+ if (__wait_latch(0x1613, 0x00))257257+ goto out;258258+ outb(0x14, 0x1610);259259+ outb(0x01, 0x1611);260260+ outb(0x01, 0x161f);261261+ if (__wait_latch(0x161f, 0x00))262262+ goto out;263263+ outb(0x10, 0x1610);264264+ outb(0xc8, 0x1611);265265+ outb(0x00, 0x1612);266266+ outb(0x02, 0x1613);267267+ outb(0x01, 0x161f);268268+ if (__wait_latch(0x161f, 0x00))269269+ goto out;270270+ if (__device_refresh(REFRESH_SYNC))271271+ goto out;272272+ if (__wait_latch(0x1611, 0x00))273273+ goto out;274274+275275+ /* we have done our dance, now let's wait for the applause */276276+ while (total_msecs > 0) {277277+ u8 ignored;278278+279279+ /* a read of the device helps push it into action */280280+ __hdaps_readb_one(HDAPS_PORT_UNKNOWN, &ignored);281281+ if (!__wait_latch(0x1611, 0x02)) {282282+ ret = 0;283283+ break;284284+ }285285+286286+ msleep(INIT_WAIT_MSECS);287287+ total_msecs -= INIT_WAIT_MSECS;288288+ }289289+290290+out:291291+ up(&hdaps_sem);292292+ return ret;293293+}294294+295295+296296+/* Input class stuff */297297+298298+/*299299+ * hdaps_calibrate - Zero out our "resting" values. Callers must hold hdaps_sem.300300+ */301301+static void hdaps_calibrate(void)302302+{303303+ int x, y;304304+305305+ if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))306306+ return;307307+308308+ rest_x = x;309309+ rest_y = y;310310+}311311+312312+static void hdaps_mousedev_poll(unsigned long unused)313313+{314314+ int x, y;315315+316316+ /* Cannot sleep. Try nonblockingly. If we fail, try again later. */317317+ if (down_trylock(&hdaps_sem)) {318318+ mod_timer(&hdaps_timer,jiffies+msecs_to_jiffies(hdaps_poll_ms));319319+ return;320320+ }321321+322322+ if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))323323+ goto out;324324+325325+ x -= rest_x;326326+ y -= rest_y;327327+ if (abs(x) > hdaps_mousedev_threshold)328328+ input_report_rel(&hdaps_idev, REL_X, x);329329+ if (abs(y) > hdaps_mousedev_threshold)330330+ input_report_rel(&hdaps_idev, REL_Y, y);331331+ input_sync(&hdaps_idev);332332+333333+ mod_timer(&hdaps_timer, jiffies + msecs_to_jiffies(hdaps_poll_ms));334334+335335+out:336336+ up(&hdaps_sem);337337+}338338+339339+/*340340+ * hdaps_mousedev_enable - enable the input class device. Can sleep.341341+ */342342+static void hdaps_mousedev_enable(void)343343+{344344+ down(&hdaps_sem);345345+346346+ /* calibrate the device before enabling */347347+ hdaps_calibrate();348348+349349+ /* initialize the input class */350350+ init_input_dev(&hdaps_idev);351351+ hdaps_idev.dev = &pdev->dev;352352+ hdaps_idev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);353353+ hdaps_idev.relbit[0] = BIT(REL_X) | BIT(REL_Y);354354+ hdaps_idev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT);355355+ input_register_device(&hdaps_idev);356356+357357+ /* start up our timer */358358+ init_timer(&hdaps_timer);359359+ hdaps_timer.function = hdaps_mousedev_poll;360360+ hdaps_timer.expires = jiffies + msecs_to_jiffies(hdaps_poll_ms);361361+ add_timer(&hdaps_timer);362362+363363+ hdaps_mousedev = 1;364364+365365+ up(&hdaps_sem);366366+367367+ printk(KERN_INFO "hdaps: input device enabled.\n");368368+}369369+370370+/*371371+ * hdaps_mousedev_disable - disable the input class device. Caller must hold372372+ * hdaps_sem.373373+ */374374+static void hdaps_mousedev_disable(void)375375+{376376+ down(&hdaps_sem);377377+ if (hdaps_mousedev) {378378+ hdaps_mousedev = 0;379379+ del_timer_sync(&hdaps_timer);380380+ input_unregister_device(&hdaps_idev);381381+ }382382+ up(&hdaps_sem);383383+}384384+385385+386386+/* Device model stuff */387387+388388+static int hdaps_probe(struct device *dev)389389+{390390+ int ret;391391+392392+ ret = hdaps_device_init();393393+ if (ret)394394+ return ret;395395+396396+ printk(KERN_INFO "hdaps: device successfully initialized.\n");397397+ return 0;398398+}399399+400400+static int hdaps_resume(struct device *dev, u32 level)401401+{402402+ if (level == RESUME_ENABLE)403403+ return hdaps_device_init();404404+ return 0;405405+}406406+407407+static struct device_driver hdaps_driver = {408408+ .name = "hdaps",409409+ .bus = &platform_bus_type,410410+ .owner = THIS_MODULE,411411+ .probe = hdaps_probe,412412+ .resume = hdaps_resume413413+};414414+415415+416416+/* Sysfs Files */417417+418418+static ssize_t hdaps_position_show(struct device *dev,419419+ struct device_attribute *attr, char *buf)420420+{421421+ int ret, x, y;422422+423423+ ret = hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);424424+ if (ret)425425+ return ret;426426+427427+ return sprintf(buf, "(%d,%d)\n", x, y);428428+}429429+430430+static ssize_t hdaps_variance_show(struct device *dev,431431+ struct device_attribute *attr, char *buf)432432+{433433+ int ret, x, y;434434+435435+ ret = hdaps_read_pair(HDAPS_PORT_XVAR, HDAPS_PORT_YVAR, &x, &y);436436+ if (ret)437437+ return ret;438438+439439+ return sprintf(buf, "(%d,%d)\n", x, y);440440+}441441+442442+static ssize_t hdaps_temp1_show(struct device *dev,443443+ struct device_attribute *attr, char *buf)444444+{445445+ u8 temp;446446+ int ret;447447+448448+ ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp);449449+ if (ret < 0)450450+ return ret;451451+452452+ return sprintf(buf, "%u\n", temp);453453+}454454+455455+static ssize_t hdaps_temp2_show(struct device *dev,456456+ struct device_attribute *attr, char *buf)457457+{458458+ u8 temp;459459+ int ret;460460+461461+ ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp);462462+ if (ret < 0)463463+ return ret;464464+465465+ return sprintf(buf, "%u\n", temp);466466+}467467+468468+static ssize_t hdaps_keyboard_activity_show(struct device *dev,469469+ struct device_attribute *attr,470470+ char *buf)471471+{472472+ return sprintf(buf, "%u\n", KEYBD_ISSET(km_activity));473473+}474474+475475+static ssize_t hdaps_mouse_activity_show(struct device *dev,476476+ struct device_attribute *attr,477477+ char *buf)478478+{479479+ return sprintf(buf, "%u\n", MOUSE_ISSET(km_activity));480480+}481481+482482+static ssize_t hdaps_calibrate_show(struct device *dev,483483+ struct device_attribute *attr, char *buf)484484+{485485+ return sprintf(buf, "(%d,%d)\n", rest_x, rest_y);486486+}487487+488488+static ssize_t hdaps_calibrate_store(struct device *dev,489489+ struct device_attribute *attr,490490+ const char *buf, size_t count)491491+{492492+ down(&hdaps_sem);493493+ hdaps_calibrate();494494+ up(&hdaps_sem);495495+496496+ return count;497497+}498498+499499+static ssize_t hdaps_invert_show(struct device *dev,500500+ struct device_attribute *attr, char *buf)501501+{502502+ return sprintf(buf, "%u\n", hdaps_invert);503503+}504504+505505+static ssize_t hdaps_invert_store(struct device *dev,506506+ struct device_attribute *attr,507507+ const char *buf, size_t count)508508+{509509+ int invert;510510+511511+ if (sscanf(buf, "%d", &invert) != 1 || (invert != 1 && invert != 0))512512+ return -EINVAL;513513+514514+ hdaps_invert = invert;515515+ hdaps_calibrate();516516+517517+ return count;518518+}519519+520520+static ssize_t hdaps_mousedev_show(struct device *dev,521521+ struct device_attribute *attr, char *buf)522522+{523523+ return sprintf(buf, "%d\n", hdaps_mousedev);524524+}525525+526526+static ssize_t hdaps_mousedev_store(struct device *dev,527527+ struct device_attribute *attr,528528+ const char *buf, size_t count)529529+{530530+ int enable;531531+532532+ if (sscanf(buf, "%d", &enable) != 1)533533+ return -EINVAL;534534+535535+ if (enable == 1)536536+ hdaps_mousedev_enable();537537+ else if (enable == 0)538538+ hdaps_mousedev_disable();539539+ else540540+ return -EINVAL;541541+542542+ return count;543543+}544544+545545+static ssize_t hdaps_poll_show(struct device *dev,546546+ struct device_attribute *attr, char *buf)547547+{548548+ return sprintf(buf, "%lu\n", hdaps_poll_ms);549549+}550550+551551+static ssize_t hdaps_poll_store(struct device *dev,552552+ struct device_attribute *attr,553553+ const char *buf, size_t count)554554+{555555+ unsigned int poll;556556+557557+ if (sscanf(buf, "%u", &poll) != 1 || poll == 0)558558+ return -EINVAL;559559+ hdaps_poll_ms = poll;560560+561561+ return count;562562+}563563+564564+static ssize_t hdaps_threshold_show(struct device *dev,565565+ struct device_attribute *attr, char *buf)566566+{567567+ return sprintf(buf, "%u\n", hdaps_mousedev_threshold);568568+}569569+570570+static ssize_t hdaps_threshold_store(struct device *dev,571571+ struct device_attribute *attr,572572+ const char *buf, size_t count)573573+{574574+ unsigned int threshold;575575+576576+ if (sscanf(buf, "%u", &threshold) != 1 || threshold == 0)577577+ return -EINVAL;578578+ hdaps_mousedev_threshold = threshold;579579+580580+ return count;581581+}582582+583583+static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL);584584+static DEVICE_ATTR(variance, 0444, hdaps_variance_show, NULL);585585+static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL);586586+static DEVICE_ATTR(temp2, 0444, hdaps_temp2_show, NULL);587587+static DEVICE_ATTR(keyboard_activity, 0444, hdaps_keyboard_activity_show, NULL);588588+static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL);589589+static DEVICE_ATTR(calibrate, 0644, hdaps_calibrate_show,hdaps_calibrate_store);590590+static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store);591591+static DEVICE_ATTR(mousedev, 0644, hdaps_mousedev_show, hdaps_mousedev_store);592592+static DEVICE_ATTR(mousedev_poll_ms, 0644, hdaps_poll_show, hdaps_poll_store);593593+static DEVICE_ATTR(mousedev_threshold, 0644, hdaps_threshold_show,594594+ hdaps_threshold_store);595595+596596+static struct attribute *hdaps_attributes[] = {597597+ &dev_attr_position.attr,598598+ &dev_attr_variance.attr,599599+ &dev_attr_temp1.attr,600600+ &dev_attr_temp2.attr,601601+ &dev_attr_keyboard_activity.attr,602602+ &dev_attr_mouse_activity.attr,603603+ &dev_attr_calibrate.attr,604604+ &dev_attr_mousedev.attr,605605+ &dev_attr_mousedev_threshold.attr,606606+ &dev_attr_mousedev_poll_ms.attr,607607+ &dev_attr_invert.attr,608608+ NULL,609609+};610610+611611+static struct attribute_group hdaps_attribute_group = {612612+ .attrs = hdaps_attributes,613613+};614614+615615+616616+/* Module stuff */617617+618618+/*619619+ * XXX: We should be able to return nonzero and halt the detection process.620620+ * But there is a bug in dmi_check_system() where a nonzero return from the621621+ * first match will result in a return of failure from dmi_check_system().622622+ * I fixed this; the patch is in 2.6-mm. Once in Linus's tree we can make623623+ * hdaps_dmi_match_invert() return hdaps_dmi_match(), which in turn returns 1.624624+ */625625+static int hdaps_dmi_match(struct dmi_system_id *id)626626+{627627+ printk(KERN_INFO "hdaps: %s detected.\n", id->ident);628628+ return 0;629629+}630630+631631+static int hdaps_dmi_match_invert(struct dmi_system_id *id)632632+{633633+ hdaps_invert = 1;634634+ printk(KERN_INFO "hdaps: inverting axis readings.\n");635635+ return 0;636636+}637637+638638+#define HDAPS_DMI_MATCH_NORMAL(model) { \639639+ .ident = "IBM " model, \640640+ .callback = hdaps_dmi_match, \641641+ .matches = { \642642+ DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), \643643+ DMI_MATCH(DMI_PRODUCT_VERSION, model) \644644+ } \645645+}646646+647647+#define HDAPS_DMI_MATCH_INVERT(model) { \648648+ .ident = "IBM " model, \649649+ .callback = hdaps_dmi_match_invert, \650650+ .matches = { \651651+ DMI_MATCH(DMI_BOARD_VENDOR, "IBM"), \652652+ DMI_MATCH(DMI_PRODUCT_VERSION, model) \653653+ } \654654+}655655+656656+static int __init hdaps_init(void)657657+{658658+ int ret;659659+660660+ /* Note that DMI_MATCH(...,"ThinkPad T42") will match "ThinkPad T42p" */661661+ struct dmi_system_id hdaps_whitelist[] = {662662+ HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"),663663+ HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"),664664+ HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"),665665+ HDAPS_DMI_MATCH_INVERT("ThinkPad T41p"),666666+ HDAPS_DMI_MATCH_NORMAL("ThinkPad T41"),667667+ HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"),668668+ HDAPS_DMI_MATCH_NORMAL("ThinkPad T42"),669669+ HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"),670670+ HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"),671671+ { .ident = NULL }672672+ };673673+674674+ if (!dmi_check_system(hdaps_whitelist)) {675675+ printk(KERN_WARNING "hdaps: supported laptop not found!\n");676676+ ret = -ENXIO;677677+ goto out;678678+ }679679+680680+ if (!request_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS, "hdaps")) {681681+ ret = -ENXIO;682682+ goto out;683683+ }684684+685685+ ret = driver_register(&hdaps_driver);686686+ if (ret)687687+ goto out_region;688688+689689+ pdev = platform_device_register_simple("hdaps", -1, NULL, 0);690690+ if (IS_ERR(pdev)) {691691+ ret = PTR_ERR(pdev);692692+ goto out_driver;693693+ }694694+695695+ ret = sysfs_create_group(&pdev->dev.kobj, &hdaps_attribute_group);696696+ if (ret)697697+ goto out_device;698698+699699+ if (hdaps_mousedev)700700+ hdaps_mousedev_enable();701701+702702+ printk(KERN_INFO "hdaps: driver successfully loaded.\n");703703+ return 0;704704+705705+out_device:706706+ platform_device_unregister(pdev);707707+out_driver:708708+ driver_unregister(&hdaps_driver);709709+out_region:710710+ release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);711711+out:712712+ printk(KERN_WARNING "hdaps: driver init failed (ret=%d)!\n", ret);713713+ return ret;714714+}715715+716716+static void __exit hdaps_exit(void)717717+{718718+ hdaps_mousedev_disable();719719+720720+ sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);721721+ platform_device_unregister(pdev);722722+ driver_unregister(&hdaps_driver);723723+ release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);724724+725725+ printk(KERN_INFO "hdaps: driver unloaded.\n");726726+}727727+728728+module_init(hdaps_init);729729+module_exit(hdaps_exit);730730+731731+module_param_named(mousedev, hdaps_mousedev, bool, 0);732732+MODULE_PARM_DESC(mousedev, "enable the input class device");733733+734734+module_param_named(invert, hdaps_invert, bool, 0);735735+MODULE_PARM_DESC(invert, "invert data along each axis");736736+737737+MODULE_AUTHOR("Robert Love");738738+MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");739739+MODULE_LICENSE("GPL v2");
···22 smsc47m1.c - Part of lm_sensors, Linux kernel modules33 for hardware monitoring4455- Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x and LPC47M14x66- Super-I/O chips.55+ Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x,66+ LPC47M15x and LPC47M192 Super-I/O chips.7788 Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>99 Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
-5
drivers/hwmon/via686a.c
···812812 return -ENODEV;813813 }814814815815- if (!address) {816816- dev_err(&dev->dev, "No Via 686A sensors found.\n");817817- return -ENODEV;818818- }819819-820815 s_bridge = pci_dev_get(dev);821816 if (i2c_isa_add_driver(&via686a_driver)) {822817 pci_dev_put(s_bridge);
+13-1
drivers/hwmon/w83627hf.c
···6464/* Insmod parameters */6565enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf };66666767+static int reset;6868+module_param(reset, bool, 0);6969+MODULE_PARM_DESC(reset, "Set to one to reset chip on load");7070+6771static int init = 1;6872module_param(init, bool, 0);6973MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");···12831279 int type = data->type;12841280 u8 tmp;1285128112861286- if(init) {12821282+ if (reset) {12831283+ /* Resetting the chip has been the default for a long time,12841284+ but repeatedly caused problems (fans going to full12851285+ speed...) so it is now optional. It might even go away if12861286+ nobody reports it as being useful, as I see very little12871287+ reason why this would be needed at all. */12881288+ dev_info(&client->dev, "If reset=1 solved a problem you were "12891289+ "having, please report!\n");12901290+12871291 /* save this register */12881292 i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG);12891293 /* Reset all except Watchdog values and last conversion values
-5
drivers/i2c/busses/i2c-nforce2.c
···9898#define NVIDIA_SMB_PRTCL_PEC 0x809999100100101101-/* Other settings */102102-#define MAX_TIMEOUT 256103103-104104-105105-106101static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,107102 unsigned short flags, char read_write,108103 u8 command, int size, union i2c_smbus_data *data);